Esempio n. 1
0
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));
}
Esempio n. 2
0
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"));
  }
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
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();
}
Esempio n. 5
0
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;
  }
}
Esempio n. 6
0
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);
}
Esempio n. 7
0
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);
}
Esempio n. 9
0
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;
  }
}
Esempio n. 10
0
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);
}
Esempio n. 11
0
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);
}
Esempio n. 13
0
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;
  }
}