void avi_reader_c::create_mpeg1_2_packetizer() { std::shared_ptr<M2VParser> m2v_parser(new M2VParser); m2v_parser->SetProbeMode(); if (m_ti.m_private_data && (m_ti.m_private_data->get_size() < sizeof(alBITMAPINFOHEADER))) m2v_parser->WriteData(m_ti.m_private_data->get_buffer() + sizeof(alBITMAPINFOHEADER), m_ti.m_private_data->get_size() - sizeof(alBITMAPINFOHEADER)); unsigned int frame_number = 0; unsigned int state = m2v_parser->GetState(); while ((frame_number < std::min(m_max_video_frames, 100u)) && (MPV_PARSER_STATE_FRAME != state)) { ++frame_number; int size = AVI_frame_size(m_avi, frame_number - 1); if (0 == size) continue; AVI_set_video_position(m_avi, frame_number - 1); memory_cptr buffer = memory_c::alloc(size); int key = 0; int num_read = AVI_read_frame(m_avi, reinterpret_cast<char *>(buffer->get_buffer()), &key); if (0 >= num_read) continue; m2v_parser->WriteData(buffer->get_buffer(), num_read); state = m2v_parser->GetState(); } AVI_set_video_position(m_avi, 0); if (MPV_PARSER_STATE_FRAME != state) mxerror_tid(m_ti.m_fname, 0, Y("Could not extract the sequence header from this MPEG-1/2 track.\n")); MPEG2SequenceHeader seq_hdr = m2v_parser->GetSequenceHeader(); std::shared_ptr<MPEGFrame> frame(m2v_parser->ReadFrame()); if (!frame) mxerror_tid(m_ti.m_fname, 0, Y("Could not extract the sequence header from this MPEG-1/2 track.\n")); int display_width = ((0 >= seq_hdr.aspectRatio) || (1 == seq_hdr.aspectRatio)) ? seq_hdr.width : static_cast<int>(seq_hdr.height * seq_hdr.aspectRatio); MPEGChunk *raw_seq_hdr = m2v_parser->GetRealSequenceHeader(); if (raw_seq_hdr) m_ti.m_private_data = memory_c::clone(raw_seq_hdr->GetPointer(), raw_seq_hdr->GetSize()); else m_ti.m_private_data.reset(); m_vptzr = add_packetizer(new mpeg1_2_video_packetizer_c(this, m_ti, m2v_parser->GetMPEGVersion(), seq_hdr.frameOrFieldRate, seq_hdr.width, seq_hdr.height, display_width, seq_hdr.height, false)); show_packetizer_info(0, PTZR(m_vptzr)); }
void avi_reader_c::create_mpeg4_p10_packetizer() { try { mpeg4_p10_es_video_packetizer_c *ptzr = new mpeg4_p10_es_video_packetizer_c(this, m_ti); m_vptzr = add_packetizer(ptzr); ptzr->set_video_pixel_dimensions(AVI_video_width(m_avi), AVI_video_height(m_avi)); if (0 != m_fps) ptzr->set_container_default_field_duration(1000000000ll / m_fps / 2); uint32_t extra_data_size = get_uint32_le(&m_avi->bitmap_info_header->bi_size) - sizeof(alBITMAPINFOHEADER); if (0 < extra_data_size) { memory_cptr avc_extra_nalus = mpeg4::p10::avcc_to_nalus(reinterpret_cast<unsigned char *>(m_avi->bitmap_info_header + 1), extra_data_size); if (avc_extra_nalus) ptzr->add_extra_data(avc_extra_nalus); } set_avc_nal_size_size(ptzr); show_packetizer_info(0, ptzr); } catch (...) { mxerror_tid(m_ti.m_fname, 0, Y("Could not extract the decoder specific config data (AVCC) from this AVC/h.264 track.\n")); } }
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 mpeg4_p2_video_packetizer_c::extract_config_data(packet_cptr &packet) { if (m_ti.m_private_data) return; m_ti.m_private_data = memory_cptr{mpeg4::p2::parse_config_data(packet->data->get_buffer(), packet->data->get_size(), m_config_data)}; if (!m_ti.m_private_data) mxerror_tid(m_ti.m_fname, m_ti.m_id, Y("Could not find the codec configuration data in the first MPEG-4 part 2 video frame. This track cannot be stored in native mode.\n")); fix_codec_string(); set_codec_private(m_ti.m_private_data); rerender_track_headers(); }
generic_packetizer_c * avi_reader_c::create_vorbis_packetizer(int aid) { try { if (m_ti.m_private_data) throw mtx::input::extended_x(Y("Invalid Vorbis headers in AVI audio track.")); auto c = m_ti.m_private_data->get_buffer(); if (2 != c[0]) throw mtx::input::extended_x(Y("Invalid Vorbis headers in AVI audio track.")); int offset = 1; const int laced_size = m_ti.m_private_data->get_size(); int i; int header_sizes[3]; unsigned char *headers[3]; for (i = 0; 2 > i; ++i) { int size = 0; while ((offset < laced_size) && (255u == c[offset])) { size += 255; ++offset; } if ((laced_size - 1) <= offset) throw mtx::input::extended_x(Y("Invalid Vorbis headers in AVI audio track.")); size += c[offset]; header_sizes[i] = size; ++offset; } headers[0] = &c[offset]; headers[1] = &c[offset + header_sizes[0]]; headers[2] = &c[offset + header_sizes[0] + header_sizes[1]]; header_sizes[2] = laced_size - offset - header_sizes[0] - header_sizes[1]; m_ti.m_private_data.reset(); return new vorbis_packetizer_c(this, m_ti, headers[0], header_sizes[0], headers[1], header_sizes[1], headers[2], header_sizes[2]); } catch (mtx::exception &e) { mxerror_tid(m_ti.m_fname, aid + 1, boost::format("%1%\n") % e.error()); // Never reached, but make the compiler happy: return nullptr; } }
void ogm_a_flac_demuxer_c::initialize() { flac_header_extractor_c fhe(reader->m_ti.m_fname, serialno, mode); if (!fhe.extract()) mxerror_tid(reader->m_ti.m_fname, track_id, Y("Could not read the FLAC header packets.\n")); flac_header_packets = fhe.num_header_packets; sample_rate = fhe.sample_rate; channels = fhe.channels; bits_per_sample = fhe.bits_per_sample; last_granulepos = 0; units_processed = 1; if ((ofm_post_1_1_1 == mode) && !packet_data.empty() && (13 < packet_data.front()->get_size())) packet_data.front()->set_offset(9); }
generic_packetizer_c * avi_reader_c::create_aac_packetizer(int aid, avi_demuxer_t &demuxer) { int profile, channels, sample_rate, output_sample_rate; bool is_sbr; bool headerless = (AVI_audio_format(m_avi) != 0x706d); if (!m_ti.m_private_data || ( (0x706d == AVI_audio_format(m_avi)) && ((sizeof(alWAVEFORMATEX) + 7) < m_ti.m_private_data->get_size()))) { channels = AVI_audio_channels(m_avi); sample_rate = AVI_audio_rate(m_avi); if (44100 > sample_rate) { profile = AAC_PROFILE_SBR; output_sample_rate = sample_rate * 2; is_sbr = true; } else { profile = AAC_PROFILE_MAIN; output_sample_rate = sample_rate; is_sbr = false; } unsigned char created_aac_data[AAC_MAX_PRIVATE_DATA_SIZE]; auto size = create_aac_data(created_aac_data, profile, channels, sample_rate, output_sample_rate, is_sbr); m_ti.m_private_data = memory_c::clone(created_aac_data, size); } else { if (!parse_aac_data(m_ti.m_private_data->get_buffer(), m_ti.m_private_data->get_size(), profile, channels, sample_rate, output_sample_rate, is_sbr)) mxerror_tid(m_ti.m_fname, aid + 1, Y("This AAC track does not contain valid headers. Could not parse the AAC information.\n")); if (is_sbr) profile = AAC_PROFILE_SBR; } demuxer.m_samples_per_second = sample_rate; demuxer.m_channels = channels; generic_packetizer_c *packetizer = new aac_packetizer_c(this, m_ti, AAC_ID_MPEG4, profile, demuxer.m_samples_per_second, demuxer.m_channels, false, headerless); if (is_sbr) packetizer->set_audio_output_sampling_freq(output_sample_rate); return packetizer; }
void generic_packetizer_c::add_packet(packet_cptr pack) { if ((0 == m_num_packets) && m_ti.m_reset_timecodes) m_ti.m_tcsync.displacement = -pack->timecode; ++m_num_packets; if (!m_reader->m_ptzr_first_packet) m_reader->m_ptzr_first_packet = this; // strip elements to be removed if ( (-1 != m_htrack_max_add_block_ids) && (pack->data_adds.size() > static_cast<size_t>(m_htrack_max_add_block_ids))) pack->data_adds.resize(m_htrack_max_add_block_ids); if (m_compressor) { try { pack->data = m_compressor->compress(pack->data); size_t i; for (i = 0; pack->data_adds.size() > i; ++i) pack->data_adds[i] = m_compressor->compress(pack->data_adds[i]); } catch (mtx::compression_x &e) { mxerror_tid(m_ti.m_fname, m_ti.m_id, boost::format(Y("Compression failed: %1%\n")) % e.error()); } } pack->data->grab(); for (auto &data_add : pack->data_adds) data_add->grab(); pack->source = this; m_enqueued_bytes += pack->data->get_size(); if ((0 > pack->bref) && (0 <= pack->fref)) std::swap(pack->bref, pack->fref); if (1 != m_connected_to) add_packet2(pack); else m_deferred_packets.push_back(pack); }
generic_packetizer_c * avi_reader_c::create_dts_packetizer(int aid) { try { AVI_set_audio_track(m_avi, aid); long audio_position = AVI_get_audio_position_index(m_avi); unsigned int num_read = 0; int dts_position = -1; byte_buffer_c buffer; dts_header_t dtsheader; while ((-1 == dts_position) && (10 > num_read)) { int chunk_size = AVI_read_audio_chunk(m_avi, nullptr); if (0 < chunk_size) { memory_cptr chunk = memory_c::alloc(chunk_size); AVI_read_audio_chunk(m_avi, reinterpret_cast<char *>(chunk->get_buffer())); buffer.add(chunk); dts_position = find_dts_header(buffer.get_buffer(), buffer.get_size(), &dtsheader); } else { dts_position = find_dts_header(buffer.get_buffer(), buffer.get_size(), &dtsheader, true); break; } } if (-1 == dts_position) throw false; AVI_set_audio_position_index(m_avi, audio_position); return new dts_packetizer_c(this, m_ti, dtsheader); } catch (...) { mxerror_tid(m_ti.m_fname, aid + 1, Y("Could not find valid DTS headers in this track's first frames.\n")); return nullptr; } }
void avi_reader_c::add_audio_demuxer(int aid) { for (auto &demuxer : m_audio_demuxers) if (demuxer.m_aid == aid) // Demuxer already added? return; AVI_set_audio_track(m_avi, aid); if (AVI_read_audio_chunk(m_avi, nullptr) < 0) { mxwarn(boost::format(Y("Could not find an index for audio track %1% (avilib error message: %2%). Skipping track.\n")) % (aid + 1) % AVI_strerror()); return; } avi_demuxer_t demuxer; generic_packetizer_c *packetizer = nullptr; alWAVEFORMATEX *wfe = m_avi->wave_format_ex[aid]; uint32_t audio_format = AVI_audio_format(m_avi); demuxer.m_aid = aid; demuxer.m_ptzr = -1; demuxer.m_samples_per_second = AVI_audio_rate(m_avi); demuxer.m_channels = AVI_audio_channels(m_avi); demuxer.m_bits_per_sample = AVI_audio_bits(m_avi); m_ti.m_id = aid + 1; // ID for this audio track. m_ti.m_avi_block_align = get_uint16_le(&wfe->n_block_align); m_ti.m_avi_avg_bytes_per_sec = get_uint32_le(&wfe->n_avg_bytes_per_sec); m_ti.m_avi_samples_per_chunk = get_uint32_le(&m_avi->stream_headers[aid].dw_scale); m_ti.m_avi_sample_scale = get_uint32_le(&m_avi->stream_headers[aid].dw_rate); m_ti.m_avi_samples_per_sec = demuxer.m_samples_per_second; if ((0xfffe == audio_format) && (get_uint16_le(&wfe->cb_size) >= (sizeof(alWAVEFORMATEXTENSION)))) { alWAVEFORMATEXTENSIBLE *ext = reinterpret_cast<alWAVEFORMATEXTENSIBLE *>(wfe); audio_format = get_uint32_le(&ext->extension.guid.data1); } else if (get_uint16_le(&wfe->cb_size) > 0) m_ti.m_private_data = memory_c::clone(wfe + 1, get_uint16_le(&wfe->cb_size)); else m_ti.m_private_data.reset(); switch(audio_format) { case 0x0001: // raw PCM audio case 0x0003: // raw PCM audio (float) packetizer = new pcm_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, demuxer.m_bits_per_sample, 0x0003 == audio_format ? pcm_packetizer_c::ieee_float : pcm_packetizer_c::little_endian_integer); break; case 0x0050: // MP2 case 0x0055: // MP3 packetizer = new mp3_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, false); break; case 0x2000: // AC3 packetizer = new ac3_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, 0); break; case 0x2001: // DTS packetizer = create_dts_packetizer(aid); break; case 0x00ff: case 0x706d: // AAC packetizer = create_aac_packetizer(aid, demuxer); break; case 0x566f: // Vorbis packetizer = create_vorbis_packetizer(aid); break; default: mxerror_tid(m_ti.m_fname, aid + 1, boost::format(Y("Unknown/unsupported audio format 0x%|1$04x| for this audio track.\n")) % audio_format); } show_packetizer_info(aid + 1, packetizer); demuxer.m_ptzr = add_packetizer(packetizer); m_audio_demuxers.push_back(demuxer); int i, maxchunks = AVI_audio_chunks(m_avi); for (i = 0; i < maxchunks; i++) m_bytes_to_process += AVI_audio_size(m_avi, i); }
int mpeg4_p2_video_packetizer_c::process_non_native(packet_cptr packet) { extract_config_data(packet); // Add a timecode and a duration if they've been given. if (-1 != packet->timecode) { if (!m_default_duration_forced) m_available_timecodes.push_back(timecode_duration_t(packet->timecode, packet->duration)); else { m_available_timecodes.push_back(timecode_duration_t(m_timecodes_generated * m_htrack_default_duration, m_htrack_default_duration)); ++m_timecodes_generated; } } else if (0.0 == m_fps) mxerror_tid(m_ti.m_fname, m_ti.m_id, Y("Cannot convert non-native MPEG4 video frames into native ones if the source container " "provides neither timecodes nor a number of frames per second.\n")); std::vector<video_frame_t> frames; mpeg4::p2::find_frame_types(packet->data->get_buffer(), packet->data->get_size(), frames, m_config_data); for (auto &frame : frames) { if (!frame.is_coded) { ++m_statistics.m_num_n_vops; int num_surplus_timecodes = static_cast<int>(m_available_timecodes.size()) - static_cast<int>(m_ref_frames.size() + m_b_frames.size()); if (0 < num_surplus_timecodes) { std::deque<timecode_duration_t>::iterator start = m_available_timecodes.begin() + m_ref_frames.size() + m_b_frames.size(); std::deque<timecode_duration_t>::iterator end = start + num_surplus_timecodes; if (0 != (m_ref_frames.size() + m_b_frames.size())) { std::deque<timecode_duration_t>::iterator last = m_available_timecodes.begin() + m_ref_frames.size() + m_b_frames.size() - 1; std::deque<timecode_duration_t>::iterator cur = start; while (cur != end) { last->m_duration = std::max(last->m_duration, static_cast<int64_t>(0)) + std::max(cur->m_duration, static_cast<int64_t>(0)); ++cur; } } m_available_timecodes.erase(start, end); m_statistics.m_num_dropped_timecodes += num_surplus_timecodes; } continue; } if (FRAME_TYPE_I == frame.type) ++m_statistics.m_num_i_frames; else if (FRAME_TYPE_P == frame.type) ++m_statistics.m_num_p_frames; else ++m_statistics.m_num_b_frames; // Maybe we can flush queued frames now. But only if we don't have // a B frame. if (FRAME_TYPE_B != frame.type) flush_frames(false); frame.data = (unsigned char *)safememdup(packet->data->get_buffer() + frame.pos, frame.size); frame.timecode = -1; if (FRAME_TYPE_B == frame.type) m_b_frames.push_back(frame); else m_ref_frames.push_back(frame); } m_previous_timecode = m_available_timecodes.back().m_timecode; return FILE_STATUS_MOREDATA; }
generic_packetizer_c::generic_packetizer_c(generic_reader_c *reader, track_info_c &ti) : m_num_packets{} , m_next_packet_wo_assigned_timecode{} , m_free_refs{-1} , m_next_free_refs{-1} , m_enqueued_bytes{} , m_safety_last_timecode{} , m_safety_last_duration{} , m_track_entry{} , m_hserialno{-1} , m_htrack_type{-1} , m_htrack_min_cache{} , m_htrack_max_cache{-1} , m_htrack_default_duration{-1} , m_default_duration_forced{true} , m_default_track_warning_printed{} , m_huid{} , m_htrack_max_add_block_ids{-1} , m_haudio_sampling_freq{-1.0} , m_haudio_output_sampling_freq{-1.0} , m_haudio_channels{-1} , m_haudio_bit_depth{-1} , m_hvideo_interlaced_flag{-1} , m_hvideo_pixel_width{-1} , m_hvideo_pixel_height{-1} , m_hvideo_display_width{-1} , m_hvideo_display_height{-1} , m_hcompression{COMPRESSION_UNSPECIFIED} , m_timestamp_factory_application_mode{TFA_AUTOMATIC} , m_last_cue_timecode{-1} , m_has_been_flushed{} , m_prevent_lacing{} , m_connected_successor{} , m_ti{ti} , m_reader{reader} , m_connected_to{} , m_correction_timecode_offset{} , m_append_timecode_offset{} , m_max_timecode_seen{} , m_relaxed_timecode_checking{} { // Let's see if the user specified timecode sync for this track. if (mtx::includes(m_ti.m_timecode_syncs, m_ti.m_id)) m_ti.m_tcsync = m_ti.m_timecode_syncs[m_ti.m_id]; else if (mtx::includes(m_ti.m_timecode_syncs, -1)) m_ti.m_tcsync = m_ti.m_timecode_syncs[-1]; if (0 == m_ti.m_tcsync.numerator) m_ti.m_tcsync.numerator = 1; if (0 == m_ti.m_tcsync.denominator) m_ti.m_tcsync.denominator = 1; // Let's see if the user specified "reset timecodes" for this track. m_ti.m_reset_timecodes = mtx::includes(m_ti.m_reset_timecodes_specs, m_ti.m_id) || mtx::includes(m_ti.m_reset_timecodes_specs, -1); // Let's see if the user has specified which cues he wants for this track. if (mtx::includes(m_ti.m_cue_creations, m_ti.m_id)) m_ti.m_cues = m_ti.m_cue_creations[m_ti.m_id]; else if (mtx::includes(m_ti.m_cue_creations, -1)) m_ti.m_cues = m_ti.m_cue_creations[-1]; // Let's see if the user has given a default track flag for this track. if (mtx::includes(m_ti.m_default_track_flags, m_ti.m_id)) m_ti.m_default_track = m_ti.m_default_track_flags[m_ti.m_id]; else if (mtx::includes(m_ti.m_default_track_flags, -1)) m_ti.m_default_track = m_ti.m_default_track_flags[-1]; // Let's see if the user has given a fix avc fps flag for this track. if (mtx::includes(m_ti.m_fix_bitstream_frame_rate_flags, m_ti.m_id)) m_ti.m_fix_bitstream_frame_rate = m_ti.m_fix_bitstream_frame_rate_flags[m_ti.m_id]; else if (mtx::includes(m_ti.m_fix_bitstream_frame_rate_flags, -1)) m_ti.m_fix_bitstream_frame_rate = m_ti.m_fix_bitstream_frame_rate_flags[-1]; // Let's see if the user has given a forced track flag for this track. if (mtx::includes(m_ti.m_forced_track_flags, m_ti.m_id)) m_ti.m_forced_track = m_ti.m_forced_track_flags[m_ti.m_id]; else if (mtx::includes(m_ti.m_forced_track_flags, -1)) m_ti.m_forced_track = m_ti.m_forced_track_flags[-1]; // Let's see if the user has given a enabled track flag for this track. if (mtx::includes(m_ti.m_enabled_track_flags, m_ti.m_id)) m_ti.m_enabled_track = m_ti.m_enabled_track_flags[m_ti.m_id]; else if (mtx::includes(m_ti.m_enabled_track_flags, -1)) m_ti.m_enabled_track = m_ti.m_enabled_track_flags[-1]; // Let's see if the user has specified a language for this track. if (mtx::includes(m_ti.m_languages, m_ti.m_id)) m_ti.m_language = m_ti.m_languages[m_ti.m_id]; else if (mtx::includes(m_ti.m_languages, -1)) m_ti.m_language = m_ti.m_languages[-1]; // Let's see if the user has specified a sub charset for this track. if (mtx::includes(m_ti.m_sub_charsets, m_ti.m_id)) m_ti.m_sub_charset = m_ti.m_sub_charsets[m_ti.m_id]; else if (mtx::includes(m_ti.m_sub_charsets, -1)) m_ti.m_sub_charset = m_ti.m_sub_charsets[-1]; // Let's see if the user has specified a sub charset for this track. if (mtx::includes(m_ti.m_all_tags, m_ti.m_id)) m_ti.m_tags_file_name = m_ti.m_all_tags[m_ti.m_id]; else if (mtx::includes(m_ti.m_all_tags, -1)) m_ti.m_tags_file_name = m_ti.m_all_tags[-1]; if (!m_ti.m_tags_file_name.empty()) m_ti.m_tags = mtx::xml::ebml_tags_converter_c::parse_file(m_ti.m_tags_file_name, false); // Let's see if the user has specified how this track should be compressed. if (mtx::includes(m_ti.m_compression_list, m_ti.m_id)) m_ti.m_compression = m_ti.m_compression_list[m_ti.m_id]; else if (mtx::includes(m_ti.m_compression_list, -1)) m_ti.m_compression = m_ti.m_compression_list[-1]; // Let's see if the user has specified a name for this track. if (mtx::includes(m_ti.m_track_names, m_ti.m_id)) m_ti.m_track_name = m_ti.m_track_names[m_ti.m_id]; else if (mtx::includes(m_ti.m_track_names, -1)) m_ti.m_track_name = m_ti.m_track_names[-1]; // Let's see if the user has specified external timecodes for this track. if (mtx::includes(m_ti.m_all_ext_timecodes, m_ti.m_id)) m_ti.m_ext_timecodes = m_ti.m_all_ext_timecodes[m_ti.m_id]; else if (mtx::includes(m_ti.m_all_ext_timecodes, -1)) m_ti.m_ext_timecodes = m_ti.m_all_ext_timecodes[-1]; // Let's see if the user has specified an aspect ratio or display dimensions // for this track. int i = LOOKUP_TRACK_ID(m_ti.m_display_properties); if (-2 != i) { display_properties_t &dprop = m_ti.m_display_properties[i]; if (0 > dprop.aspect_ratio) { set_video_display_dimensions(dprop.width, dprop.height, OPTION_SOURCE_COMMAND_LINE); } else { set_video_aspect_ratio(dprop.aspect_ratio, dprop.ar_factor, OPTION_SOURCE_COMMAND_LINE); m_ti.m_aspect_ratio_given = true; } } if (m_ti.m_aspect_ratio_given && m_ti.m_display_dimensions_given) { if (m_ti.m_aspect_ratio_is_factor) mxerror_tid(m_ti.m_fname, m_ti.m_id, boost::format(Y("Both the aspect ratio factor and '--display-dimensions' were given.\n"))); else mxerror_tid(m_ti.m_fname, m_ti.m_id, boost::format(Y("Both the aspect ratio and '--display-dimensions' were given.\n"))); } // Let's see if the user has specified a FourCC for this track. if (mtx::includes(m_ti.m_all_fourccs, m_ti.m_id)) m_ti.m_fourcc = m_ti.m_all_fourccs[m_ti.m_id]; else if (mtx::includes(m_ti.m_all_fourccs, -1)) m_ti.m_fourcc = m_ti.m_all_fourccs[-1]; // Let's see if the user has specified a FourCC for this track. i = LOOKUP_TRACK_ID(m_ti.m_pixel_crop_list); if (-2 != i) set_video_pixel_cropping(m_ti.m_pixel_crop_list[i], OPTION_SOURCE_COMMAND_LINE); // Let's see if the user has specified a stereo mode for this track. i = LOOKUP_TRACK_ID(m_ti.m_stereo_mode_list); if (-2 != i) set_video_stereo_mode(m_ti.m_stereo_mode_list[m_ti.m_id], OPTION_SOURCE_COMMAND_LINE); // Let's see if the user has specified a default duration for this track. if (mtx::includes(m_ti.m_default_durations, m_ti.m_id)) m_htrack_default_duration = m_ti.m_default_durations[m_ti.m_id]; else if (mtx::includes(m_ti.m_default_durations, -1)) m_htrack_default_duration = m_ti.m_default_durations[-1]; else m_default_duration_forced = false; // Let's see if the user has set a max_block_add_id if (mtx::includes(m_ti.m_max_blockadd_ids, m_ti.m_id)) m_htrack_max_add_block_ids = m_ti.m_max_blockadd_ids[m_ti.m_id]; else if (mtx::includes(m_ti.m_max_blockadd_ids, -1)) m_htrack_max_add_block_ids = m_ti.m_max_blockadd_ids[-1]; // Let's see if the user has specified a NALU size length for this track. if (mtx::includes(m_ti.m_nalu_size_lengths, m_ti.m_id)) m_ti.m_nalu_size_length = m_ti.m_nalu_size_lengths[m_ti.m_id]; else if (mtx::includes(m_ti.m_nalu_size_lengths, -1)) m_ti.m_nalu_size_length = m_ti.m_nalu_size_lengths[-1]; // Let's see if the user has specified a compression scheme for this track. if (COMPRESSION_UNSPECIFIED != m_ti.m_compression) m_hcompression = m_ti.m_compression; // Set default header values to 'unset'. if (!m_reader->m_appending) { m_hserialno = create_track_number(); g_packetizers_by_track_num[m_hserialno] = this; } m_timestamp_factory = timestamp_factory_c::create(m_ti.m_ext_timecodes, m_ti.m_fname, m_ti.m_id); // If no external timecode file but a default duration has been // given then create a simple timecode factory that generates the // timecodes for the given FPS. if (!m_timestamp_factory && (-1 != m_htrack_default_duration)) m_timestamp_factory = timestamp_factory_c::create_fps_factory(m_htrack_default_duration, m_ti.m_tcsync); }
void avi_reader_c::add_audio_demuxer(int aid) { for (auto &demuxer : m_audio_demuxers) if (demuxer.m_aid == aid) // Demuxer already added? return; AVI_set_audio_track(m_avi, aid); if (AVI_read_audio_chunk(m_avi, nullptr) < 0) { mxwarn(boost::format(Y("Could not find an index for audio track %1% (avilib error message: %2%). Skipping track.\n")) % (aid + 1) % AVI_strerror()); return; } avi_demuxer_t demuxer; generic_packetizer_c *packetizer = nullptr; alWAVEFORMATEX *wfe = m_avi->wave_format_ex[aid]; uint32_t audio_format = AVI_audio_format(m_avi); demuxer.m_aid = aid; demuxer.m_ptzr = -1; demuxer.m_samples_per_second = AVI_audio_rate(m_avi); demuxer.m_channels = AVI_audio_channels(m_avi); demuxer.m_bits_per_sample = AVI_audio_bits(m_avi); m_ti.m_id = aid + 1; // ID for this audio track. auto stream_header = &m_avi->stream_headers[aid]; auto dw_scale = static_cast<int64_t>(get_uint32_le(&stream_header->dw_scale)); auto dw_rate = static_cast<int64_t>(get_uint32_le(&stream_header->dw_rate)); auto dw_sample_size = static_cast<int64_t>(get_uint32_le(&stream_header->dw_sample_size)); m_ti.m_avi_audio_data_rate = dw_scale ? dw_rate * dw_sample_size / dw_scale : 0; if ((0xfffe == audio_format) && (get_uint16_le(&wfe->cb_size) >= (sizeof(alWAVEFORMATEXTENSION)))) { alWAVEFORMATEXTENSIBLE *ext = reinterpret_cast<alWAVEFORMATEXTENSIBLE *>(wfe); audio_format = get_uint32_le(&ext->extension.guid.data1); } else if (get_uint16_le(&wfe->cb_size) > 0) m_ti.m_private_data = memory_c::clone(wfe + 1, get_uint16_le(&wfe->cb_size)); else m_ti.m_private_data.reset(); demuxer.m_codec = codec_c::look_up_audio_format(audio_format); if (demuxer.m_codec.is(codec_c::type_e::A_PCM)) packetizer = new pcm_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, demuxer.m_bits_per_sample, 0x0003 == audio_format ? pcm_packetizer_c::ieee_float : pcm_packetizer_c::little_endian_integer); else if (demuxer.m_codec.is(codec_c::type_e::A_MP2) || demuxer.m_codec.is(codec_c::type_e::A_MP3)) packetizer = new mp3_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, false); else if (demuxer.m_codec.is(codec_c::type_e::A_AC3)) packetizer = new ac3_packetizer_c(this, m_ti, demuxer.m_samples_per_second, demuxer.m_channels, 0); else if (demuxer.m_codec.is(codec_c::type_e::A_DTS)) packetizer = create_dts_packetizer(aid); else if (demuxer.m_codec.is(codec_c::type_e::A_AAC)) packetizer = create_aac_packetizer(aid, demuxer); else if (demuxer.m_codec.is(codec_c::type_e::A_VORBIS)) packetizer = create_vorbis_packetizer(aid); else mxerror_tid(m_ti.m_fname, aid + 1, boost::format(Y("Unknown/unsupported audio format 0x%|1$04x| for this audio track.\n")) % audio_format); packetizer->enable_avi_audio_sync(true); show_packetizer_info(aid + 1, packetizer); demuxer.m_ptzr = add_packetizer(packetizer); m_audio_demuxers.push_back(demuxer); int i, maxchunks = AVI_audio_chunks(m_avi); for (i = 0; i < maxchunks; i++) { auto size = AVI_audio_size(m_avi, i); if (size < AVI_MAX_AUDIO_CHUNK_SIZE) m_bytes_to_process += size; } }