void vc1::es_parser_c::handle_entrypoint_packet(memory_cptr packet) { add_pre_frame_extra_data(packet); if (!m_raw_entrypoint.is_set()) m_raw_entrypoint = memory_cptr(packet->clone()); }
void theora_video_packetizer_c::extract_aspect_ratio() { if (display_dimensions_or_aspect_ratio_set() || (NULL == m_ti.m_private_data) || (0 == m_ti.m_private_size)) return; memory_cptr private_data = memory_cptr(new memory_c(m_ti.m_private_data, m_ti.m_private_size, false)); std::vector<memory_cptr> packets = unlace_memory_xiph(private_data); for (auto &packet : packets) { if ((0 == packet->get_size()) || (THEORA_HEADERTYPE_IDENTIFICATION != packet->get_buffer()[0])) continue; try { theora_identification_header_t theora; theora_parse_identification_header(packet->get_buffer(), packet->get_size(), theora); if ((0 == theora.display_width) || (0 == theora.display_height)) return; set_video_display_dimensions(theora.display_width, theora.display_height, PARAMETER_SOURCE_BITSTREAM); mxinfo_tid(m_ti.m_fname, m_ti.m_id, boost::format(Y("Extracted the aspect ratio information from the Theora video headers and set the display dimensions to %1%/%2%.\n")) % theora.display_width % theora.display_height); } catch (...) { } return; } }
void vc1::es_parser_c::handle_entrypoint_packet(memory_cptr packet) { if (!postpone_processing(packet)) add_pre_frame_extra_data(packet); if (!m_raw_entrypoint) m_raw_entrypoint = memory_cptr(packet->clone()); }
void vc1::frame_t::init() { header.init(); data = memory_cptr(NULL); timecode = -1; duration = 0; contains_sequence_header = false; contains_field = false; }
void mpeg4_p10_video_packetizer_c::change_nalu_size_len(packet_cptr packet) { unsigned char *src = packet->data->get_buffer(); int size = packet->data->get_size(); if (!src || !size) return; std::vector<int> nalu_sizes; int src_pos = 0; // Find all NALU sizes in this packet. while (src_pos < size) { if ((size - src_pos) < m_nalu_size_len_src) break; int nalu_size = get_uint_be(&src[src_pos], m_nalu_size_len_src); nalu_size = std::min<int>(nalu_size, size - src_pos - m_nalu_size_len_src); if (nalu_size > m_max_nalu_size) mxerror_tid(m_ti.m_fname, m_ti.m_id, boost::format(Y("The chosen NALU size length of %1% is too small. Try using '4'.\n")) % m_nalu_size_len_dst); src_pos += m_nalu_size_len_src + nalu_size; nalu_sizes.push_back(nalu_size); } // Allocate memory if the new NALU size length is greater // than the previous one. Otherwise reuse the existing memory. if (m_nalu_size_len_dst > m_nalu_size_len_src) { int new_size = size + nalu_sizes.size() * (m_nalu_size_len_dst - m_nalu_size_len_src); packet->data = memory_cptr(new memory_c((unsigned char *)safemalloc(new_size), new_size, true)); } // Copy the NALUs and write the new sized length field. unsigned char *dst = packet->data->get_buffer(); src_pos = 0; int dst_pos = 0; size_t i; for (i = 0; nalu_sizes.size() > i; ++i) { int nalu_size = nalu_sizes[i]; put_uint_be(&dst[dst_pos], nalu_size, m_nalu_size_len_dst); memmove(&dst[dst_pos + m_nalu_size_len_dst], &src[src_pos + m_nalu_size_len_src], nalu_size); src_pos += m_nalu_size_len_src + nalu_size; dst_pos += m_nalu_size_len_dst + nalu_size; } packet->data->set_size(dst_pos); }
void vc1::es_parser_c::flush() { if (m_unparsed_buffer.is_set() && (4 <= m_unparsed_buffer->get_size())) { uint32_t marker = get_uint32_be(m_unparsed_buffer->get_buffer()); if (vc1::is_marker(marker)) handle_packet(clone_memory(m_unparsed_buffer->get_buffer(), m_unparsed_buffer->get_size())); } m_unparsed_buffer = memory_cptr(NULL); flush_frame(); }
void vc1::es_parser_c::add_bytes(unsigned char *buffer, int size) { memory_slice_cursor_c cursor; int previous_pos = -1; int64_t previous_stream_pos = m_stream_pos; if (m_unparsed_buffer.is_set() && (0 != m_unparsed_buffer->get_size())) cursor.add_slice(m_unparsed_buffer); cursor.add_slice(buffer, size); if (3 <= cursor.get_remaining_size()) { uint32_t marker = (1 << 24) | ((unsigned int)cursor.get_char() << 16) | ((unsigned int)cursor.get_char() << 8) | (unsigned int)cursor.get_char(); while (1) { if (vc1::is_marker(marker)) { if (-1 != previous_pos) { int new_size = cursor.get_position() - 4 - previous_pos; memory_cptr packet(new memory_c(safemalloc(new_size), new_size, true)); cursor.copy(packet->get_buffer(), previous_pos, new_size); handle_packet(packet); } previous_pos = cursor.get_position() - 4; m_stream_pos = previous_stream_pos + previous_pos; } if (!cursor.char_available()) break; marker <<= 8; marker |= (unsigned int)cursor.get_char(); } } if (-1 == previous_pos) previous_pos = 0; int new_size = cursor.get_size() - previous_pos; if (0 != new_size) { memory_cptr new_unparsed_buffer = memory_c::alloc(new_size); cursor.copy(new_unparsed_buffer->get_buffer(), previous_pos, new_size); m_unparsed_buffer = new_unparsed_buffer; } else m_unparsed_buffer = memory_cptr(NULL); }
std::vector<memory_cptr> unlace_memory_xiph(memory_cptr &buffer) { if (1 > buffer->get_size()) throw mtx::mem::lacing_x("Buffer too small"); std::vector<int> sizes; unsigned char *ptr = buffer->get_buffer(); unsigned char *end = buffer->get_buffer() + buffer->get_size(); size_t last_size = buffer->get_size(); size_t num_blocks = ptr[0] + 1; size_t i; ++ptr; for (i = 0; (num_blocks - 1) > i; ++i) { int size = 0; while ((ptr < end) && (*ptr == 255)) { size += 255; ++ptr; } if (ptr >= end) throw mtx::mem::lacing_x("End-of-buffer while reading the block sizes"); size += *ptr; ++ptr; sizes.push_back(size); last_size -= size; } sizes.push_back(last_size - (ptr - buffer->get_buffer())); std::vector<memory_cptr> blocks; for (i = 0; sizes.size() > i; ++i) { if ((ptr + sizes[i]) > end) throw mtx::mem::lacing_x("End-of-buffer while assigning the blocks"); blocks.push_back(memory_cptr(new memory_c(ptr, sizes[i], false))); ptr += sizes[i]; } return blocks; }
void vc1::es_parser_c::handle_sequence_header_packet(memory_cptr packet) { flush_frame(); add_pre_frame_extra_data(packet); vc1::sequence_header_t seqhdr; if (!vc1::parse_sequence_header(packet->get_buffer(), packet->get_size(), seqhdr)) return; m_seqhdr_changed = !m_seqhdr_found || (packet->get_size() != m_raw_seqhdr->get_size()) || memcmp(packet->get_buffer(), m_raw_seqhdr->get_buffer(), packet->get_size()); memcpy(&m_seqhdr, &seqhdr, sizeof(vc1::sequence_header_t)); m_raw_seqhdr = memory_cptr(packet->clone()); m_seqhdr_found = true; if (!m_default_duration_forced && m_seqhdr.framerate_flag && (0 != m_seqhdr.framerate_num) && (0 != m_seqhdr.framerate_den)) m_default_duration = 1000000000ll * m_seqhdr.framerate_num / m_seqhdr.framerate_den; }
/* 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 vc1::es_parser_c::add_post_frame_extra_data(memory_cptr packet) { m_post_frame_extra_data.push_back(memory_cptr(packet->clone())); }