bool mpeg1_2_video_packetizer_c::put_sequence_headers_into_codec_state(packet_cptr packet) { unsigned char *buf = packet->data->get_buffer(); size_t pos = 4; size_t size = packet->data->get_size(); unsigned int marker = get_uint32_be(buf); while ((pos < size) && (MPEGVIDEO_SEQUENCE_START_CODE != marker)) { marker <<= 8; marker |= buf[pos]; ++pos; } if ((MPEGVIDEO_SEQUENCE_START_CODE != marker) || ((pos + 4) >= size)) return false; size_t start = pos - 4; marker = get_uint32_be(&buf[pos]); pos += 4; while ((pos < size) && ((MPEGVIDEO_EXT_START_CODE == marker) || (0x00000100 != (marker & 0xffffff00)))) { marker <<= 8; marker |= buf[pos]; ++pos; } if (pos >= size) return false; pos -= 4; size_t sh_size = pos - start; if (NULL == m_hcodec_private) { set_codec_private(&buf[start], sh_size); rerender_track_headers(); } if (!m_seq_hdr.is_set() || (sh_size != m_seq_hdr->get_size()) || memcmp(&buf[start], m_seq_hdr->get_buffer(), sh_size)) { m_seq_hdr = clone_memory(&buf[start], sh_size); packet->codec_state = clone_memory(&buf[start], sh_size); } if (hack_engaged(ENGAGE_USE_CODEC_STATE_ONLY)) { memmove(&buf[start], &buf[pos], size - pos); packet->data->set_size(size - sh_size); } return true; }
void xtr_oggopus_c::header_packets_unlaced(std::vector<memory_cptr> &header_packets) { auto signature = std::string{"OpusTags"}; auto version = std::string{"unknown encoder; extracted from Matroska with "} + (!hack_engaged(ENGAGE_NO_VARIABLE_DATA) ? get_version_info("mkvextract") : std::string{"mkvextract"}); auto ver_len = version.length(); auto mem = memory_c::alloc(8 + 4 + ver_len + 4); auto buffer = reinterpret_cast<char *>(mem->get_buffer()); signature.copy(buffer, 8); put_uint32_le(buffer + 8, ver_len); version.copy(buffer + 8 + 4, ver_len); put_uint32_le(buffer + mem->get_size() - 4, 0); header_packets.push_back(mem); }
void avi_reader_c::create_video_packetizer() { size_t i; mxverb_tid(4, m_ti.m_fname, 0, "frame sizes:\n"); for (i = 0; i < m_max_video_frames; i++) { m_bytes_to_process += AVI_frame_size(m_avi, i); mxverb(4, boost::format(" %1%: %2%\n") % i % AVI_frame_size(m_avi, i)); } if (m_avi->bitmap_info_header) { m_ti.m_private_data = memory_c::clone(m_avi->bitmap_info_header, get_uint32_le(&m_avi->bitmap_info_header->bi_size)); mxverb(4, boost::format("track extra data size: %1%\n") % (m_ti.m_private_data->get_size() - sizeof(alBITMAPINFOHEADER))); if (sizeof(alBITMAPINFOHEADER) < m_ti.m_private_data->get_size()) mxverb(4, boost::format(" %1%\n") % to_hex(m_ti.m_private_data->get_buffer() + sizeof(alBITMAPINFOHEADER), m_ti.m_private_data->get_size() - sizeof(alBITMAPINFOHEADER))); } const char *codec = AVI_video_compressor(m_avi); if (mpeg4::p2::is_v3_fourcc(codec)) m_divx_type = DIVX_TYPE_V3; else if (mpeg4::p2::is_fourcc(codec)) m_divx_type = DIVX_TYPE_MPEG4; if (map_has_key(m_ti.m_default_durations, 0)) m_fps = 1000000000.0 / m_ti.m_default_durations[0]; else if (map_has_key(m_ti.m_default_durations, -1)) m_fps = 1000000000.0 / m_ti.m_default_durations[-1]; m_ti.m_id = 0; // ID for the video track. if (DIVX_TYPE_MPEG4 == m_divx_type) create_mpeg4_p2_packetizer(); else if (mpeg4::p10::is_avc_fourcc(codec) && !hack_engaged(ENGAGE_ALLOW_AVC_IN_VFW_MODE)) create_mpeg4_p10_packetizer(); else if (mpeg1_2::is_fourcc(get_uint32_le(codec))) create_mpeg1_2_packetizer(); else if (FOURCC('V', 'P', '8', '0') == get_uint32_be(codec)) create_vp8_packetizer(); else create_standard_video_packetizer(); }
uint32_t create_unique_uint32(unique_id_category_e category) { assert_valid_category(category); if (hack_engaged(ENGAGE_NO_VARIABLE_DATA)) { s_random_unique_numbers[category].push_back(s_random_unique_numbers[category].size() + 1); return s_random_unique_numbers[category].size(); } uint32_t random_number; do { random_number = random_c::generate_32bits(); } while ((random_number == 0) || !is_unique_uint32(random_number, category)); add_unique_uint32(random_number, category); return random_number; }
mpeg4_p2_video_packetizer_c:: mpeg4_p2_video_packetizer_c(generic_reader_c *p_reader, track_info_c &p_ti, double fps, int width, int height, bool input_is_native) : video_packetizer_c(p_reader, p_ti, MKV_V_MPEG4_ASP, fps, width, height) , m_timecodes_generated(0) , m_previous_timecode(0) , m_aspect_ratio_extracted(false) , m_input_is_native(input_is_native) , m_output_is_native(hack_engaged(ENGAGE_NATIVE_MPEG4) || input_is_native) , m_size_extracted(false) { if (!m_output_is_native) { set_codec_id(MKV_V_MSCOMP); check_fourcc(); m_timecode_factory_application_mode = TFA_SHORT_QUEUEING; } else { set_codec_id(MKV_V_MPEG4_ASP); if (!m_input_is_native) m_ti.m_private_data.reset(); // If no external timecode file has been specified then mkvmerge // might have created a factory due to the --default-duration // command line argument. This factory must be disabled for this // packetizer because it takes care of handling the default // duration/FPS itself. if (m_ti.m_ext_timecodes.empty()) m_timecode_factory.reset(); if (m_default_duration_forced) m_fps = 1000000000.0 / m_htrack_default_duration; else if (0.0 != m_fps) m_htrack_default_duration = static_cast<int64_t>(1000000000ll / m_fps); m_timecode_factory_application_mode = TFA_FULL_QUEUEING; } }
/* The page is the beginning of a new stream. Check the contents for known stream headers. If it is a known stream and the user has requested that it should be extracted then allocate a new packetizer based on the stream type and store the needed data in a new ogm_demuxer_c. */ void ogm_reader_c::handle_new_stream(ogg_page *og) { ogg_stream_state os; ogg_packet op; if (ogg_stream_init(&os, ogg_page_serialno(og))) { mxwarn_fn(m_ti.m_fname, boost::format(Y("ogg_stream_init for stream number %1% failed. Will try to continue and ignore this stream.\n")) % sdemuxers.size()); return; } // Read the first page and get its first packet. ogg_stream_pagein(&os, og); ogg_stream_packetout(&os, &op); ogm_demuxer_c *dmx = nullptr; /* * Check the contents for known stream headers. This one is the * standard Vorbis header. */ if ((7 <= op.bytes) && !strncmp((char *)&op.packet[1], "vorbis", 6)) dmx = new ogm_a_vorbis_demuxer_c(this); else if ((7 <= op.bytes) && !strncmp((char *)&op.packet[1], "theora", 6)) dmx = new ogm_v_theora_demuxer_c(this); else if ((8 <= op.bytes) && !memcmp(&op.packet[1], "kate\0\0\0", 7)) dmx = new ogm_s_kate_demuxer_c(this); // FLAC else if ( ((4 <= op.bytes) && !strncmp(reinterpret_cast<char *>(&op.packet[0]), "fLaC", 4)) || ((5 <= op.bytes) && !strncmp(reinterpret_cast<char *>(&op.packet[1]), "FLAC", 4) && (0x7f == op.packet[0]))) { #if !defined(HAVE_FLAC_FORMAT_H) if (demuxing_requested('a', sdemuxers.size())) mxerror_fn(m_ti.m_fname, Y("mkvmerge has not been compiled with FLAC support but handling of this stream has been requested.\n")); else { dmx = new ogm_demuxer_c(this); dmx->stype = OGM_STREAM_TYPE_A_FLAC; dmx->in_use = true; } #else dmx = new ogm_a_flac_demuxer_c(this, 0x7f == op.packet[0] ? ofm_post_1_1_1 : ofm_pre_1_1_1); #endif } else if ((static_cast<size_t>(op.bytes) >= sizeof(vp8_ogg_header_t)) && (0x4f == op.packet[0]) && (get_uint32_be(&op.packet[1]) == 0x56503830)) dmx = new ogm_v_vp8_demuxer_c(this, op); else if (((*op.packet & PACKET_TYPE_BITS ) == PACKET_TYPE_HEADER) && (op.bytes >= ((int)sizeof(stream_header) + 1))) { // The new stream headers introduced by OggDS (see ogmstreams.h). stream_header *sth = (stream_header *)(op.packet + 1); char buf[5]; buf[4] = 0; if (!strncmp(sth->streamtype, "video", 5)) { memcpy(buf, (char *)sth->subtype, 4); if (mpeg4::p10::is_avc_fourcc(buf) && !hack_engaged(ENGAGE_ALLOW_AVC_IN_VFW_MODE)) dmx = new ogm_v_avc_demuxer_c(this); else dmx = new ogm_v_mscomp_demuxer_c(this); } else if (!strncmp(sth->streamtype, "audio", 5)) { memcpy(buf, (char *)sth->subtype, 4); uint32_t codec_id = strtol(buf, (char **)nullptr, 16); if (0x0001 == codec_id) dmx = new ogm_a_pcm_demuxer_c(this); else if ((0x0050 == codec_id) || (0x0055 == codec_id)) dmx = new ogm_a_mp3_demuxer_c(this); else if (0x2000 == codec_id) dmx = new ogm_a_ac3_demuxer_c(this); else if (0x00ff == codec_id) dmx = new ogm_a_aac_demuxer_c(this); else mxwarn_fn(m_ti.m_fname, boost::format(Y("Unknown audio stream type 0x%|1$04x|. Stream ID %2% will be ignored.\n")) % codec_id % sdemuxers.size()); } else if (!strncmp(sth->streamtype, "text", 4)) dmx = new ogm_s_text_demuxer_c(this); } /* * The old OggDS headers (see MPlayer's source, libmpdemux/demux_ogg.c) * are not supported. */ if (!dmx) dmx = new ogm_demuxer_c(this); std::string type = dmx->get_type(); dmx->serialno = ogg_page_serialno(og); dmx->track_id = sdemuxers.size(); dmx->in_use = (type != "unknown") && demuxing_requested(type[0], dmx->track_id); dmx->packet_data.push_back(memory_cptr(new memory_c((unsigned char *)safememdup(op.packet, op.bytes), op.bytes, true))); memcpy(&dmx->os, &os, sizeof(ogg_stream_state)); sdemuxers.push_back(ogm_demuxer_cptr(dmx)); dmx->initialize(); }
void generic_packetizer_c::add_packet2(packet_cptr pack) { if (pack->has_discard_padding()) set_required_matroska_version(4); pack->timecode = ADJUST_TIMECODE(pack->timecode); if (pack->has_bref()) pack->bref = ADJUST_TIMECODE(pack->bref); if (pack->has_fref()) pack->fref = ADJUST_TIMECODE(pack->fref); if (pack->has_duration()) { pack->duration = static_cast<int64_t>(pack->duration * m_ti.m_tcsync.numerator / m_ti.m_tcsync.denominator); if (pack->has_discard_padding()) pack->duration -= std::min(pack->duration, pack->discard_padding.to_ns()); } if ((2 > m_htrack_min_cache) && pack->has_fref()) { set_track_min_cache(2); rerender_track_headers(); } else if ((1 > m_htrack_min_cache) && pack->has_bref()) { set_track_min_cache(1); rerender_track_headers(); } if (0 > pack->timecode) return; // 'timecode < safety_last_timecode' may only occur for B frames. In this // case we have the coding order, e.g. IPB1B2 and the timecodes // I: 0, P: 120, B1: 40, B2: 80. if (!m_relaxed_timecode_checking && (pack->timecode < m_safety_last_timecode) && (0 > pack->fref) && hack_engaged(ENGAGE_ENABLE_TIMECODE_WARNING)) { if (track_audio == m_htrack_type) { int64_t needed_timecode_offset = m_safety_last_timecode + m_safety_last_duration - pack->timecode; m_correction_timecode_offset += needed_timecode_offset; pack->timecode += needed_timecode_offset; if (pack->has_bref()) pack->bref += needed_timecode_offset; if (pack->has_fref()) pack->fref += needed_timecode_offset; mxwarn_tid(m_ti.m_fname, m_ti.m_id, boost::format(Y("The current packet's timecode is smaller than that of the previous packet. " "This usually means that the source file is a Matroska file that has not been created 100%% correctly. " "The timecodes of all packets will be adjusted by %1%ms in order not to lose any data. " "This may throw audio/video synchronization off, but that can be corrected with mkvmerge's \"--sync\" option. " "If you already use \"--sync\" and you still get this warning then do NOT worry -- this is normal. " "If this error happens more than once and you get this message more than once for a particular track " "then either is the source file badly mastered, or mkvmerge contains a bug. " "In this case you should contact the author Moritz Bunkus <*****@*****.**>.\n")) % ((needed_timecode_offset + 500000) / 1000000)); } else mxwarn_tid(m_ti.m_fname, m_ti.m_id, boost::format("generic_packetizer_c::add_packet2: timecode < last_timecode (%1% < %2%). %3%\n") % format_timestamp(pack->timecode) % format_timestamp(m_safety_last_timecode) % BUGMSG); } m_safety_last_timecode = pack->timecode; m_safety_last_duration = pack->duration; pack->timecode_before_factory = pack->timecode; m_packet_queue.push_back(pack); if (!m_timestamp_factory || (TFA_IMMEDIATE == m_timestamp_factory_application_mode)) apply_factory_once(pack); else apply_factory(); }
int cluster_helper_c::render() { std::vector<render_groups_cptr> render_groups; KaxCues cues; cues.SetGlobalTimecodeScale(g_timecode_scale); bool use_simpleblock = !hack_engaged(ENGAGE_NO_SIMPLE_BLOCKS); LacingType lacing_type = hack_engaged(ENGAGE_LACING_XIPH) ? LACING_XIPH : hack_engaged(ENGAGE_LACING_EBML) ? LACING_EBML : LACING_AUTO; int64_t min_cl_timecode = std::numeric_limits<int64_t>::max(); int64_t max_cl_timecode = 0; int elements_in_cluster = 0; bool added_to_cues = false; // Splitpoint stuff if ((-1 == m->header_overhead) && splitting()) m->header_overhead = m->out->getFilePointer() + g_tags_size; // Make sure that we don't have negative/wrapped around timecodes in the output file. // Can happend when we're splitting; so adjust timecode_offset accordingly. m->timecode_offset = boost::accumulate(m->packets, m->timecode_offset, [](int64_t a, const packet_cptr &p) { return std::min(a, p->assigned_timecode); }); int64_t timecode_offset = m->timecode_offset + get_discarded_duration(); for (auto &pack : m->packets) { generic_packetizer_c *source = pack->source; bool has_codec_state = !!pack->codec_state; if (g_video_packetizer == source) m->max_video_timecode_rendered = std::max(pack->assigned_timecode + pack->get_duration(), m->max_video_timecode_rendered); if (discarding()) { if (-1 == m->first_discarded_timecode) m->first_discarded_timecode = pack->assigned_timecode; m->last_discarded_timecode_and_duration = std::max(m->last_discarded_timecode_and_duration, pack->assigned_timecode + pack->get_duration()); continue; } if (source->contains_gap()) m->cluster->SetSilentTrackUsed(); render_groups_c *render_group = nullptr; for (auto &rg : render_groups) if (rg->m_source == source) { render_group = rg.get(); break; } if (!render_group) { render_groups.push_back(render_groups_cptr(new render_groups_c(source))); render_group = render_groups.back().get(); } min_cl_timecode = std::min(pack->assigned_timecode, min_cl_timecode); max_cl_timecode = std::max(pack->assigned_timecode, max_cl_timecode); DataBuffer *data_buffer = new DataBuffer((binary *)pack->data->get_buffer(), pack->data->get_size()); KaxTrackEntry &track_entry = static_cast<KaxTrackEntry &>(*source->get_track_entry()); kax_block_blob_c *previous_block_group = !render_group->m_groups.empty() ? render_group->m_groups.back().get() : nullptr; kax_block_blob_c *new_block_group = previous_block_group; if (!pack->is_key_frame() || has_codec_state || pack->has_discard_padding()) render_group->m_more_data = false; if (!render_group->m_more_data) { set_duration(render_group); render_group->m_durations.clear(); render_group->m_duration_mandatory = false; BlockBlobType this_block_blob_type = !use_simpleblock ? BLOCK_BLOB_NO_SIMPLE : must_duration_be_set(render_group, pack) ? BLOCK_BLOB_NO_SIMPLE : !pack->data_adds.empty() ? BLOCK_BLOB_NO_SIMPLE : has_codec_state ? BLOCK_BLOB_NO_SIMPLE : pack->has_discard_padding() ? BLOCK_BLOB_NO_SIMPLE : BLOCK_BLOB_ALWAYS_SIMPLE; render_group->m_groups.push_back(kax_block_blob_cptr(new kax_block_blob_c(this_block_blob_type))); new_block_group = render_group->m_groups.back().get(); m->cluster->AddBlockBlob(new_block_group); new_block_group->SetParent(*m->cluster); added_to_cues = false; } // Now put the packet into the cluster. render_group->m_more_data = new_block_group->add_frame_auto(track_entry, pack->assigned_timecode - timecode_offset, *data_buffer, lacing_type, pack->has_bref() ? pack->bref - timecode_offset : -1, pack->has_fref() ? pack->fref - timecode_offset : -1); if (has_codec_state) { KaxBlockGroup &bgroup = (KaxBlockGroup &)*new_block_group; KaxCodecState *cstate = new KaxCodecState; bgroup.PushElement(*cstate); cstate->CopyBuffer(pack->codec_state->get_buffer(), pack->codec_state->get_size()); } if (-1 == m->first_timecode_in_file) m->first_timecode_in_file = pack->assigned_timecode; if (-1 == m->first_timecode_in_part) m->first_timecode_in_part = pack->assigned_timecode; m->min_timecode_in_file = std::min(timecode_c::ns(pack->assigned_timecode), m->min_timecode_in_file.value_or_max()); m->max_timecode_in_file = std::max(pack->assigned_timecode, m->max_timecode_in_file); m->max_timecode_and_duration = std::max(pack->assigned_timecode + pack->get_duration(), m->max_timecode_and_duration); if (!pack->is_key_frame() || !track_entry.LacingEnabled()) render_group->m_more_data = false; render_group->m_durations.push_back(pack->get_unmodified_duration()); render_group->m_duration_mandatory |= pack->duration_mandatory; cues_c::get().set_duration_for_id_timecode(source->get_track_num(), pack->assigned_timecode - timecode_offset, pack->get_duration()); if (new_block_group) { // Set the reference priority if it was wanted. if ((0 < pack->ref_priority) && new_block_group->replace_simple_by_group()) GetChild<KaxReferencePriority>(*new_block_group).SetValue(pack->ref_priority); // Handle BlockAdditions if needed if (!pack->data_adds.empty() && new_block_group->ReplaceSimpleByGroup()) { KaxBlockAdditions &additions = AddEmptyChild<KaxBlockAdditions>(*new_block_group); size_t data_add_idx; for (data_add_idx = 0; pack->data_adds.size() > data_add_idx; ++data_add_idx) { auto &block_more = AddEmptyChild<KaxBlockMore>(additions); GetChild<KaxBlockAddID >(block_more).SetValue(data_add_idx + 1); GetChild<KaxBlockAdditional>(block_more).CopyBuffer((binary *)pack->data_adds[data_add_idx]->get_buffer(), pack->data_adds[data_add_idx]->get_size()); } } if (pack->has_discard_padding()) GetChild<KaxDiscardPadding>(*new_block_group).SetValue(pack->discard_padding.to_ns()); } elements_in_cluster++; if (!new_block_group) new_block_group = previous_block_group; else if (g_write_cues && (!added_to_cues || has_codec_state)) { added_to_cues = add_to_cues_maybe(pack); if (added_to_cues) cues.AddBlockBlob(*new_block_group); } pack->group = new_block_group; m->track_statistics[ source->get_uid() ].process(*pack); } if (!discarding()) { if (0 < elements_in_cluster) { for (auto &rg : render_groups) set_duration(rg.get()); m->cluster->SetPreviousTimecode(min_cl_timecode - timecode_offset - 1, (int64_t)g_timecode_scale); m->cluster->set_min_timecode(min_cl_timecode - timecode_offset); m->cluster->set_max_timecode(max_cl_timecode - timecode_offset); m->cluster->Render(*m->out, cues); m->bytes_in_file += m->cluster->ElementSize(); if (g_kax_sh_cues) g_kax_sh_cues->IndexThis(*m->cluster, *g_kax_segment); m->previous_cluster_tc = m->cluster->GlobalTimecode(); cues_c::get().postprocess_cues(cues, *m->cluster); } else m->previous_cluster_tc = -1; } m->min_timecode_in_cluster = -1; m->max_timecode_in_cluster = -1; m->cluster->delete_non_blocks(); return 1; }
void mpeg1_2_video_packetizer_c::remove_stuffing_bytes_and_handle_sequence_headers(packet_cptr packet) { mxdebug_if(m_debug_stuffing_removal, boost::format("Starting stuff removal, frame size %1%\n") % packet->data->get_size()); auto buf = packet->data->get_buffer(); auto size = packet->data->get_size(); size_t pos = 4; size_t start_code_pos = 0; size_t stuffing_start = 0; auto marker = get_uint32_be(buf); uint32_t chunk_type = 0; bool seq_hdr_found = false; auto mid_remover = [this, &stuffing_start, &pos, &size, &buf]() { if (!stuffing_start || (stuffing_start >= (pos - 4))) return; auto num_stuffing_bytes = pos - 4 - stuffing_start; m_num_removed_stuffing_bytes += num_stuffing_bytes; ::memmove(&buf[stuffing_start], &buf[pos - 4], size - pos + 4); pos -= num_stuffing_bytes; size -= num_stuffing_bytes; mxdebug_if(m_debug_stuffing_removal, boost::format(" Stuffing in the middle: %1%\n") % num_stuffing_bytes); }; memory_cptr new_seq_hdr; auto seq_hdr_copier = [this, &chunk_type, &seq_hdr_found, &buf, &start_code_pos, &pos, &new_seq_hdr, &size](bool at_end) { if ((MPEGVIDEO_SEQUENCE_HEADER_START_CODE != chunk_type) && (MPEGVIDEO_EXT_START_CODE != chunk_type)) return; if (MPEGVIDEO_SEQUENCE_HEADER_START_CODE == chunk_type) seq_hdr_found = true; else if (!seq_hdr_found) return; auto bytes_to_copy = at_end ? pos - start_code_pos : pos - 4 - start_code_pos; if (!new_seq_hdr) new_seq_hdr = memory_c::clone(&buf[start_code_pos], bytes_to_copy); else new_seq_hdr->add(&buf[start_code_pos], bytes_to_copy); if (!hack_engaged(ENGAGE_USE_CODEC_STATE_ONLY)) return; memmove(&buf[start_code_pos], &buf[pos - 4], size - pos + 4); pos -= bytes_to_copy; size -= bytes_to_copy; }; while (pos < size) { if ((MPEGVIDEO_SLICE_START_CODE_LOWER <= marker) && (MPEGVIDEO_SLICE_START_CODE_UPPER >= marker)) { mxdebug_if(m_debug_stuffing_removal, boost::format(" Slice start code at %1%\n") % (pos - 4)); mid_remover(); seq_hdr_copier(false); chunk_type = MPEGVIDEO_SLICE_START_CODE_LOWER; stuffing_start = 0; start_code_pos = pos - 4; } else if ((marker & 0xffffff00) == 0x00000100) { mxdebug_if(m_debug_stuffing_removal, boost::format(" Non-slice start code at %1%\n") % (pos - 4)); mid_remover(); seq_hdr_copier(false); chunk_type = marker; stuffing_start = 0; start_code_pos = pos - 4; } else if ((MPEGVIDEO_SLICE_START_CODE_LOWER == chunk_type) && !stuffing_start && (marker == 0x00000000)) { mxdebug_if(m_debug_stuffing_removal, boost::format(" Start at %1%\n") % (pos - 3)); stuffing_start = pos - 3; } marker <<= 8; marker |= buf[pos]; ++pos; } if ((marker & 0xffffff00) == 0x00000100) { seq_hdr_copier(false); mid_remover(); } else if (stuffing_start && (stuffing_start < size)) { mxdebug_if(m_debug_stuffing_removal, boost::format(" Stuffing at the end: chunk_type 0x%|1$08x| stuffing_start %2% stuffing_size %3%\n") % chunk_type % stuffing_start % (stuffing_start ? size - stuffing_start : 0)); m_num_removed_stuffing_bytes += size - stuffing_start; size = stuffing_start; } packet->data->set_size(size); if (!new_seq_hdr) return; if (!m_hcodec_private) { set_codec_private(new_seq_hdr); rerender_track_headers(); } if (!m_seq_hdr || (*new_seq_hdr != *m_seq_hdr)) { m_seq_hdr = new_seq_hdr; packet->codec_state = new_seq_hdr->clone(); } }