virtual bool GetVideoInformation(unsigned int &width, unsigned int &height) override { if (pictureId == pictureIdPrev) return false; pictureIdPrev = pictureId; if (AP4_AvcSampleDescription *avc = AP4_DYNAMIC_CAST(AP4_AvcSampleDescription, sample_description)) { AP4_Array<AP4_DataBuffer>& buffer = avc->GetPictureParameters(); AP4_AvcPictureParameterSet pps; for (unsigned int i(0); i < buffer.ItemCount(); ++i) { if (AP4_SUCCEEDED(AP4_AvcFrameParser::ParsePPS(buffer[i].GetData(), buffer[i].GetDataSize(), pps)) && pps.pic_parameter_set_id == pictureId) { buffer = avc->GetSequenceParameters(); AP4_AvcSequenceParameterSet sps; for (unsigned int i(0); i < buffer.ItemCount(); ++i) { if (AP4_SUCCEEDED(AP4_AvcFrameParser::ParseSPS(buffer[i].GetData(), buffer[i].GetDataSize(), sps)) && sps.seq_parameter_set_id == pps.seq_parameter_set_id) { sps.GetInfo(width, height); return true; } } break; } } } return false; };
int8_t Mp4Writer::WriteFile(int frameRate) { // frameRate should be in frames/second // adjust the sample CTS/DTS offsets based on the sample orders if (m_sample_orders.ItemCount() > 1) { unsigned int start = 0; for (unsigned int i=1; i<=m_sample_orders.ItemCount(); i++) { if (i == m_sample_orders.ItemCount() || m_sample_orders[i].m_DisplayOrder == 0) { // we got to the end of the GOP, sort it by display order mp_sample_storage->SortSamples(&m_sample_orders[start], i-start); start = i; } } } unsigned int max_delta = 0; for (unsigned int i=0; i<m_sample_orders.ItemCount(); i++) { if (m_sample_orders[i].m_DecodeOrder > i) { unsigned int delta =m_sample_orders[i].m_DecodeOrder-i; if (delta > max_delta) { max_delta = delta; } } } for (unsigned int i=0; i<m_sample_orders.ItemCount(); i++) { mp_sample_table->UseSample(m_sample_orders[i].m_DecodeOrder).SetCts(1000ULL*(AP4_UI64)(i+max_delta)); } // check the video parameters AP4_AvcSequenceParameterSet* sps = NULL; for (unsigned int i=0; i<=AP4_AVC_SPS_MAX_ID; i++) { if (m_parser.GetSequenceParameterSets()[i]) { sps = m_parser.GetSequenceParameterSets()[i]; break; } } if (sps == NULL) { m_errorMsg = "ERROR: no sequence parameter set found in video"; return -1; } unsigned int video_width = 0; unsigned int video_height = 0; sps->GetInfo(video_width, video_height); // collect the SPS and PPS into arrays AP4_Array<AP4_DataBuffer> sps_array; for (unsigned int i=0; i<=AP4_AVC_SPS_MAX_ID; i++) { if (m_parser.GetSequenceParameterSets()[i]) { sps_array.Append(m_parser.GetSequenceParameterSets()[i]->raw_bytes); } } AP4_Array<AP4_DataBuffer> pps_array; for (unsigned int i=0; i<=AP4_AVC_PPS_MAX_ID; i++) { if (m_parser.GetPictureParameterSets()[i]) { pps_array.Append(m_parser.GetPictureParameterSets()[i]->raw_bytes); } } // setup the video the sample descripton AP4_AvcSampleDescription* sample_description = new AP4_AvcSampleDescription(AP4_SAMPLE_FORMAT_AVC1, video_width, video_height, 24, "h264", sps->profile_idc, sps->level_idc, sps->constraint_set0_flag<<7 | sps->constraint_set1_flag<<6 | sps->constraint_set2_flag<<5 | sps->constraint_set3_flag<<4, 4, sps_array, pps_array); mp_sample_table->AddSampleDescription(sample_description); // TODO: set frame rate here m_frameRate = frameRate * 1000; AP4_UI32 movie_timescale = 1000; AP4_UI32 media_timescale = m_frameRate; AP4_UI64 video_track_duration = AP4_ConvertTime(1000*mp_sample_table->GetSampleCount(), media_timescale, movie_timescale); AP4_UI64 video_media_duration = 1000*mp_sample_table->GetSampleCount(); // create a video track AP4_Track* track = new AP4_Track(AP4_Track::TYPE_VIDEO, mp_sample_table, 0, // auto-select track id movie_timescale, // movie time scale video_track_duration, // track duration m_frameRate, // media time scale video_media_duration, // media duration "und", // language video_width<<16, // width video_height<<16 // height ); // update the brands list m_brands.Append(AP4_FILE_BRAND_AVC1); mp_movie->AddTrack(track); // open the output AP4_Result result; AP4_ByteStream* output = NULL; result = AP4_FileByteStream::Create(m_outputFilename.c_str(), AP4_FileByteStream::STREAM_MODE_WRITE, output); if (AP4_FAILED(result)) { m_errorMsg = "ERROR: cannot open output file"; return -1; } // create a multimedia file AP4_File file(mp_movie); // set the file type file.SetFileType(AP4_FILE_BRAND_MP42, 1, &m_brands[0], m_brands.ItemCount()); // write the file to the output AP4_FileWriter::Write(file, *output); // cleanup output->Release(); }