// Parse a 'FRGM' chunk and any image bearing chunks that immediately follow. // 'fragment_chunk_size' is the previously validated, padded chunk size. static ParseStatus ParseFragment(WebPDemuxer* const dmux, uint32_t fragment_chunk_size) { const int frame_num = 1; // All fragments belong to the 1st (and only) frame. const int is_fragmented = !!(dmux->feature_flags_ & FRAGMENTS_FLAG); const uint32_t frgm_payload_size = fragment_chunk_size - FRGM_CHUNK_SIZE; int added_fragment = 0; MemBuffer* const mem = &dmux->mem_; Frame* frame; ParseStatus status = NewFrame(mem, FRGM_CHUNK_SIZE, fragment_chunk_size, &frame); if (status != PARSE_OK) return status; frame->is_fragment_ = 1; frame->x_offset_ = 2 * ReadLE24s(mem); frame->y_offset_ = 2 * ReadLE24s(mem); // Store a fragment only if the 'fragments' flag is set and there is some // data available. status = StoreFrame(frame_num, frgm_payload_size, mem, frame); if (status != PARSE_ERROR && is_fragmented && frame->frame_num_ > 0) { added_fragment = AddFrame(dmux, frame); if (!added_fragment) { status = PARSE_ERROR; } else { dmux->num_frames_ = 1; } } if (!added_fragment) free(frame); return status; }
// Parse a 'TILE' chunk and any image bearing chunks that immediately follow. // 'tile_chunk_size' is the previously validated, padded chunk size. static ParseStatus ParseTile(WebPDemuxer* const dmux, uint32_t tile_chunk_size) { const int has_tiles = !!(dmux->feature_flags_ & TILE_FLAG); const uint32_t min_size = tile_chunk_size + CHUNK_HEADER_SIZE; int added_tile = 0; MemBuffer* const mem = &dmux->mem_; Frame* frame; ParseStatus status = NewFrame(mem, min_size, TILE_CHUNK_SIZE, tile_chunk_size, &frame); if (status != PARSE_OK) return status; frame->is_tile_ = 1; frame->x_offset_ = 2 * GetLE24s(mem); frame->y_offset_ = 2 * GetLE24s(mem); Skip(mem, tile_chunk_size - TILE_CHUNK_SIZE); // skip any trailing data. // Store a (potentially partial) tile only if the tile flag is set // and the tile contains some data. status = StoreFrame(dmux->num_frames_, mem, frame); if (status != PARSE_ERROR && has_tiles && frame->frame_num_ > 0) { // Note num_frames_ is incremented only when all tiles have been consumed. added_tile = AddFrame(dmux, frame); if (!added_tile) status = PARSE_ERROR; } if (!added_tile) free(frame); return status; }
bool AVIDump::Start(HWND hWnd, int w, int h) { s_emu_wnd = hWnd; s_file_count = 0; s_width = w; s_height = h; s_last_frame = CoreTiming::GetTicks(); if (SConfig::GetInstance().m_SYSCONF->GetData<u8>("IPL.E60")) s_frame_rate = 60; // always 60, for either pal60 or ntsc else s_frame_rate = VideoInterface::TargetRefreshRate; // 50 or 60, depending on region // clear CFR frame cache on start, not on file create (which is also segment switch) SetBitmapFormat(); StoreFrame(nullptr); //Dragonbane: Setup file reading if last side bool lastSide = false; if (Movie::cmp_isRunning) { if (Movie::cmp_leftFinished || Movie::cmp_rightFinished) lastSide = true; if (lastSide) { tempFileCount = 0; s_stopTempFile = false; std::string movie_file_name = GetCurrDumpFile(tempFileCount, true); if (File::Exists(movie_file_name) && Movie::cmp_startTimerFrame > Movie::cmp_curentBranchFrame) //Dragonbane: Open temp file for reading { HRESULT h2 = AVIFileOpenA(&s_file_temp, movie_file_name.c_str(), OF_READ, nullptr); HRESULT h3 = AVIFileGetStream(s_file_temp, &s_stream_temp, streamtypeVIDEO, 0); s_last_key_temp = 1; //Skip first key frame as its always black s_getFrame_temp = AVIStreamGetFrameOpen(s_stream_temp, &s_bitmap); if (!s_getFrame_temp) { PanicAlertT("Your chosen compression codec can not be decompressed again! Can't create video comparison!"); Movie::CancelComparison(); } } } } return CreateFile(); }
static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) { const size_t min_size = CHUNK_HEADER_SIZE; MemBuffer* const mem = &dmux->mem_; Frame* frame; ParseStatus status; int image_added = 0; if (dmux->frames_ != NULL) return PARSE_ERROR; if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR; if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA; frame = (Frame*)calloc(1, sizeof(*frame)); if (frame == NULL) return PARSE_ERROR; // For the single image case we allow parsing of a partial frame, but we need // at least CHUNK_HEADER_SIZE for parsing. status = StoreFrame(1, CHUNK_HEADER_SIZE, &dmux->mem_, frame); if (status != PARSE_ERROR) { const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG); // Clear any alpha when the alpha flag is missing. if (!has_alpha && frame->img_components_[1].size_ > 0) { frame->img_components_[1].offset_ = 0; frame->img_components_[1].size_ = 0; frame->has_alpha_ = 0; } // Use the frame width/height as the canvas values for non-vp8x files. // Also, set ALPHA_FLAG if this is a lossless image with alpha. if (!dmux->is_ext_format_ && frame->width_ > 0 && frame->height_ > 0) { dmux->state_ = WEBP_DEMUX_PARSED_HEADER; dmux->canvas_width_ = frame->width_; dmux->canvas_height_ = frame->height_; dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0; } if (!AddFrame(dmux, frame)) { status = PARSE_ERROR; // last frame was left incomplete } else { image_added = 1; dmux->num_frames_ = 1; } } if (!image_added) free(frame); return status; }
Json::Value FileSaver::StoreLayer(Layer* layer, const std::string& dir, bool single) { Json::Value value; value["name"] = layer->GetName(); const std::map<int, KeyFrame*>& frames = layer->GetAllFrames(); std::vector<KeyFrame*> all_frames; all_frames.reserve(frames.size()); std::map<int, KeyFrame*>::const_iterator itr = frames.begin(); for (size_t i = 0; itr != frames.end(); ++itr, ++i) { value["frame"][i] = StoreFrame(itr->second, dir, single); all_frames.push_back(itr->second); } return value; }
// Parse a 'ANMF' chunk and any image bearing chunks that immediately follow. // 'frame_chunk_size' is the previously validated, padded chunk size. static ParseStatus ParseAnimationFrame( WebPDemuxer* const dmux, uint32_t frame_chunk_size) { const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG); const uint32_t anmf_payload_size = frame_chunk_size - ANMF_CHUNK_SIZE; int added_frame = 0; int bits; MemBuffer* const mem = &dmux->mem_; Frame* frame; ParseStatus status = NewFrame(mem, ANMF_CHUNK_SIZE, frame_chunk_size, &frame); if (status != PARSE_OK) return status; frame->x_offset_ = 2 * ReadLE24s(mem); frame->y_offset_ = 2 * ReadLE24s(mem); frame->width_ = 1 + ReadLE24s(mem); frame->height_ = 1 + ReadLE24s(mem); frame->duration_ = ReadLE24s(mem); bits = ReadByte(mem); frame->dispose_method_ = (bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE; frame->blend_method_ = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND; if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) { free(frame); return PARSE_ERROR; } // Store a frame only if the animation flag is set there is some data for // this frame is available. status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame); if (status != PARSE_ERROR && is_animation && frame->frame_num_ > 0) { added_frame = AddFrame(dmux, frame); if (added_frame) { ++dmux->num_frames_; } else { status = PARSE_ERROR; } } if (!added_frame) free(frame); return status; }
static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) { const size_t min_size = CHUNK_HEADER_SIZE; MemBuffer* const mem = &dmux->mem_; Frame* frame; ParseStatus status; if (dmux->frames_ != NULL) return PARSE_ERROR; if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR; if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA; frame = (Frame*)calloc(1, sizeof(*frame)); if (frame == NULL) return PARSE_ERROR; status = StoreFrame(1, &dmux->mem_, frame); if (status != PARSE_ERROR) { const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG); // Clear any alpha when the alpha flag is missing. if (!has_alpha && frame->img_components_[1].size_ > 0) { frame->img_components_[1].offset_ = 0; frame->img_components_[1].size_ = 0; } // Use the frame width/height as the canvas values for non-vp8x files. if (!dmux->is_ext_format_ && frame->width_ > 0 && frame->height_ > 0) { dmux->state_ = WEBP_DEMUX_PARSED_HEADER; dmux->canvas_width_ = frame->width_; dmux->canvas_height_ = frame->height_; } AddFrame(dmux, frame); dmux->num_frames_ = 1; } else { free(frame); } return status; }
// Parse a 'FRM ' chunk and any image bearing chunks that immediately follow. // 'frame_chunk_size' is the previously validated, padded chunk size. static ParseStatus ParseFrame( WebPDemuxer* const dmux, uint32_t frame_chunk_size) { const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG); const uint32_t min_size = frame_chunk_size + CHUNK_HEADER_SIZE; int added_frame = 0; MemBuffer* const mem = &dmux->mem_; Frame* frame; ParseStatus status = NewFrame(mem, min_size, FRAME_CHUNK_SIZE, frame_chunk_size, &frame); if (status != PARSE_OK) return status; frame->x_offset_ = 2 * GetLE24s(mem); frame->y_offset_ = 2 * GetLE24s(mem); frame->width_ = 1 + GetLE24s(mem); frame->height_ = 1 + GetLE24s(mem); frame->duration_ = 1 + GetLE24s(mem); Skip(mem, frame_chunk_size - FRAME_CHUNK_SIZE); // skip any trailing data. if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) { return PARSE_ERROR; } // Store a (potentially partial) frame only if the animation flag is set // and there is some data in 'frame'. status = StoreFrame(dmux->num_frames_ + 1, mem, frame); if (status != PARSE_ERROR && has_frames && frame->frame_num_ > 0) { added_frame = AddFrame(dmux, frame); if (added_frame) { ++dmux->num_frames_; } else { status = PARSE_ERROR; } } if (!added_frame) free(frame); return status; }
void AVIDump::AddFrame(const u8* data, int w, int h) { static bool shown_error = false; if ((w != s_bitmap.biWidth || h != s_bitmap.biHeight) && !shown_error) { PanicAlertT("You have resized the window while dumping frames.\n" "Nothing can be done to handle this properly.\n" "Your video will likely be broken."); shown_error = true; s_bitmap.biWidth = w; s_bitmap.biHeight = h; } // no timecodes, instead dump each frame as many/few times as needed to keep sync u64 one_cfr = SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate; int nplay = 0; s64 delta; if (!s_start_dumping && s_last_frame <= SystemTimers::GetTicksPerSecond()) { delta = CoreTiming::GetTicks(); s_start_dumping = true; } else { delta = CoreTiming::GetTicks() - s_last_frame; } bool b_frame_dumped = false; // try really hard to place one copy of frame in stream (otherwise it's dropped) if (delta > (s64)one_cfr * 1 / 10) // place if 1/10th of a frame space { delta -= one_cfr; nplay++; } // try not nearly so hard to place additional copies of the frame while (delta > (s64)one_cfr * 9 / 10) // place if 9/10th of a frame space { delta -= one_cfr; nplay++; } while (nplay--) { if (!b_frame_dumped) { AVIStreamWrite(s_stream_compressed, s_frame_count++, 1, GetFrame(), s_bitmap.biSizeImage, AVIIF_KEYFRAME, nullptr, &s_byte_buffer); b_frame_dumped = true; } else { AVIStreamWrite(s_stream, s_frame_count++, 1, nullptr, 0, 0, nullptr, nullptr); } s_total_bytes += s_byte_buffer; // Close the recording if the file is larger than 2gb // VfW can't properly save files over 2gb in size, but can keep writing to them up to 4gb. if (s_total_bytes >= 2000000000) { CloseFile(); s_file_count++; CreateFile(); } } StoreFrame(data); s_last_frame = CoreTiming::GetTicks(); }