コード例 #1
0
ファイル: Mp4RtpHintInfo.cpp プロジェクト: Fluffiest/splayer
/*----------------------------------------------------------------------
|       main
+---------------------------------------------------------------------*/
int
main(int argc, char** argv)
{
    AP4_Result result = AP4_SUCCESS;

    // parse the command line
    if (argc != 2) PrintUsageAndExit();

    // create the input stream
    AP4_ByteStream* input;
    try {
        input = new AP4_FileByteStream(argv[1],
            AP4_FileByteStream::STREAM_MODE_READ);
    } catch (AP4_Exception) {
        fprintf(stderr, "ERROR: cannot open input file (%s)\n", argv[1]);
        return 1;
    }

    AP4_File* file = new AP4_File(*input);
  

    AP4_Movie* movie = file->GetMovie();
    if (movie != NULL) {
        // get a hint track reader
        AP4_Track* hint_track = movie->GetTrack(AP4_Track::TYPE_HINT, 1);
        if (hint_track == NULL) {
            AP4_Debug("No hint track in this movie\n");
            return AP4_FAILURE;
        }
        AP4_HintTrackReader reader(*hint_track, *movie, 0x01020304);
        AP4_String rtp_file_name(argv[1]);
        rtp_file_name += ".rtp";

        // display the sdp
        AP4_String sdp;
        reader.GetSdpText(sdp);
        AP4_Debug("sdp:\n%s\n\n", sdp.c_str());

        // dump the packet
        result = DumpRtpPackets(reader, rtp_file_name.c_str());
        if (AP4_FAILED(result)) goto bail;

    } else {
        AP4_Debug("No movie found in the file\n");
        return AP4_FAILURE;
    }

bail:
    delete file;
    input->Release();

    return result;
}
コード例 #2
0
/*----------------------------------------------------------------------
|   main
+---------------------------------------------------------------------*/
int
main(int argc, char** argv)
{
    if (argc != 2) {
        PrintUsageAndExit();
    }
    const char* input_filename  = argv[1];
    
    // open the input
    AP4_ByteStream* input = NULL;
    try {
        input = new AP4_FileByteStream(input_filename,
                               AP4_FileByteStream::STREAM_MODE_READ);
    } catch (AP4_Exception) {
        fprintf(stderr, "ERROR: cannot open input file (%s)\n", input_filename);
        return 1;
    }
        
    // get the movie
    AP4_File* file = new AP4_File(*input);
    AP4_Movie* movie = file->GetMovie();
    CHECK(movie != NULL);
    
    AP4_Track* video_track = movie->GetTrack(AP4_Track::TYPE_VIDEO);
    CHECK(video_track != NULL);
    AP4_Ordinal index;
    index = video_track->GetNearestSyncSampleIndex(0, true);
    CHECK(index == 0);
    index = video_track->GetNearestSyncSampleIndex(0, false);
    CHECK(index == 0);
    index = video_track->GetNearestSyncSampleIndex(1, true);
    CHECK(index == 0);
    index = video_track->GetNearestSyncSampleIndex(1, false);
    CHECK(index == 12);
    index = video_track->GetNearestSyncSampleIndex(52, true);
    CHECK(index == 48);
    index = video_track->GetNearestSyncSampleIndex(52, false);
    CHECK(index == video_track->GetSampleCount());
    
    // cleanup
    delete file;
    input->Release();

    return 0;                                            
}
コード例 #3
0
ファイル: Mp4Encrypt.cpp プロジェクト: 9aa5/Bento4
/*----------------------------------------------------------------------
|   CheckWarning
+---------------------------------------------------------------------*/
static bool
CheckWarning(AP4_ByteStream& stream, AP4_ProtectionKeyMap& key_map, Method method)
{
    AP4_File file(stream,
                  AP4_DefaultAtomFactory::Instance,
                  true);
    AP4_Movie* movie = file.GetMovie();
    if (!movie) {
        if (method != METHOD_MPEG_CENC && method != METHOD_PIFF_CBC && method != METHOD_PIFF_CTR) {
            fprintf(stderr, "WARNING: no movie atom found in input file\n");
            return false;
        }
    }

    bool warning = false;
    switch (method) {
        case METHOD_MPEG_CENC:
        case METHOD_PIFF_CBC:
        case METHOD_PIFF_CTR:
            if (movie && !movie->HasFragments()) {
                fprintf(stderr, "WARNING: MPEG-CENC method only applies to fragmented files\n");
                warning = true;
            }
            break;
        default:
            break;
    }

    if (movie) {
        for (unsigned int i=0; i<movie->GetTracks().ItemCount(); i++) {
            AP4_Track* track;
            AP4_Result result = movie->GetTracks().Get(i, track);
            if (AP4_FAILED(result)) return false;
            const AP4_DataBuffer* key = key_map.GetKey(track->GetId());
            if (key == NULL) {
                fprintf(stderr, "WARNING: track ID %d will not be encrypted\n", track->GetId());
                warning = true;
            }
        }
    }
    
    stream.Seek(0);
    return warning;
}
コード例 #4
0
/*----------------------------------------------------------------------
|   AP4_HintTrackReader::AP4_HintTrackReader
+---------------------------------------------------------------------*/
AP4_HintTrackReader::AP4_HintTrackReader(AP4_Track& hint_track, 
                                         AP4_Movie& movie,
                                         AP4_UI32   ssrc) :
    m_HintTrack(hint_track),
    m_MediaTrack(NULL),
    m_MediaTimeScale(0),
    m_RtpSampleData(NULL),
    m_Ssrc(ssrc),
    m_SampleIndex(0),
    m_PacketIndex(0),
    m_RtpSequenceStart(0),
    m_RtpTimeStampStart(0),
    m_RtpTimeScale(0)
{
    // get the media track
    AP4_TrakAtom* hint_trak_atom = hint_track.UseTrakAtom();
    AP4_Atom* atom = hint_trak_atom->FindChild("tref/hint");
    if (atom != NULL) {
        AP4_UI32 media_track_id = AP4_DYNAMIC_CAST(AP4_TrefTypeAtom, atom)->GetTrackIds()[0];
        m_MediaTrack = movie.GetTrack(media_track_id);

        // get the media time scale
        m_MediaTimeScale = m_MediaTrack->GetMediaTimeScale();
    }

    // initiate random generator
    srand((int)time(NULL));

    // rtp sequence start init TODO!!
    m_RtpSequenceStart = (AP4_UI16)(rand()&0xFFFF);

    // rtp timestamp start init TODO!!
    m_RtpTimeStampStart = rand();

    // rtp time scale
    atom = hint_trak_atom->FindChild("mdia/minf/stbl/rtp /tims");
    if (atom) {
        AP4_TimsAtom* tims = AP4_DYNAMIC_CAST(AP4_TimsAtom, atom);
        m_RtpTimeScale = tims->GetTimeScale();
    }

    // generate a random ssrc if = 0
    if (m_Ssrc == 0) {
        m_Ssrc = rand();
    }

    // get the first sample
    GetRtpSample(0);
}
コード例 #5
0
ファイル: Ap4LinearReader.cpp プロジェクト: olegloa/wkrj
/*----------------------------------------------------------------------
|   AP4_LinearReader::AP4_LinearReader
+---------------------------------------------------------------------*/
AP4_LinearReader::AP4_LinearReader(AP4_Movie&      movie, 
                                   AP4_ByteStream* fragment_stream,
                                   AP4_Size        max_buffer) :
    m_Movie(movie),
    m_Fragment(NULL),
    m_FragmentStream(fragment_stream),
    m_NextFragmentPosition(0),
    m_BufferFullness(0),
    m_BufferFullnessPeak(0),
    m_MaxBufferFullness(max_buffer),
    m_Mfra(NULL)
{
    m_HasFragments = movie.HasFragments();
    if (fragment_stream) {
        fragment_stream->AddReference();
        fragment_stream->Tell(m_NextFragmentPosition);
    }
}
コード例 #6
0
/*----------------------------------------------------------------------
|   main
+---------------------------------------------------------------------*/
int
main(int argc, char** argv)
{
    if (argc < 3) {
        PrintUsageAndExit();
    }
    
    // parse command line
    AP4_Result result;
    char** args = argv+1;
    unsigned char key[16];
    bool          key_option = false;
    if (!strcmp(*args, "--key")) {
        if (argc != 5) {
            fprintf(stderr, "ERROR: invalid command line\n");
            return 1;
        }
        ++args;
        if (AP4_ParseHex(*args++, key, 16)) {
            fprintf(stderr, "ERROR: invalid hex format for key\n");
            return 1;
        }
        key_option = true;
    }

	// create the input stream
    AP4_ByteStream* input = NULL;
    result = AP4_FileByteStream::Create(*args++, AP4_FileByteStream::STREAM_MODE_READ, input);
    if (AP4_FAILED(result)) {
        fprintf(stderr, "ERROR: cannot open input (%d)\n", result);
    }
    
	// create the output stream
    AP4_ByteStream* output = NULL;
    result = AP4_FileByteStream::Create(*args++, AP4_FileByteStream::STREAM_MODE_WRITE, output);
    if (AP4_FAILED(result)) {
        fprintf(stderr, "ERROR: cannot open output (%d)\n", result);
    }

	// open the file
    AP4_File* input_file = new AP4_File(*input);   

    // get the movie
    AP4_SampleDescription* sample_description;
    AP4_Track* video_track;
    AP4_Movie* movie = input_file->GetMovie();
    if (movie == NULL) {
        fprintf(stderr, "ERROR: no movie in file\n");
        goto end;
    }

    // get the video track
    video_track = movie->GetTrack(AP4_Track::TYPE_VIDEO);
    if (video_track == NULL) {
        fprintf(stderr, "ERROR: no video track found\n");
        goto end;
    }

    // check that the track is of the right type
    sample_description = video_track->GetSampleDescription(0);
    if (sample_description == NULL) {
        fprintf(stderr, "ERROR: unable to parse sample description\n");
        goto end;
    }

    // show info
    AP4_Debug("Video Track:\n");
    AP4_Debug("  duration: %ld ms\n", video_track->GetDurationMs());
    AP4_Debug("  sample count: %ld\n", video_track->GetSampleCount());

    switch (sample_description->GetType()) {
        case AP4_SampleDescription::TYPE_HEVC:
            WriteSamples(video_track, sample_description, output);
            break;

        case AP4_SampleDescription::TYPE_PROTECTED: 
            if (!key_option) {
                fprintf(stderr, "ERROR: encrypted tracks require a key\n");
                goto end;
            }
            DecryptAndWriteSamples(video_track, sample_description, key, output);
            break;

        default:
            fprintf(stderr, "ERROR: unsupported sample type\n");
            break;
    }

end:
    delete input_file;
    input->Release();
    output->Release();

    return 0;
}
コード例 #7
0
bool Session::initialize()
{
  // Get URN's wich are supported by this addon
  if (!license_type_.empty())
    GetSupportedDecrypterURN(dashtree_.adp_pssh_);

  // Open mpd file
  const char* delim(strrchr(mpdFileURL_.c_str(), '/'));
  if (!delim)
  {
    xbmc->Log(ADDON::LOG_ERROR, "Invalid mpdURL: / expected (%s)", mpdFileURL_.c_str());
    return false;
  }
  dashtree_.base_url_ = std::string(mpdFileURL_.c_str(), (delim - mpdFileURL_.c_str()) + 1);

  if (!dashtree_.open(mpdFileURL_.c_str()) || dashtree_.empty())
  {
    xbmc->Log(ADDON::LOG_ERROR, "Could not open / parse mpdURL (%s)", mpdFileURL_.c_str());
    return false;
  }
  xbmc->Log(ADDON::LOG_INFO, "Successfully parsed .mpd file. Download speed: %0.4f Bytes/s", dashtree_.download_speed_);

  if (dashtree_.encryptionState_ == dash::DASHTree::ENCRYTIONSTATE_ENCRYPTED)
  {
    xbmc->Log(ADDON::LOG_ERROR, "Unable to handle decryption. Unsupported!");
    return false;
  }

  uint32_t min_bandwidth(0), max_bandwidth(0);
  {
    int buf;
    xbmc->GetSetting("MINBANDWIDTH", (char*)&buf); min_bandwidth = buf;
    xbmc->GetSetting("MAXBANDWIDTH", (char*)&buf); max_bandwidth = buf;
  }

  // create SESSION::STREAM objects. One for each AdaptationSet
  unsigned int i(0);
  const dash::DASHTree::AdaptationSet *adp;

  for (std::vector<STREAM*>::iterator b(streams_.begin()), e(streams_.end()); b != e; ++b)
    SAFE_DELETE(*b);
  streams_.clear();

  while ((adp = dashtree_.GetAdaptationSet(i++)))
  {
    streams_.push_back(new STREAM(dashtree_, adp->type_));
    STREAM &stream(*streams_.back());
    stream.stream_.prepare_stream(adp, width_, height_, min_bandwidth, max_bandwidth);

    const dash::DASHTree::Representation *rep(stream.stream_.getRepresentation());

    stream.info_.m_Width = rep->width_;
    stream.info_.m_Height = rep->height_;
    stream.info_.m_Aspect = rep->aspect_;
    stream.info_.m_pID = i;
    switch (adp->type_)
    {
    case dash::DASHTree::VIDEO:
      stream.info_.m_streamType = INPUTSTREAM_INFO::TYPE_VIDEO;
      break;
    case dash::DASHTree::AUDIO:
      stream.info_.m_streamType = INPUTSTREAM_INFO::TYPE_AUDIO;
      break;
    case dash::DASHTree::TEXT:
      stream.info_.m_streamType = INPUTSTREAM_INFO::TYPE_TELETEXT;
      break;
    default:
      break;
    }

    // we currently use only the first track!
    std::string::size_type pos = rep->codecs_.find(",");
    if (pos == std::string::npos)
      pos = rep->codecs_.size();

    strncpy(stream.info_.m_codecInternalName, rep->codecs_.c_str(), pos);
    stream.info_.m_codecInternalName[pos] = 0;

    if (rep->codecs_.find("mp4a") == 0)
      strcpy(stream.info_.m_codecName, "aac");
    else if (rep->codecs_.find("ec-3") == 0 || rep->codecs_.find("ac-3") == 0)
      strcpy(stream.info_.m_codecName, "eac3");
    else if (rep->codecs_.find("avc") == 0)
      strcpy(stream.info_.m_codecName, "h264");
    else if (rep->codecs_.find("hevc") == 0)
      strcpy(stream.info_.m_codecName, "hevc");

    stream.info_.m_FpsRate = rep->fpsRate_;
    stream.info_.m_FpsScale = rep->fpsScale_;
    stream.info_.m_SampleRate = rep->samplingRate_;
    stream.info_.m_Channels = rep->channelCount_;
    stream.info_.m_Bandwidth = rep->bandwidth_;
    strcpy(stream.info_.m_language, adp->language_.c_str());
  }
  
  // Try to initialize an SingleSampleDecryptor
  if (dashtree_.encryptionState_)
  {
    AP4_DataBuffer init_data;

    if (dashtree_.adp_pssh_.second == "FILE")
    {
      std::string strkey(dashtree_.adp_pssh_.first.substr(9));
      while (size_t pos = strkey.find('-') != std::string::npos)
        strkey.erase(pos, 1);
      if (strkey.size() != 32)
      {
        xbmc->Log(ADDON::LOG_ERROR, "Key system mismatch (%s)!", dashtree_.adp_pssh_.first.c_str());
        return false;
      }

      unsigned char key_system[16];
      AP4_ParseHex(strkey.c_str(), key_system, 16);

      Session::STREAM *stream(streams_[0]);

      stream->enabled = true;
      stream->stream_.start_stream(0);
      stream->stream_.select_stream(true);

      stream->input_ = new AP4_DASHStream(&stream->stream_);
      stream->input_file_ = new AP4_File(*stream->input_, AP4_DefaultAtomFactory::Instance, true);
      AP4_Movie* movie = stream->input_file_->GetMovie();
      if (movie == NULL)
      {
        xbmc->Log(ADDON::LOG_ERROR, "No MOOV in stream!");
        stream->disable();
        return false;
      }
      AP4_Array<AP4_PsshAtom*>& pssh = movie->GetPsshAtoms();

      for (unsigned int i = 0; !init_data.GetDataSize() && i < pssh.ItemCount(); i++)
      {
        if (memcmp(pssh[i]->GetSystemId(), key_system, 16) == 0)
          init_data.AppendData(pssh[i]->GetData().GetData(), pssh[i]->GetData().GetDataSize());
      }

      if (!init_data.GetDataSize())
      {
        xbmc->Log(ADDON::LOG_ERROR, "Could not extract license from video stream (PSSH not found)");
        stream->disable();
        return false;
      }
      stream->disable();
    }
    else
    {
      init_data.SetBufferSize(1024);
      unsigned int init_data_size(1024);
      b64_decode(dashtree_.pssh_.second.data(), dashtree_.pssh_.second.size(), init_data.UseData(), init_data_size);
      init_data.SetDataSize(init_data_size);
    }
    return (single_sample_decryptor_ = CreateSingleSampleDecrypter(init_data))!=0;
  }
  return true;
}
コード例 #8
0
  void EnableStreamAtPTS(int streamid, uint64_t pts)
  {
    xbmc->Log(ADDON::LOG_DEBUG, "EnableStreamAtPTS(%d, %" PRIi64, streamid, pts);

    if (!session)
      return;

    Session::STREAM *stream(session->GetStream(streamid));

    if (!stream)
      return;

    if (~pts)
    {
      if (stream->enabled)
        return;

      stream->enabled = true;

      stream->stream_.start_stream(0);
      stream->stream_.select_stream(true);

      stream->input_ = new AP4_DASHStream(&stream->stream_);
      stream->input_file_ = new AP4_File(*stream->input_, AP4_DefaultAtomFactory::Instance, true);
      AP4_Movie* movie = stream->input_file_->GetMovie();
      if (movie == NULL)
      {
        xbmc->Log(ADDON::LOG_ERROR, "No MOOV in stream!");
        return stream->disable();
      }

      static const AP4_Track::Type TIDC[dash::DASHTree::STREAM_TYPE_COUNT] =
      { AP4_Track::TYPE_UNKNOWN, AP4_Track::TYPE_VIDEO, AP4_Track::TYPE_AUDIO, AP4_Track::TYPE_TEXT };

      AP4_Track *track = movie->GetTrack(TIDC[stream->stream_.get_type()]);
      if (!track)
      {
        xbmc->Log(ADDON::LOG_ERROR, "No suitable track found in stream");
        return stream->disable();
      }

      stream->reader_ = new FragmentedSampleReader(stream->input_, movie, track, streamid, session->GetSingleSampleDecryptor());

      // ExtraData is now available......
      stream->info_.m_ExtraData = stream->reader_->GetExtraData();
      stream->info_.m_ExtraSize = stream->reader_->GetExtraDataSize();

      // Set the session Changed to force new GetStreamInfo call from kodi -> addon
      session->CheckChange(true);

      if ((pts > 0 && !session->SeekTime(static_cast<double>(pts)*0.000001f, streamid))
      ||(pts <= 0 && !AP4_SUCCEEDED(stream->reader_->ReadSample())))
        return stream->disable();

      // Maybe we have changed information for hints after parsing the first packet...
      stream->reader_->GetVideoInformation(stream->info_.m_Width, stream->info_.m_Height);
      stream->reader_->GetAudioInformation(stream->info_.m_Channels);
      return;
    }
    return stream->disable();
  }
コード例 #9
0
/*----------------------------------------------------------------------
|   main
+---------------------------------------------------------------------*/
int
main(int argc, char** argv)
{
    if (argc < 3) {
        PrintUsageAndExit();
    }
    
    // default options
    Options.segment_duration           = 0;
    Options.pmt_pid                    = 0x100;
    Options.audio_pid                  = 0x101;
    Options.video_pid                  = 0x102;
    Options.verbose                    = false;
    Options.playlist                   = NULL;
    Options.playlist_hls_version       = 3;
    Options.input                      = NULL;
    Options.output                     = NULL;
    Options.segment_duration_threshold = DefaultSegmentDurationThreshold;
    
    // parse command line
    AP4_Result result;
    char** args = argv+1;
    while (const char* arg = *args++) {
        if (!strcmp(arg, "--segment")) {
            if (*args == NULL) {
                fprintf(stderr, "ERROR: --segment requires a number\n");
                return 1;
            }
            Options.segment_duration = strtoul(*args++, NULL, 10);
        } else if (!strcmp(arg, "--segment-duration-threshold")) {
            if (*args == NULL) {
                fprintf(stderr, "ERROR: --segment-duration-threshold requires a number\n");
                return 1;
            }
            Options.segment_duration_threshold = strtoul(*args++, NULL, 10);
        } else if (!strcmp(arg, "--verbose")) {
            Options.verbose = true;
        } else if (!strcmp(arg, "--pmt-pid")) {
            if (*args == NULL) {
                fprintf(stderr, "ERROR: --pmt-pid requires a number\n");
                return 1;
            }
            Options.pmt_pid = strtoul(*args++, NULL, 10);
        } else if (!strcmp(arg, "--audio-pid")) {
            if (*args == NULL) {
                fprintf(stderr, "ERROR: --audio-pid requires a number\n");
                return 1;
            }
            Options.audio_pid = strtoul(*args++, NULL, 10);
        } else if (!strcmp(arg, "--video-pid")) {
            if (*args == NULL) {
                fprintf(stderr, "ERROR: --video-pid requires a number\n");
                return 1;
            }
            Options.video_pid = strtoul(*args++, NULL, 10);
        } else if (!strcmp(arg, "--playlist")) {
            if (*args == NULL) {
                fprintf(stderr, "ERROR: --playlist requires a filename\n");
                return 1;
            }
            Options.playlist = *args++;
        } else if (!strcmp(arg, "--playlist-hls-version")) {
            if (*args == NULL) {
                fprintf(stderr, "ERROR: --playlist-hls-version requires a number\n");
                return 1;
            }
            Options.playlist_hls_version = strtoul(*args++, NULL, 10);
            if (Options.playlist_hls_version ==0) {
                fprintf(stderr, "ERROR: --playlist-hls-version requires number > 0\n");
                return 1;
            }
        } else if (Options.input == NULL) {
            Options.input = arg;
        } else if (Options.output == NULL) {
            Options.output = arg;
        } else {
            fprintf(stderr, "ERROR: unexpected argument\n");
            return 1;
        }
    }

    // check args
    if (Options.input == NULL) {
        fprintf(stderr, "ERROR: missing input file name\n");
        return 1;
    }
    if (Options.output == NULL) {
        fprintf(stderr, "ERROR: missing output file name\n");
        return 1;
    }
    
	// create the input stream
    AP4_ByteStream* input = NULL;
    result = AP4_FileByteStream::Create(Options.input, AP4_FileByteStream::STREAM_MODE_READ, input);
    if (AP4_FAILED(result)) {
        fprintf(stderr, "ERROR: cannot open input (%d)\n", result);
        return 1;
    }
    
	// open the file
    AP4_File* input_file = new AP4_File(*input, AP4_DefaultAtomFactory::Instance, true);   

    // get the movie
    AP4_SampleDescription* sample_description;
    AP4_Movie* movie = input_file->GetMovie();
    if (movie == NULL) {
        fprintf(stderr, "ERROR: no movie in file\n");
        return 1;
    }

    // get the audio and video tracks
    AP4_Track* audio_track = movie->GetTrack(AP4_Track::TYPE_AUDIO);
    AP4_Track* video_track = movie->GetTrack(AP4_Track::TYPE_VIDEO);
    if (audio_track == NULL && video_track == NULL) {
        fprintf(stderr, "ERROR: no suitable tracks found\n");
        delete input_file;
        input->Release();
        return 1;
    }

    // create the appropriate readers
    AP4_LinearReader* linear_reader = NULL;
    SampleReader*     audio_reader  = NULL;
    SampleReader*     video_reader  = NULL;
    if (movie->HasFragments()) {
        // create a linear reader to get the samples
        linear_reader = new AP4_LinearReader(*movie, input);
    
        if (audio_track) {
            linear_reader->EnableTrack(audio_track->GetId());
            audio_reader = new FragmentedSampleReader(*linear_reader, audio_track->GetId());
        }
        if (video_track) {
            linear_reader->EnableTrack(video_track->GetId());
            video_reader = new FragmentedSampleReader(*linear_reader, video_track->GetId());
        }
    } else {
        if (audio_track) {
            audio_reader = new TrackSampleReader(*audio_track);
        }
        if (video_track) {
            video_reader = new TrackSampleReader(*video_track);
        }
    }
    
    // create an MPEG2 TS Writer
    AP4_Mpeg2TsWriter writer(Options.pmt_pid);
    AP4_Mpeg2TsWriter::SampleStream* audio_stream = NULL;
    AP4_Mpeg2TsWriter::SampleStream* video_stream = NULL;
    
    // add the audio stream
    if (audio_track) {
        sample_description = audio_track->GetSampleDescription(0);
        if (sample_description == NULL) {
            fprintf(stderr, "ERROR: unable to parse audio sample description\n");
            goto end;
        }

        unsigned int stream_type = 0;
        unsigned int stream_id   = 0;
        if (sample_description->GetFormat() == AP4_SAMPLE_FORMAT_MP4A) {
            stream_type = AP4_MPEG2_STREAM_TYPE_ISO_IEC_13818_7;
            stream_id   = AP4_MPEG2_TS_DEFAULT_STREAM_ID_AUDIO;
        } else if (sample_description->GetFormat() == AP4_SAMPLE_FORMAT_AC_3 ||
                   sample_description->GetFormat() == AP4_SAMPLE_FORMAT_EC_3) {
            stream_type = AP4_MPEG2_STREAM_TYPE_ATSC_AC3;
            stream_id   = AP4_MPEG2_TS_STREAM_ID_PRIVATE_STREAM_1;
        } else {
            fprintf(stderr, "ERROR: audio codec not supported\n");
            return 1;
        }

        result = writer.SetAudioStream(audio_track->GetMediaTimeScale(),
                                       stream_type,
                                       stream_id,
                                       audio_stream,
                                       Options.audio_pid);
        if (AP4_FAILED(result)) {
            fprintf(stderr, "could not create audio stream (%d)\n", result);
            goto end;
        }
    }
    
    // add the video stream
    if (video_track) {
        sample_description = video_track->GetSampleDescription(0);
        if (sample_description == NULL) {
            fprintf(stderr, "ERROR: unable to parse video sample description\n");
            goto end;
        }
        
        // decide on the stream type
        unsigned int stream_type = 0;
        unsigned int stream_id   = AP4_MPEG2_TS_DEFAULT_STREAM_ID_VIDEO;
        if (sample_description->GetFormat() == AP4_SAMPLE_FORMAT_AVC1 ||
            sample_description->GetFormat() == AP4_SAMPLE_FORMAT_AVC2 ||
            sample_description->GetFormat() == AP4_SAMPLE_FORMAT_AVC3 ||
            sample_description->GetFormat() == AP4_SAMPLE_FORMAT_AVC4) {
            stream_type = AP4_MPEG2_STREAM_TYPE_AVC;
        } else if (sample_description->GetFormat() == AP4_SAMPLE_FORMAT_HEV1 ||
                   sample_description->GetFormat() == AP4_SAMPLE_FORMAT_HVC1) {
            stream_type = AP4_MPEG2_STREAM_TYPE_HEVC;
        } else {
            fprintf(stderr, "ERROR: video codec not supported\n");
            return 1;
        }
        result = writer.SetVideoStream(video_track->GetMediaTimeScale(),
                                       stream_type,
                                       stream_id,
                                       video_stream,
                                       Options.video_pid);
        if (AP4_FAILED(result)) {
            fprintf(stderr, "could not create video stream (%d)\n", result);
            goto end;
        }
    }
    
    result = WriteSamples(writer,
                          audio_track, audio_reader, audio_stream,
                          video_track, video_reader, video_stream,
                          Options.segment_duration_threshold);
    if (AP4_FAILED(result)) {
        fprintf(stderr, "ERROR: failed to write samples (%d)\n", result);
    }

end:
    delete input_file;
    input->Release();
    delete linear_reader;
    delete audio_reader;
    delete video_reader;
    
    return result == AP4_SUCCESS?0:1;
}
コード例 #10
0
/*----------------------------------------------------------------------
|   Mp4ParserInput_SetStream
+---------------------------------------------------------------------*/
BLT_METHOD
Mp4ParserInput_SetStream(BLT_InputStreamUser* _self,
                         ATX_InputStream*     stream,
                         const BLT_MediaType* stream_media_type)
{
    Mp4Parser* self = ATX_SELF_M(input, Mp4Parser, BLT_InputStreamUser);
    BLT_Result result = BLT_ERROR_INVALID_MEDIA_FORMAT;
    
    /* check media type */
    if (stream_media_type == NULL || 
        (stream_media_type->id != self->input.audio_media_type.id &&
         stream_media_type->id != self->input.video_media_type.id)) {
        return BLT_ERROR_INVALID_MEDIA_TYPE;
    }

    /* if we had a file before, release it now */
    delete self->input.mp4_file;
    self->input.mp4_file = NULL;
    self->input.slow_seek = false;
    
    /* create an adapter for the stream */
    AP4_ByteStream* stream_adapter = new ATX_InputStream_To_AP4_ByteStream_Adapter(stream);

    /* check if the source can seek quickly or not */
    {
        ATX_Properties* stream_properties = ATX_CAST(stream, ATX_Properties);
        if (stream_properties) {
            ATX_PropertyValue property_value;
            result = ATX_Properties_GetProperty(stream_properties, 
                                                ATX_INPUT_STREAM_PROPERTY_SEEK_SPEED,
                                                &property_value);
            if (ATX_SUCCEEDED(result) && 
                property_value.type == ATX_PROPERTY_VALUE_TYPE_INTEGER &&
                property_value.data.integer <= ATX_INPUT_STREAM_SEEK_SPEED_SLOW) {
                AP4_ByteStream* buffered = new AP4_BufferedInputStream(*stream_adapter);
                ATX_LOG_FINE("using no-seek mode, source is slow");
                stream_adapter->Release();
                stream_adapter = buffered;
                self->input.slow_seek = true;
            }
        }
    }

    /* parse the MP4 file */
    ATX_LOG_FINE("parsing MP4 file");
    self->input.mp4_file = new AP4_File(*stream_adapter, 
                                        AP4_DefaultAtomFactory::Instance,
                                        true); /* parse until moov only */
    stream_adapter->Release();

    // get the global file info
    AP4_Movie* movie = self->input.mp4_file->GetMovie();
    if (movie == NULL) {
        ATX_LOG_FINE("no movie in file");
        goto fail;
    }
    
    // update the stream info
    BLT_StreamInfo stream_info;
    stream_info.type     = BLT_STREAM_TYPE_MULTIPLEXED;
    stream_info.id       = 0;
    stream_info.duration = movie->GetDurationMs();
    stream_info.mask = BLT_STREAM_INFO_MASK_TYPE |
                       BLT_STREAM_INFO_MASK_ID   |
                       BLT_STREAM_INFO_MASK_DURATION;    
    BLT_Stream_SetInfo(ATX_BASE(self, BLT_BaseMediaNode).context, &stream_info);
    
    // create a linear reader if the source is slow-seeking
    if (self->input.slow_seek) {
        self->input.reader = new AP4_LinearReader(*movie);
    }
    
    // setup the tracks
    result = Mp4Parser_SetupAudioOutput(self, movie);
    if (BLT_FAILED(result)) goto fail;
    result = Mp4Parser_SetupVideoOutput(self, movie);
    if (BLT_FAILED(result)) goto fail;
    
    // check that we have at least one media track
    if (self->audio_output.track == NULL && 
        self->video_output.track == NULL) {
        ATX_LOG_FINE("no media track found");
        goto fail;
    }
    
    return BLT_SUCCESS;

fail:
    delete self->input.mp4_file;
    self->input.mp4_file = NULL;
    self->audio_output.track = NULL;
    self->video_output.track = NULL;
    
    return result;
}
コード例 #11
0
/*----------------------------------------------------------------------
|   main
+---------------------------------------------------------------------*/
int
main(int argc, char** argv)
{
    if (argc < 2) {
        PrintUsageAndExit();
    }
    
    // default options
    Options.verbose                = false;
    Options.input                  = NULL;
    Options.init_segment_name      = AP4_SPLIT_DEFAULT_INIT_SEGMENT_NAME;
    Options.media_segment_name     = AP4_SPLIT_DEFAULT_MEDIA_SEGMENT_NAME;
    Options.pattern_params         = AP4_SPLIT_DEFAULT_PATTERN_PARAMS;
    Options.start_number           = 1;
    Options.track_id               = 0;
    Options.audio_only             = false;
    Options.video_only             = false;
    Options.init_only              = false;
    Options.track_filter           = 0;
    
    // parse command line
    AP4_Result result;
    char** args = argv+1;
    while (const char* arg = *args++) {
        if (!strcmp(arg, "--verbose")) {
            Options.verbose = true;
        } else if (!strcmp(arg, "--init-segment")) {
            if (*args == NULL) {
                fprintf(stderr, "ERROR: missing argument after --init-segment option\n");
                return 1;
            }
            Options.init_segment_name = *args++;
        } else if (!strcmp(arg, "--media-segment")) {
            if (*args == NULL) {
                fprintf(stderr, "ERROR: missing argument after --media-segment option\n");
                return 1;
            }
            Options.media_segment_name = *args++;
        } else if (!strcmp(arg, "--pattern-parameters")) {
            if (*args == NULL) {
                fprintf(stderr, "ERROR: missing argument after --pattern-params option\n");
                return 1;
            }
            Options.pattern_params = *args++;
        } else if (!strcmp(arg, "--track-id")) {
            Options.track_id = strtoul(*args++, NULL, 10);
        } else if (!strcmp(arg, "--start-number")) {
            Options.start_number = strtoul(*args++, NULL, 10);
        } else if (!strcmp(arg, "--init-only")) {
            Options.init_only = true;
        } else if (!strcmp(arg, "--audio")) {
            Options.audio_only = true;
        } else if (!strcmp(arg, "--video")) {
            Options.video_only = true;
        } else if (Options.input == NULL) {
            Options.input = arg;
        } else {
            fprintf(stderr, "ERROR: unexpected argument\n");
            return 1;
        }
    }

    // check args
    if (Options.input == NULL) {
        fprintf(stderr, "ERROR: missing input file name\n");
        return 1;
    }
    if ((Options.audio_only && (Options.video_only || Options.track_id)) ||
        (Options.video_only && (Options.audio_only || Options.track_id)) ||
        (Options.track_id   && (Options.audio_only || Options.video_only))) {
        fprintf(stderr, "ERROR: --audio, --video and --track-id options are mutualy exclusive\n");
        return 1;
    }
    if (strlen(Options.pattern_params) < 1) {
        fprintf(stderr, "ERROR: --pattern-params argument is too short\n");
        return 1;
    }
    if (strlen(Options.pattern_params) > 2) {
        fprintf(stderr, "ERROR: --pattern-params argument is too long\n");
        return 1;
    }
    const char* cursor = Options.pattern_params;
    while (*cursor) {
        if (*cursor != 'I' && *cursor != 'N') {
            fprintf(stderr, "ERROR: invalid pattern parameter '%c'\n", *cursor);
            return 1;
        }
        ++cursor;
    }
    
	// create the input stream
    AP4_ByteStream* input = NULL;
    result = AP4_FileByteStream::Create(Options.input, AP4_FileByteStream::STREAM_MODE_READ, input);
    if (AP4_FAILED(result)) {
        fprintf(stderr, "ERROR: cannot open input (%d)\n", result);
        return 1;
    }
    
    // get the movie
    AP4_File* file = new AP4_File(*input, AP4_DefaultAtomFactory::Instance, true);
    AP4_Movie* movie = file->GetMovie();
    if (movie == NULL) {
        fprintf(stderr, "no movie found in file\n");
        return 1;
    }
    
    // filter tracks if required
    if (Options.audio_only) {
        AP4_Track* track = movie->GetTrack(AP4_Track::TYPE_AUDIO);
        if (track == NULL) {
            fprintf(stderr, "--audio option specified, but no audio track found\n");
            return 1;
        }
        Options.track_filter = track->GetId();
    } else if (Options.video_only) {
        AP4_Track* track = movie->GetTrack(AP4_Track::TYPE_VIDEO);
        if (track == NULL) {
            fprintf(stderr, "--video option specified, but no video track found\n");
            return 1;
        }
        Options.track_filter = track->GetId();
    } else if (Options.track_id) {
        AP4_Track* track = movie->GetTrack(Options.track_id);
        if (track == NULL) {
            fprintf(stderr, "--track-id option specified, but no such track found\n");
            return 1;
        }
        Options.track_filter = track->GetId();
    }
    
    // save the init segment
    AP4_ByteStream* output = NULL;
    result = AP4_FileByteStream::Create(Options.init_segment_name, AP4_FileByteStream::STREAM_MODE_WRITE, output);
    if (AP4_FAILED(result)) {
        fprintf(stderr, "ERROR: cannot open output file (%d)\n", result);
        return 1;
    }
    AP4_FtypAtom* ftyp = file->GetFileType(); 
    if (ftyp) {
        result = ftyp->Write(*output);
        if (AP4_FAILED(result)) {
            fprintf(stderr, "ERROR: cannot write ftyp segment (%d)\n", result);
            return 1;
        }
    }
    if (Options.track_filter) {
        AP4_MoovAtom* moov = movie->GetMoovAtom();
        
        // only keep the 'trak' atom that we need
        AP4_List<AP4_Atom>::Item* child = moov->GetChildren().FirstItem();
        while (child) {
            AP4_Atom* atom = child->GetData();
            child = child->GetNext();
            if (atom->GetType() == AP4_ATOM_TYPE_TRAK) {
                AP4_TrakAtom* trak = (AP4_TrakAtom*)atom;
                AP4_TkhdAtom* tkhd = (AP4_TkhdAtom*)trak->GetChild(AP4_ATOM_TYPE_TKHD);
                if (tkhd && tkhd->GetTrackId() != Options.track_filter) {
                    atom->Detach();
                    delete atom;
                }
            }
        }

        // only keep the 'trex' atom that we need
        AP4_ContainerAtom* mvex = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moov->GetChild(AP4_ATOM_TYPE_MVEX));
        if (mvex) {
            child = mvex->GetChildren().FirstItem();
            while (child) {
                AP4_Atom* atom = child->GetData();
                child = child->GetNext();
                if (atom->GetType() == AP4_ATOM_TYPE_TREX) {
                    AP4_TrexAtom* trex = AP4_DYNAMIC_CAST(AP4_TrexAtom, atom);
                    if (trex && trex->GetTrackId() != Options.track_filter) {
                        atom->Detach();
                        delete atom;
                    }
                }
            }
        }
    }
    result = movie->GetMoovAtom()->Write(*output);
    if (AP4_FAILED(result)) {
        fprintf(stderr, "ERROR: cannot write init segment (%d)\n", result);
        return 1;
    }
        
    AP4_Atom* atom = NULL;
    unsigned int track_id = 0;
    for (;!Options.init_only;) {
        // process the next atom
        result = AP4_DefaultAtomFactory::Instance.CreateAtomFromStream(*input, atom);
        if (AP4_FAILED(result)) break;
        
        if (atom->GetType() == AP4_ATOM_TYPE_MOOF) {
            AP4_ContainerAtom* moof = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);

            unsigned int traf_count = 0;
            AP4_ContainerAtom* traf = NULL;
            do {
                traf = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moof->GetChild(AP4_ATOM_TYPE_TRAF, traf_count));
                if (traf == NULL) break;
                AP4_TfhdAtom* tfhd = AP4_DYNAMIC_CAST(AP4_TfhdAtom, traf->GetChild(AP4_ATOM_TYPE_TFHD));
                if (tfhd == NULL) {
                    fprintf(stderr, "ERROR: invalid media format\n");
                    return 1;                    
                }
                track_id = tfhd->GetTrackId();
                traf_count++;
            } while (traf);
    
            // check if this fragment has more than one traf
            if (traf_count > 1) {
                if (Options.audio_only) {
                    fprintf(stderr, "ERROR: --audio option incompatible with multi-track fragments");
                    return 1;
                }
                if (Options.video_only) {
                    fprintf(stderr, "ERROR: --video option incompatible with multi-track fragments");
                    return 1;
                }
                track_id = 0;
            }
            
            // open a new file for this fragment
            if (output) {
                output->Release();
                output = NULL;
            }
            char segment_name[4096];
            if (Options.track_filter == 0 || Options.track_filter == track_id) {
                AP4_UI64 p[2] = {0,0};
                unsigned int params_len = strlen(Options.pattern_params);
                for (unsigned int i=0; i<params_len; i++) {
                    if (Options.pattern_params[i] == 'I') {
                        p[i] = track_id;
                    } else if (Options.pattern_params[i] == 'N') {
                        p[i] = NextFragmentIndex(track_id)+Options.start_number;
                    }
                }
                switch (params_len) {
                    case 1:
                        sprintf(segment_name, Options.media_segment_name, p[0]);
                        break;
                    case 2:
                        sprintf(segment_name, Options.media_segment_name, p[0], p[1]);
                        break;
                    default:
                        segment_name[0] = 0;
                        break;
                }
                result = AP4_FileByteStream::Create(segment_name, AP4_FileByteStream::STREAM_MODE_WRITE, output);
                if (AP4_FAILED(result)) {
                    fprintf(stderr, "ERROR: cannot open output file (%d)\n", result);
                    return 1;
                }
            }
        }
        
        // write the atom
        if (output && atom->GetType() != AP4_ATOM_TYPE_MFRA) {
            atom->Write(*output);
        }
        delete atom;
    }

    // cleanup
    delete file;
    if (input) input->Release();
    if (output) output->Release();
    
    return 0;
}
コード例 #12
0
ファイル: Aac2Mp4.cpp プロジェクト: elvin-reis/splayer
/*----------------------------------------------------------------------
|       main
+---------------------------------------------------------------------*/
int
main(int argc, char** argv)
{
    AP4_Result result;

    if (argc < 2) {
        PrintUsageAndExit();
    }

    // open the input
    AP4_ByteStream* input;
    try {
        input = new AP4_FileByteStream(argv[1], AP4_FileByteStream::STREAM_MODE_READ);
    } catch (AP4_Exception&) {
        AP4_Debug("ERROR: cannot open input (%s)\n", argv[1]);
        return 1;
    }

    // open the output
    AP4_ByteStream* output = new AP4_FileByteStream(
        argv[2],
        AP4_FileByteStream::STREAM_MODE_WRITE);

    // create a sample table
    AP4_SyntheticSampleTable* sample_table = new AP4_SyntheticSampleTable();

    // create an ADTS parser
    AP4_AdtsParser parser;
    bool           initialized = false;
    unsigned int   sample_description_index = 0;

    // read from the input, feed, and get AAC frames
    AP4_UI32     sample_rate = 0;
    AP4_Cardinal sample_count = 0;
    bool eos = false;
    for(;;) {
        // try to get a frame
        AP4_AacFrame frame;
        result = parser.FindFrame(frame);
        if (AP4_SUCCEEDED(result)) {
            AP4_Debug("AAC frame [%06d]: size = %d, %d kHz, %d ch\n",
                      sample_count,
                      frame.m_Info.m_FrameLength,
                      frame.m_Info.m_SamplingFrequency,
                      frame.m_Info.m_ChannelConfiguration);
            if (!initialized) {
                initialized = true;

                // create a sample description for our samples
                AP4_DataBuffer dsi;
                unsigned char aac_dsi[2] = {0x12, 0x10};
                dsi.SetData(aac_dsi, 2);
                AP4_MpegAudioSampleDescription* sample_description =
                    new AP4_MpegAudioSampleDescription(
                    AP4_MPEG4_AUDIO_OTI,   // object type
                    frame.m_Info.m_SamplingFrequency,
                    16,                    // sample size
                    frame.m_Info.m_ChannelConfiguration,
                    &dsi,                  // decoder info
                    6144,                  // buffer size
                    128000,                // max bitrate
                    128000);               // average bitrate
                sample_description_index = sample_table->AddSampleDescription(sample_description);
                sample_rate = frame.m_Info.m_SamplingFrequency;
            }

            AP4_MemoryByteStream* sample_data = new AP4_MemoryByteStream(frame.m_Info.m_FrameLength);
            frame.m_Source->ReadBytes(sample_data->GetBuffer(), frame.m_Info.m_FrameLength);
            printf("%02x %02x %02x %02x\n",
                   sample_data->GetBuffer()[0],
                   sample_data->GetBuffer()[1],
                   sample_data->GetBuffer()[2],
                   sample_data->GetBuffer()[3]);
            sample_table->AddSample(*sample_data, 0, frame.m_Info.m_FrameLength, sample_description_index);
            sample_data->Release();
            sample_count++;
        } else {
            if (eos) break;
        }

        // read some data and feed the parser
        AP4_UI08 input_buffer[4096];
        AP4_Size bytes_read = 0;
        AP4_Size to_read = parser.GetBytesFree();
        if (to_read) {
            if (to_read > sizeof(input_buffer)) to_read = sizeof(input_buffer);
            result = input->Read(input_buffer, to_read, &bytes_read);
            if (AP4_SUCCEEDED(result)) {
                AP4_Size to_feed = bytes_read;
                result = parser.Feed(input_buffer, &to_feed);
                if (AP4_FAILED(result)) {
                    AP4_Debug("ERROR: parser.Feed() failed (%d)\n", result);
                    return 1;
                }
            } else {
                if (result == AP4_ERROR_EOS) {
                    eos = true;
                }
            }
        }
    }

    // create an audio track
    AP4_Track* track = new AP4_Track(AP4_Track::TYPE_AUDIO,
                                     sample_table,
                                     0,     // track id
                                     sample_rate, // movie time scale
                                     sample_rate, // track time scale
                                     sample_count*1024, // track duration
                                     "eng", // language
                                     0, 0); // width, height

    // create a movie
    AP4_Movie* movie = new AP4_Movie();

    // add the track to the movie
    movie->AddTrack(track);

    // create a multimedia file
    AP4_File* file = new AP4_File(movie);

    // create a writer to write the file
    AP4_FileWriter* writer = new AP4_FileWriter(*file);

    // write the file to the output
    writer->Write(*output);

    delete writer;
    delete file;
    delete output;

    return 0;
}