/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | 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); }
/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | 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; }
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(); }
/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | 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; }