From 26e96e009bb53645ca178ce0263fa8af58d323d0 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sun, 4 Mar 2018 03:10:59 -0600 Subject: [PATCH] Added in metadata encoding capabilities (writer.info.metadata["title"] = "My Title"). Only certain tag names are accepted (see FFmpeg for more on which tags are supported by which codecs). --- include/WriterBase.h | 1 + src/FFmpegWriter.cpp | 19 ++++++++++++++ src/examples/Example.cpp | 54 ++++++++++++++++++++++++---------------- 3 files changed, 52 insertions(+), 22 deletions(-) diff --git a/include/WriterBase.h b/include/WriterBase.h index 30da006b..8f424054 100644 --- a/include/WriterBase.h +++ b/include/WriterBase.h @@ -73,6 +73,7 @@ namespace openshot ChannelLayout channel_layout; ///< The channel layout (mono, stereo, 5 point surround, etc...) int audio_stream_index; ///< The index of the audio stream Fraction audio_timebase; ///< The audio timebase determines how long each audio packet should be played + std::map metadata; ///< An optional map/dictionary of video & audio metadata }; /** diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index d15a304c..e83e4781 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -335,6 +335,13 @@ void FFmpegWriter::WriteHeader() // Write the stream header, if any // TODO: add avoptions / parameters instead of NULL + + // Add general metadata (if any) + for(std::map::iterator iter = info.metadata.begin(); iter != info.metadata.end(); ++iter) + { + av_dict_set(&oc->metadata, iter->first.c_str(), iter->second.c_str(), 0); + } + avformat_write_header(oc, NULL); // Mark as 'written' @@ -1018,6 +1025,12 @@ void FFmpegWriter::open_audio(AVFormatContext *oc, AVStream *st) audio_encoder_buffer_size = AUDIO_PACKET_ENCODING_SIZE; audio_encoder_buffer = new uint8_t[audio_encoder_buffer_size]; + // Add audio metadata (if any) + for(std::map::iterator iter = info.metadata.begin(); iter != info.metadata.end(); ++iter) + { + av_dict_set(&st->metadata, iter->first.c_str(), iter->second.c_str(), 0); + } + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::open_audio", "audio_codec->thread_count", audio_codec->thread_count, "audio_input_frame_size", audio_input_frame_size, "buffer_size", AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE, "", -1, "", -1, "", -1); } @@ -1046,6 +1059,12 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) if (avcodec_open2(video_codec, codec, NULL) < 0) throw InvalidCodec("Could not open codec", path); + // Add video metadata (if any) + for(std::map::iterator iter = info.metadata.begin(); iter != info.metadata.end(); ++iter) + { + av_dict_set(&st->metadata, iter->first.c_str(), iter->second.c_str(), 0); + } + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::open_video", "video_codec->thread_count", video_codec->thread_count, "", -1, "", -1, "", -1, "", -1, "", -1); } diff --git a/src/examples/Example.cpp b/src/examples/Example.cpp index e57445bf..411abdda 100644 --- a/src/examples/Example.cpp +++ b/src/examples/Example.cpp @@ -36,34 +36,44 @@ using namespace openshot; int main(int argc, char* argv[]) { - // Create and open reader - FFmpegReader r("/home/jonathan/sintel-120fps-crash.mp4"); - r.Open(); + FFmpegReader r9("/home/jonathan/Videos/sintel_trailer-720p.mp4"); + r9.Open(); + r9.DisplayInfo(); - // Enable debug logging - ZmqLogger::Instance()->Enable(false); - ZmqLogger::Instance()->Path("/home/jonathan/.openshot_qt/libopenshot2.log"); - CrashHandler::Instance(); + /* WRITER ---------------- */ + FFmpegWriter w9("/home/jonathan/metadata.mp4"); - // Loop a few times - for (int attempt = 1; attempt < 10; attempt++) { - cout << "** Attempt " << attempt << " **" << endl; + // Set options + w9.SetAudioOptions(true, "libmp3lame", r9.info.sample_rate, r9.info.channels, r9.info.channel_layout, 128000); + w9.SetVideoOptions(true, "libx264", r9.info.fps, 1024, 576, Fraction(1,1), false, false, 3000000); - // Read every frame in reader as fast as possible - for (int64_t frame_number = 1; frame_number < r.info.video_length; frame_number++) { - // Get frame object - std::shared_ptr f = r.GetFrame(frame_number); + w9.info.metadata["title"] = "testtest"; + w9.info.metadata["artist"] = "aaa"; + w9.info.metadata["album"] = "bbb"; + w9.info.metadata["year"] = "2015"; + w9.info.metadata["description"] = "ddd"; + w9.info.metadata["comment"] = "eee"; + w9.info.metadata["comment"] = "comment"; + w9.info.metadata["copyright"] = "copyright OpenShot!"; - // Print frame numbers - cout << frame_number << " [" << f->number << "], " << flush; - if (frame_number % 10 == 0) - cout << endl; - } + // Open writer + w9.Open(); + + for (long int frame = 1; frame <= 100; frame++) + { + //int frame_number = (rand() % 750) + 1; + int frame_number = frame; + std::shared_ptr f = r9.GetFrame(frame_number); + w9.WriteFrame(f); } - cout << "Completed successfully!" << endl; - // Close reader - r.Close(); + // Close writer & reader + w9.Close(); + + // Close timeline + r9.Close(); + + cout << "Completed successfully!" << endl; return 0; } \ No newline at end of file