void vc1::es_parser_c::combine_extra_data_with_packet() { auto sum_fn = [](size_t size, const memory_cptr &buffer) { return size + buffer->get_size(); }; auto extra_size = boost::accumulate(m_pre_frame_extra_data, 0, sum_fn) + boost::accumulate(m_post_frame_extra_data, 0, sum_fn); auto new_packet = memory_c::alloc(extra_size + m_current_frame->data->get_size()); auto ptr = new_packet->get_buffer(); for (const auto &mem : m_pre_frame_extra_data) { memcpy(ptr, mem->get_buffer(), mem->get_size()); ptr += mem->get_size(); if (VC1_MARKER_SEQHDR == get_uint32_be(mem->get_buffer())) m_current_frame->contains_sequence_header = true; } memcpy(ptr, m_current_frame->data->get_buffer(), m_current_frame->data->get_size()); ptr += m_current_frame->data->get_size(); for (const auto &mem : m_post_frame_extra_data) { memcpy(ptr, mem->get_buffer(), mem->get_size()); ptr += mem->get_size(); if (VC1_MARKER_FIELD == get_uint32_be(mem->get_buffer())) m_current_frame->contains_field = true; } m_pre_frame_extra_data.clear(); m_post_frame_extra_data.clear(); m_current_frame->data = new_packet; }
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 vc1::es_parser_c::handle_packet(memory_cptr packet) { uint32_t marker = get_uint32_be(packet->get_buffer()); switch (marker) { case VC1_MARKER_SEQHDR: handle_sequence_header_packet(packet); break; case VC1_MARKER_ENTRYPOINT: handle_entrypoint_packet(packet); break; case VC1_MARKER_FRAME: handle_frame_packet(packet); break; case VC1_MARKER_SLICE: handle_slice_packet(packet); break; case VC1_MARKER_FIELD: handle_field_packet(packet); break; case VC1_MARKER_ENDOFSEQ: handle_end_of_sequence_packet(packet); break; default: handle_unknown_packet(marker, packet); break; } }
int aac_adif_reader_c::probe_file(mm_io_c *in, uint64_t size) { try { if (4 > size) return 0; unsigned char buf[4]; in->setFilePointer(0, seek_beginning); if (in->read(buf, 4) != 4) return 0; in->setFilePointer(0, seek_beginning); if (FOURCC('A', 'D', 'I', 'F') == get_uint32_be(buf)) { id_result_container_unsupported(in->get_file_name(), Y("AAC with ADIF headers")); // Never reached: return 1; } return 0; } catch (...) { return 0; } }
/** \brief Extract the FPS from a MPEG video sequence header This function looks for a MPEG sequence header in a buffer containing a MPEG1 or MPEG2 video frame. If such a header is found its FPS index is extracted and returned. This index can be mapped to the actual number of frames per second with the function ::mpeg_video_get_fps \param buffer The buffer to search for the header. \param buffer_size The buffer size. \return The index or \c -1 if no MPEG sequence header was found or if the buffer was too small. */ int mpeg1_2::extract_fps_idx(const unsigned char *buffer, int buffer_size) { mxverb(3, boost::format("mpeg_video_fps: start search in %1% bytes\n") % buffer_size); if (buffer_size < 8) { mxverb(3, "mpeg_video_fps: sequence header too small\n"); return -1; } auto marker = get_uint32_be(buffer); int idx = 4; while ((idx < buffer_size) && (marker != MPEGVIDEO_SEQUENCE_HEADER_START_CODE)) { marker <<= 8; marker |= buffer[idx]; idx++; } if ((idx + 3) >= buffer_size) { mxverb(3, "mpeg_video_fps: no full sequence header start code found\n"); return -1; } mxverb(3, boost::format("mpeg_video_fps: found sequence header start code at %1%\n") % (idx - 4)); return buffer[idx + 3] & 0x0f; }
int dirac_es_reader_c::probe_file(mm_io_c *in, uint64_t size) { try { if (PROBESIZE > size) return 0; in->setFilePointer(0, seek_beginning); memory_cptr buf = memory_c::alloc(READ_SIZE); int num_read = in->read(buf->get_buffer(), READ_SIZE); if (4 > num_read) return 0; uint32_t marker = get_uint32_be(buf->get_buffer()); if (DIRAC_SYNC_WORD != marker) return 0; dirac::es_parser_c parser; parser.add_bytes(buf->get_buffer(), num_read); return parser.is_sequence_header_available(); } catch (...) { mxinfo("have an xcptn\n"); } return 0; }
int vc1_es_reader_c::probe_file(mm_io_c *in, uint64_t size) { try { if (PROBESIZE > size) return 0; in->setFilePointer(0, seek_beginning); memory_cptr buf = memory_c::alloc(READ_SIZE); int num_read = in->read(buf->get_buffer(), READ_SIZE); if (4 > num_read) return 0; uint32_t marker = get_uint32_be(buf->get_buffer()); if ((VC1_MARKER_SEQHDR != marker) && (VC1_MARKER_ENTRYPOINT != marker) && (VC1_MARKER_FRAME != marker)) return 0; vc1::es_parser_c parser; parser.add_bytes(buf->get_buffer(), num_read); return parser.is_sequence_header_available(); } catch (...) { mxinfo(Y("have an xcptn\n")); } return 0; }
int asf_reader_c::probe_file(mm_io_c *in, uint64_t size) { try { if (4 > size) return 0; unsigned char buf[4]; in->setFilePointer(0, seek_beginning); if (in->read(buf, 4) != 4) return 0; in->setFilePointer(0, seek_beginning); if (MAGIC_ASF_WMV == get_uint32_be(buf)) { id_result_container_unsupported(in->get_file_name(), "Windows Media (ASF/WMV)"); // Never reached: return 1; } return 0; } catch (...) { return 0; } }
void avi_reader_c::set_avc_nal_size_size(mpeg4_p10_es_video_packetizer_c *ptzr) { m_avc_nal_size_size = ptzr->get_nalu_size_length(); for (size_t i = 0; i < m_max_video_frames; ++i) { int size = AVI_frame_size(m_avi, i); if (0 == size) continue; memory_cptr buffer = memory_c::alloc(size); AVI_set_video_position(m_avi, i); int key = 0; size = AVI_read_frame(m_avi, reinterpret_cast<char *>(buffer->get_buffer()), &key); if ( (4 <= size) && ( (get_uint32_be(buffer->get_buffer()) == NALU_START_CODE) || (get_uint24_be(buffer->get_buffer()) == NALU_START_CODE))) m_avc_nal_size_size = -1; break; } AVI_set_video_position(m_avi, 0); }
uint32_t mm_io_c::read_uint32_be() { unsigned char buffer[4]; if (read(buffer, 4) != 4) throw mtx::mm_io::end_of_file_x(); return get_uint32_be(buffer); }
void real_reader_c::parse_headers() { if (rmff_read_headers(file) != RMFF_ERR_OK) return; int ndx; for (ndx = 0; ndx < file->num_tracks; ndx++) { rmff_track_t *track = file->tracks[ndx]; if ((RMFF_TRACK_TYPE_UNKNOWN == track->type) || (get_uint32_be(&track->mdpr_header.type_specific_size) == 0)) continue; if ((RMFF_TRACK_TYPE_VIDEO == track->type) && !demuxing_requested('v', track->id)) continue; if ((RMFF_TRACK_TYPE_AUDIO == track->type) && !demuxing_requested('a', track->id)) continue; if ((NULL == track->mdpr_header.mime_type) || ( strcmp(track->mdpr_header.mime_type, "audio/x-pn-realaudio") && strcmp(track->mdpr_header.mime_type, "video/x-pn-realvideo"))) continue; unsigned char *ts_data = track->mdpr_header.type_specific_data; uint32_t ts_size = get_uint32_be(&track->mdpr_header.type_specific_size); real_demuxer_cptr dmx(new real_demuxer_t(track)); if (RMFF_TRACK_TYPE_VIDEO == track->type) { dmx->rvp = (real_video_props_t *)track->mdpr_header.type_specific_data; memcpy(dmx->fourcc, &dmx->rvp->fourcc2, 4); dmx->fourcc[4] = 0; dmx->width = get_uint16_be(&dmx->rvp->width); dmx->height = get_uint16_be(&dmx->rvp->height); uint32_t i = get_uint32_be(&dmx->rvp->fps); dmx->fps = (float)((i & 0xffff0000) >> 16) + ((float)(i & 0x0000ffff)) / 65536.0; dmx->private_data = (unsigned char *)safememdup(ts_data, ts_size); dmx->private_size = ts_size; demuxers.push_back(dmx); } else if (RMFF_TRACK_TYPE_AUDIO == track->type) {
void dirac::es_parser_c::flush() { if (m_unparsed_buffer && (4 <= m_unparsed_buffer->get_size())) { uint32_t marker = get_uint32_be(m_unparsed_buffer->get_buffer()); if (DIRAC_SYNC_WORD == marker) handle_unit(memory_c::clone(m_unparsed_buffer->get_buffer(), m_unparsed_buffer->get_size())); } m_unparsed_buffer.reset(); flush_frame(); }
void vc1::es_parser_c::flush() { if (m_unparsed_buffer && (4 <= m_unparsed_buffer->get_size())) { uint32_t marker = get_uint32_be(m_unparsed_buffer->get_buffer()); if (vc1::is_marker(marker)) handle_packet(memory_c::clone(m_unparsed_buffer->get_buffer(), m_unparsed_buffer->get_size())); } m_unparsed_buffer.reset(); flush_frame(); }
void xtr_mpeg1_2_video_c::handle_frame(xtr_frame_t &f) { binary *buf = (binary *)f.frame->get_buffer(); if (f.references_valid) f.keyframe = (0 == f.bref); if (f.keyframe && m_seq_hdr) { bool seq_hdr_found = false; size_t size = f.frame->get_size(); if (4 <= size) { uint32_t marker = get_uint32_be(buf); seq_hdr_found = MPEGVIDEO_SEQUENCE_HEADER_START_CODE == marker; if (seq_hdr_found && (8 <= size)) { size_t end_pos = 7; marker = get_uint32_be(&buf[4]); while ( ((end_pos + 1) < size) && ( (0x00000100 != (marker & 0xffffff00)) || (MPEGVIDEO_EXT_START_CODE == marker))) { ++end_pos; marker = (marker << 8) | buf[end_pos]; } size_t seq_size = end_pos - (((end_pos + 1) < size) ? 3 : 4); if ((m_seq_hdr->get_size() != seq_size) || memcmp(m_seq_hdr->get_buffer(), buf, seq_size)) m_seq_hdr = memory_c::clone(buf, seq_size); } } if (!seq_hdr_found) m_out->write(m_seq_hdr); } m_out->write(buf, f.frame->get_size()); }
/** \brief Extract the aspect ratio from a MPEG video sequence header This function looks for a MPEG sequence header in a buffer containing a MPEG1 or MPEG2 video frame. If such a header is found its aspect ratio is extracted and returned. \param buffer The buffer to search for the header. \param buffer_size The buffer size. \return \c true if a MPEG sequence header was found and \c false otherwise. */ bool mpeg1_2::extract_ar(const unsigned char *buffer, int buffer_size, float &ar) { uint32_t marker; int idx; mxverb(3, boost::format("mpeg_video_ar: start search in %1% bytes\n") % buffer_size); if (buffer_size < 8) { mxverb(3, "mpeg_video_ar: sequence header too small\n"); return false; } marker = get_uint32_be(buffer); idx = 4; while ((idx < buffer_size) && (marker != MPEGVIDEO_SEQUENCE_HEADER_START_CODE)) { marker <<= 8; marker |= buffer[idx]; idx++; } if (idx >= buffer_size) { mxverb(3, "mpeg_video_ar: no sequence header start code found\n"); return false; } mxverb(3, boost::format("mpeg_video_ar: found sequence header start code at %1%\n") % (idx - 4)); idx += 3; // width and height if (idx >= buffer_size) { mxverb(3, "mpeg_video_ar: sequence header too small\n"); return false; } switch (buffer[idx] & 0xf0) { case MPEGVIDEO_AR_1_1: ar = 1.0f; break; case MPEGVIDEO_AR_4_3: ar = 4.0f / 3.0f; break; case MPEGVIDEO_AR_16_9: ar = 16.0f / 9.0f; break; case MPEGVIDEO_AR_2_21: ar = 2.21f; break; default: ar = -1.0f; } return true; }
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(); }
bool cdxa_reader_c::probe_file(mm_io_c *in, uint64_t size) { try { if (12 > size) return false; unsigned char buffer[12]; in->setFilePointer(0, seek_beginning); if (in->read(buffer, 12) != 12) return false; if ((FOURCC('R', 'I', 'F', 'F') == get_uint32_be(&buffer[0])) && (FOURCC('C', 'D', 'X', 'A') == get_uint32_be(&buffer[8]))) { id_result_container_unsupported(in->get_file_name(), "RIFF CDXA"); // Never reached: return true; } } catch (...) { } return false; }
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(); } }
/* 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(); }
int mpeg_ts_reader_c::parse_pat(unsigned char *pat) { if (!pat) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pat: Invalid parameters!\n"); return -1; } mpeg_ts_pat_t *pat_header = (mpeg_ts_pat_t *)pat; if (pat_header->table_id != 0x00) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pat: Invalid PAT table_id!\n"); return -1; } if (pat_header->get_section_syntax_indicator() != 1 || pat_header->get_current_next_indicator() == 0) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pat: Invalid PAT section_syntax_indicator/current_next_indicator!\n"); return -1; } if (pat_header->section_number != 0 || pat_header->last_section_number != 0) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pat: Unsupported multiple section PAT!\n"); return -1; } unsigned short pat_section_length = pat_header->get_section_length(); uint32_t elapsed_CRC = crc_calc_mpeg2(pat, 3 + pat_section_length - 4/*CRC32*/); uint32_t read_CRC = get_uint32_be(pat + 3 + pat_section_length - 4); if (elapsed_CRC != read_CRC) { mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pat: Wrong PAT CRC !!! Elapsed = 0x%|1$08x|, read 0x%|2$08x|\n") % elapsed_CRC % read_CRC); return -1; } if (pat_section_length < 13 || pat_section_length > 1021) { mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pat: Wrong PAT section_length (= %1%)\n") % pat_section_length); return -1; } unsigned int prog_count = (pat_section_length - 5 - 4/*CRC32*/) / 4; unsigned int i = 0; mpeg_ts_pat_section_t *pat_section = (mpeg_ts_pat_section_t *)(pat + sizeof(mpeg_ts_pat_t)); for (; i < prog_count; i++, pat_section++) { unsigned short local_program_number = pat_section->get_program_number(); uint16_t tmp_pid = pat_section->get_pid(); mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pat: program_number: %1%; %2%_pid: %3%\n") % local_program_number % (0 == local_program_number ? "nit" : "pmt") % tmp_pid); if (0 != local_program_number) { PAT_found = true; bool skip = false; for (uint16_t i = 0; i < tracks.size(); i++) { if (tracks[i]->pid == tmp_pid) { skip = true; break; } } if (skip == true) continue; mpeg_ts_track_ptr PMT(new mpeg_ts_track_c(*this)); PMT->type = PMT_TYPE; PMT->processed = false; PMT->data_ready = false; es_to_process = 0; PMT->set_pid(tmp_pid); tracks.push_back(PMT); } } return 0; }
int mpeg_ts_reader_c::parse_pmt(unsigned char *pmt) { if (!pmt) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: Invalid parameters!\n"); return -1; } mpeg_ts_pmt_t *pmt_header = (mpeg_ts_pmt_t *)pmt; if (pmt_header->table_id != 0x02) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: Invalid PMT table_id!\n"); return -1; } if (pmt_header->get_section_syntax_indicator() != 1 || pmt_header->get_current_next_indicator() == 0) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: Invalid PMT section_syntax_indicator/current_next_indicator!\n"); return -1; } if (pmt_header->section_number != 0 || pmt_header->last_section_number != 0) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: Unsupported multiple section PMT!\n"); return -1; } unsigned short pmt_section_length = pmt_header->get_section_length(); uint32_t elapsed_CRC = crc_calc_mpeg2(pmt, 3 + pmt_section_length - 4/*CRC32*/); uint32_t read_CRC = get_uint32_be(pmt + 3 + pmt_section_length - 4); if (elapsed_CRC != read_CRC) { mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: Wrong PMT CRC !!! Elapsed = 0x%|1$08x|, read 0x%|2$08x|\n") % elapsed_CRC % read_CRC); return -1; } if (pmt_section_length < 13 || pmt_section_length > 1021) { mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: Wrong PMT section_length (=%1%)\n") % pmt_section_length); return -1; } mpeg_ts_pmt_descriptor_t *pmt_descriptor = (mpeg_ts_pmt_descriptor_t *)(pmt + sizeof(mpeg_ts_pmt_t)); unsigned short program_info_length = pmt_header->get_program_info_length(); while (pmt_descriptor < (mpeg_ts_pmt_descriptor_t *)(pmt + sizeof(mpeg_ts_pmt_t) + program_info_length)) pmt_descriptor = (mpeg_ts_pmt_descriptor_t *)((unsigned char *)pmt_descriptor + sizeof(mpeg_ts_pmt_descriptor_t) + pmt_descriptor->length); mpeg_ts_pmt_pid_info_t *pmt_pid_info = (mpeg_ts_pmt_pid_info_t *)pmt_descriptor; // Calculate pids_count size_t pids_found = 0; while (pmt_pid_info < (mpeg_ts_pmt_pid_info_t *)(pmt + 3 + pmt_section_length - 4/*CRC32*/)) { pids_found++; pmt_pid_info = (mpeg_ts_pmt_pid_info_t *)((unsigned char *)pmt_pid_info + sizeof(mpeg_ts_pmt_pid_info_t) + pmt_pid_info->get_es_info_length()); } mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: program number (%1%)\n") % pmt_header->get_program_number()); mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: pcr pid (%1%)\n") % pmt_header->get_pcr_pid()); if (pids_found == 0) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: There's no information about elementary PIDs\n"); return 0; } pmt_pid_info = (mpeg_ts_pmt_pid_info_t *)pmt_descriptor; // Extract pid_info while (pmt_pid_info < (mpeg_ts_pmt_pid_info_t *)(pmt + 3 + pmt_section_length - 4/*CRC32*/)) { mpeg_ts_track_ptr track(new mpeg_ts_track_c(*this)); unsigned short es_info_length = pmt_pid_info->get_es_info_length(); track->type = ES_UNKNOWN; track->set_pid(pmt_pid_info->get_pid()); switch(pmt_pid_info->stream_type) { case ISO_11172_VIDEO: track->type = ES_VIDEO_TYPE; track->fourcc = FOURCC('M', 'P', 'G', '1'); break; case ISO_13818_VIDEO: track->type = ES_VIDEO_TYPE; track->fourcc = FOURCC('M', 'P', 'G', '2'); break; case ISO_14496_PART2_VIDEO: track->type = ES_VIDEO_TYPE; track->fourcc = FOURCC('M', 'P', 'G', '4'); break; case ISO_14496_PART10_VIDEO: track->type = ES_VIDEO_TYPE; track->fourcc = FOURCC('A', 'V', 'C', '1'); break; case STREAM_VIDEO_VC1: track->type = ES_VIDEO_TYPE; track->fourcc = FOURCC('W', 'V', 'C', '1'); break; case ISO_11172_AUDIO: case ISO_13818_AUDIO: track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('M', 'P', '2', ' '); break; case ISO_13818_PART7_AUDIO: track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('A', 'A', 'C', ' '); break; case ISO_14496_PART3_AUDIO: track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('A', 'A', 'C', ' '); break; case STREAM_AUDIO_AC3: case STREAM_AUDIO_AC3_PLUS: // EAC3 track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('A', 'C', '3', ' '); break; case STREAM_AUDIO_AC3_LOSSLESS: track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('T', 'R', 'H', 'D'); break; case STREAM_AUDIO_DTS: case STREAM_AUDIO_DTS_HD: case STREAM_AUDIO_DTS_HD_MA: track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('D', 'T', 'S', ' '); break; case STREAM_SUBTITLES_HDMV_PGS: track->type = ES_SUBT_TYPE; track->fourcc = FOURCC('P', 'G', 'S', ' '); track->probed_ok = true; break; case ISO_13818_PES_PRIVATE: break; default: mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: Unknown stream type: %1%\n") % (int)pmt_pid_info->stream_type); track->type = ES_UNKNOWN; break; } pmt_descriptor = (mpeg_ts_pmt_descriptor_t *)((unsigned char *)pmt_pid_info + sizeof(mpeg_ts_pmt_pid_info_t)); bool type_known = false; while (pmt_descriptor < (mpeg_ts_pmt_descriptor_t *)((unsigned char *)pmt_pid_info + sizeof(mpeg_ts_pmt_pid_info_t) + es_info_length)) { mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: PMT descriptor tag 0x%|1$02x| length %2%\n") % static_cast<unsigned int>(pmt_descriptor->tag) % static_cast<unsigned int>(pmt_descriptor->length)); switch(pmt_descriptor->tag) { case 0x56: // Teletext descriptor if (pmt_pid_info->stream_type == ISO_13818_PES_PRIVATE) { // PES containig private data track->type = ES_UNKNOWN; type_known = true; mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: Teletext found but not handled !!\n"); } break; case 0x59: // Subtitles descriptor if (pmt_pid_info->stream_type == ISO_13818_PES_PRIVATE) { // PES containig private data track->type = ES_SUBT_TYPE; track->fourcc = FOURCC('V', 'S', 'U', 'B'); type_known = true; } break; case 0x6A: // AC3 descriptor case 0x7A: // EAC3 descriptor if (pmt_pid_info->stream_type == ISO_13818_PES_PRIVATE) { // PES containig private data track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('A', 'C', '3', ' '); type_known = true; } break; case 0x7b: // DTS descriptor if (pmt_pid_info->stream_type == ISO_13818_PES_PRIVATE) { // PES containig private data track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('D', 'T', 'S', ' '); type_known = true; } break; case 0x0a: // ISO 639 language descriptor if (3 <= pmt_descriptor->length) { int language_idx = map_to_iso639_2_code(std::string(reinterpret_cast<char *>(pmt_descriptor + 1), 3).c_str()); if (-1 != language_idx) track->language = iso639_languages[language_idx].iso639_2_code; } break; } pmt_descriptor = (mpeg_ts_pmt_descriptor_t *)((unsigned char *)pmt_descriptor + sizeof(mpeg_ts_pmt_descriptor_t) + pmt_descriptor->length); } // Default to AC3 if it's a PES private stream type that's missing // a known/more concrete descriptor tag. if ((pmt_pid_info->stream_type == ISO_13818_PES_PRIVATE) && !type_known) { track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('A', 'C', '3', ' '); } pmt_pid_info = (mpeg_ts_pmt_pid_info_t *)((unsigned char *)pmt_pid_info + sizeof(mpeg_ts_pmt_pid_info_t) + es_info_length); if (track->type != ES_UNKNOWN) { PMT_found = true; track->pid = track->pid; track->processed = false; track->data_ready = false; tracks.push_back(track); es_to_process++; uint32_t fourcc = get_uint32_be(&track->fourcc); mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: PID %1% has type: 0x%|2$08x| (%3%)\n") % track->pid % fourcc % std::string(reinterpret_cast<char *>(&fourcc), 4)); } } return 0; }
int32_t get_int32_be(uint8_t *buffer) { return((int32_t)get_uint32_be(buffer)); }
uint32_t fourcc_c::read(void const *mem, fourcc_c::byte_order_t byte_order) { return val(get_uint32_be(mem), byte_order); }
int mpeg_es_reader_c::probe_file(mm_io_c *in, uint64_t size) { if (PROBESIZE > size) return 0; try { memory_cptr af_buf = memory_c::alloc(READ_SIZE); unsigned char *buf = af_buf->get_buffer(); in->setFilePointer(0, seek_beginning); int num_read = in->read(buf, READ_SIZE); if (4 > num_read) return 0; in->setFilePointer(0, seek_beginning); // MPEG TS starts with 0x47. if (0x47 == buf[0]) return 0; // MPEG PS starts with 0x000001ba. uint32_t value = get_uint32_be(buf); if (MPEGVIDEO_PACKET_START_CODE == value) return 0; // Due to type detection woes mkvmerge requires // the stream to start with a MPEG start code. if (!mpeg_is_start_code(value)) return 0; bool gop_start_code_found = false; bool sequence_start_code_found = false; bool ext_start_code_found = false; bool picture_start_code_found = false; bool slice_start_code_found = false; bool ok = false; // Let's look for a MPEG ES start code inside the first 1 MB. int i; for (i = 4; i < num_read - 1; i++) { if (mpeg_is_start_code(value)) { mxverb(3, boost::format("mpeg_es_detection: start code found; fourth byte: 0x%|1$02x|\n") % (value & 0xff)); if (MPEGVIDEO_SEQUENCE_HEADER_START_CODE == value) sequence_start_code_found = true; else if (MPEGVIDEO_PICTURE_START_CODE == value) picture_start_code_found = true; else if (MPEGVIDEO_GROUP_OF_PICTURES_START_CODE == value) gop_start_code_found = true; else if (MPEGVIDEO_EXT_START_CODE == value) gop_start_code_found = true; else if ((MPEGVIDEO_FIRST_SLICE_START_CODE >= value) && (MPEGVIDEO_LAST_SLICE_START_CODE <= value)) slice_start_code_found = true; ok = sequence_start_code_found && picture_start_code_found && (gop_start_code_found || ext_start_code_found || slice_start_code_found); if (ok) break; } value <<= 8; value |= buf[i]; } mxverb(3, boost::format("mpeg_es_detection: sequence %1% picture %2% gop %3% ext %4% slice %5%\n") % sequence_start_code_found % picture_start_code_found % gop_start_code_found % ext_start_code_found % slice_start_code_found); if (!ok) return 0; // Let's try to read one frame. M2VParser parser; parser.SetProbeMode(); if (!read_frame(parser, *in, READ_SIZE)) return 0; } catch (...) { return 0; } return 1; }
void dirac::es_parser_c::add_bytes(unsigned char *buffer, size_t size) { memory_slice_cursor_c cursor; bool previous_found = false; size_t previous_pos = 0; int64_t previous_stream_pos = m_stream_pos; if (m_unparsed_buffer && (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 (DIRAC_SYNC_WORD == marker) { if (!previous_found) { previous_found = true; 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(); continue; } unsigned char offset_buffer[4]; cursor.copy(offset_buffer, previous_pos + 4 + 1, 4); uint32_t next_offset = get_uint32_be(offset_buffer); if ((0 == next_offset) || ((previous_pos + next_offset) <= (cursor.get_position() - 4))) { int new_size = cursor.get_position() - 4 - previous_pos; memory_cptr packet = memory_c::alloc(new_size); cursor.copy(packet->get_buffer(), previous_pos, new_size); handle_unit(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(); } } unsigned 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.reset(); }