diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp
index dd36bed08..245b01086 100644
--- a/src/FFmpegWriter.cpp
+++ b/src/FFmpegWriter.cpp
@@ -222,10 +222,10 @@ void FFmpegWriter::SetVideoOptions(bool has_video, std::string codec, Fraction f
hw_en_on = 0;
hw_en_supported = 0;
}
- #else // is FFmpeg 3 but not linux
+#else // unknown OS
new_codec = avcodec_find_encoder_by_name(codec.c_str());
- #endif //__linux__
-#else // not ffmpeg 3
+#endif //__linux__/_WIN32/__APPLE__
+#else // HAVE_HW_ACCEL
new_codec = avcodec_find_encoder_by_name(codec.c_str());
#endif // HAVE_HW_ACCEL
if (new_codec == NULL)
@@ -410,57 +410,54 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
// encode quality and special settings like lossless
// This might be better in an extra methods as more options
// and way to set quality are possible
- #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101)
- #if HAVE_HW_ACCEL
- if (hw_en_on) {
- av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0); // 0-63
- } else
- #endif // HAVE_HW_ACCEL
- {
+ #if HAVE_HW_ACCEL
+ if (hw_en_on) {
+ av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0); // 0-63
+ } else
+ #endif // HAVE_HW_ACCEL
+ {
switch (c->codec_id) {
- #if (LIBAVCODEC_VERSION_MAJOR >= 58)
- case AV_CODEC_ID_AV1 :
- c->bit_rate = 0;
- av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0); // 0-63
- break;
- #endif
- case AV_CODEC_ID_VP8 :
- c->bit_rate = 10000000;
- av_opt_set_int(c->priv_data, "qp", std::max(std::min(std::stoi(value), 63), 4), 0); // 4-63
- break;
- case AV_CODEC_ID_VP9 :
- c->bit_rate = 0; // Must be zero!
- av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value), 63), 0); // 0-63
- if (std::stoi(value) == 0) {
- av_opt_set(c->priv_data, "preset", "veryslow", 0);
- av_opt_set_int(c->priv_data, "lossless", 1, 0);
- }
- break;
- case AV_CODEC_ID_H264 :
- av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value), 51), 0); // 0-51
- if (std::stoi(value) == 0) {
- av_opt_set(c->priv_data, "preset", "veryslow", 0);
- }
- break;
- case AV_CODEC_ID_HEVC :
- av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value), 51), 0); // 0-51
- if (std::stoi(value) == 0) {
- av_opt_set(c->priv_data, "preset", "veryslow", 0);
- av_opt_set_int(c->priv_data, "lossless", 1, 0);
- }
- break;
- default:
- // For all other codecs assume a range of 0-63
- av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value), 63), 0); // 0-63
- c->bit_rate = 0;
+ #if (LIBAVCODEC_VERSION_MAJOR >= 58)
+ case AV_CODEC_ID_AV1 :
+ c->bit_rate = 0;
+ av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0); // 0-63
+ break;
+ #endif
+ case AV_CODEC_ID_VP8 :
+ c->bit_rate = 10000000;
+ av_opt_set_int(c->priv_data, "qp", std::max(std::min(std::stoi(value), 63), 4), 0); // 4-63
+ break;
+ case AV_CODEC_ID_VP9 :
+ c->bit_rate = 0; // Must be zero!
+ av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value), 63), 0); // 0-63
+ if (std::stoi(value) == 0) {
+ av_opt_set(c->priv_data, "preset", "veryslow", 0);
+ av_opt_set_int(c->priv_data, "lossless", 1, 0);
+ }
+ break;
+ case AV_CODEC_ID_H264 :
+ av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value), 51), 0); // 0-51
+ if (std::stoi(value) == 0) {
+ av_opt_set(c->priv_data, "preset", "veryslow", 0);
+ }
+ break;
+ case AV_CODEC_ID_HEVC :
+ av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value), 51), 0); // 0-51
+ if (std::stoi(value) == 0) {
+ av_opt_set(c->priv_data, "preset", "veryslow", 0);
+ av_opt_set_int(c->priv_data, "lossless", 1, 0);
+ }
+ break;
+ default:
+ // For all other codecs assume a range of 0-63
+ av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value), 63), 0); // 0-63
+ c->bit_rate = 0;
}
}
- #endif
} else if (name == "crf") {
// encode quality and special settings like lossless
// This might be better in an extra methods as more options
// and way to set quality are possible
-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101)
#if HAVE_HW_ACCEL
if (hw_en_on) {
double mbs = 15000000.0;
@@ -478,51 +475,50 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
{
switch (c->codec_id) {
#if (LIBAVCODEC_VERSION_MAJOR >= 58)
- case AV_CODEC_ID_AV1 :
- c->bit_rate = 0;
- av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0);
- break;
+ case AV_CODEC_ID_AV1 :
+ c->bit_rate = 0;
+ av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0);
+ break;
#endif
- case AV_CODEC_ID_VP8 :
- c->bit_rate = 10000000;
- av_opt_set_int(c->priv_data, "crf", std::max(std::min(std::stoi(value), 63), 4), 0); // 4-63
- break;
- case AV_CODEC_ID_VP9 :
- c->bit_rate = 0; // Must be zero!
- av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value), 63), 0); // 0-63
- if (std::stoi(value) == 0) {
- av_opt_set(c->priv_data, "preset", "veryslow", 0);
- av_opt_set_int(c->priv_data, "lossless", 1, 0);
- }
- break;
- case AV_CODEC_ID_H264 :
- av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value), 51), 0); // 0-51
- if (std::stoi(value) == 0) {
- av_opt_set(c->priv_data, "preset", "veryslow", 0);
- }
- break;
- case AV_CODEC_ID_HEVC :
- av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value), 51), 0); // 0-51
- if (std::stoi(value) == 0) {
- av_opt_set(c->priv_data, "preset", "veryslow", 0);
- av_opt_set_int(c->priv_data, "lossless", 1, 0);
- }
- break;
- default:
- // If this codec doesn't support crf calculate a bitrate
- // TODO: find better formula
- double mbs = 15000000.0;
- if (info.video_bit_rate > 0) {
- if (info.video_bit_rate > 42) {
- mbs = 380000.0;
- } else {
- mbs *= std::pow(0.912, info.video_bit_rate);
- }
+ case AV_CODEC_ID_VP8 :
+ c->bit_rate = 10000000;
+ av_opt_set_int(c->priv_data, "crf", std::max(std::min(std::stoi(value), 63), 4), 0); // 4-63
+ break;
+ case AV_CODEC_ID_VP9 :
+ c->bit_rate = 0; // Must be zero!
+ av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value), 63), 0); // 0-63
+ if (std::stoi(value) == 0) {
+ av_opt_set(c->priv_data, "preset", "veryslow", 0);
+ av_opt_set_int(c->priv_data, "lossless", 1, 0);
+ }
+ break;
+ case AV_CODEC_ID_H264 :
+ av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value), 51), 0); // 0-51
+ if (std::stoi(value) == 0) {
+ av_opt_set(c->priv_data, "preset", "veryslow", 0);
+ }
+ break;
+ case AV_CODEC_ID_HEVC :
+ av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value), 51), 0); // 0-51
+ if (std::stoi(value) == 0) {
+ av_opt_set(c->priv_data, "preset", "veryslow", 0);
+ av_opt_set_int(c->priv_data, "lossless", 1, 0);
+ }
+ break;
+ default:
+ // If this codec doesn't support crf calculate a bitrate
+ // TODO: find better formula
+ double mbs = 15000000.0;
+ if (info.video_bit_rate > 0) {
+ if (info.video_bit_rate > 42) {
+ mbs = 380000.0;
+ } else {
+ mbs *= std::pow(0.912, info.video_bit_rate);
}
- c->bit_rate = (int) (mbs);
+ }
+ c->bit_rate = (int) (mbs);
}
}
-#endif
} else {
// Set AVOption
AV_OPTION_SET(st, c->priv_data, name.c_str(), value.c_str(), c);
@@ -635,15 +631,8 @@ void FFmpegWriter::WriteFrame(std::shared_ptr frame) {
// Write the frames once it reaches the correct cache size
if ((int)spooled_video_frames.size() == cache_size || (int)spooled_audio_frames.size() == cache_size) {
- // Is writer currently writing?
- if (!is_writing)
- // Write frames to video file
- write_queued_frames();
-
- else {
- // Write frames to video file
- write_queued_frames();
- }
+ // Write frames to video file
+ write_queued_frames();
}
// Keep track of the last frame added
@@ -801,6 +790,7 @@ void FFmpegWriter::flush_encoders() {
if (info.has_audio && audio_codec && AV_GET_CODEC_TYPE(audio_st) == AVMEDIA_TYPE_AUDIO && AV_GET_CODEC_ATTRIBUTES(audio_st, audio_codec)->frame_size <= 1)
return;
#if (LIBAVFORMAT_VERSION_MAJOR < 58)
+ // FFmpeg < 4.0
if (info.has_video && video_codec && AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && (oc->oformat->flags & AVFMT_RAWPICTURE) && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO)
return;
#endif
@@ -820,9 +810,6 @@ void FFmpegWriter::flush_encoders() {
pkt.data = NULL;
pkt.size = 0;
- // Pointer for video buffer (if using old FFmpeg version)
- uint8_t *video_outbuf = NULL;
-
/* encode the image */
int got_packet = 0;
int error_code = 0;
@@ -853,28 +840,9 @@ void FFmpegWriter::flush_encoders() {
}
#else // IS_FFMPEG_3_2
-#if LIBAVFORMAT_VERSION_MAJOR >= 54
// Encode video packet (older than FFmpeg 3.2)
error_code = avcodec_encode_video2(video_codec, &pkt, NULL, &got_packet);
-#else
- // Encode video packet (even older version of FFmpeg)
- int video_outbuf_size = 0;
-
- /* encode the image */
- int out_size = avcodec_encode_video(video_codec, NULL, video_outbuf_size, NULL);
-
- /* if zero size, it means the image was buffered */
- if (out_size > 0) {
- if(video_codec->coded_frame->key_frame)
- pkt.flags |= AV_PKT_FLAG_KEY;
- pkt.data= video_outbuf;
- pkt.size= out_size;
-
- // got data back (so encode this frame)
- got_packet = 1;
- }
-#endif // LIBAVFORMAT_VERSION_MAJOR >= 54
#endif // IS_FFMPEG_3_2
if (error_code < 0) {
@@ -903,9 +871,6 @@ void FFmpegWriter::flush_encoders() {
ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::flush_encoders ERROR [" + (std::string)av_err2str(error_code) + "]", "error_code", error_code);
}
- // Deallocate memory (if needed)
- if (video_outbuf)
- av_freep(&video_outbuf);
}
// FLUSH AUDIO ENCODER
@@ -913,12 +878,8 @@ void FFmpegWriter::flush_encoders() {
for (;;) {
// Increment PTS (in samples and scaled to the codec's timebase)
-#if LIBAVFORMAT_VERSION_MAJOR >= 54
// for some reason, it requires me to multiply channels X 2
write_audio_count += av_rescale_q(audio_input_position / (audio_codec->channels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)), (AVRational){1, info.sample_rate}, audio_codec->time_base);
-#else
- write_audio_count += av_rescale_q(audio_input_position / audio_codec->channels, (AVRational){1, info.sample_rate}, audio_codec->time_base);
-#endif
AVPacket pkt;
av_init_packet(&pkt);
@@ -1073,11 +1034,7 @@ AVStream *FFmpegWriter::add_audio_stream() {
AV_FORMAT_NEW_STREAM(oc, audio_codec, codec, st)
c->codec_id = codec->id;
-#if LIBAVFORMAT_VERSION_MAJOR >= 53
c->codec_type = AVMEDIA_TYPE_AUDIO;
-#else
- c->codec_type = CODEC_TYPE_AUDIO;
-#endif
// Set the sample parameters
c->bit_rate = info.audio_bit_rate;
@@ -1131,6 +1088,7 @@ AVStream *FFmpegWriter::add_audio_stream() {
// some formats want stream headers to be separate
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
#if (LIBAVCODEC_VERSION_MAJOR >= 57)
+ // FFmpeg 3.0+
c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
#else
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
@@ -1156,11 +1114,7 @@ AVStream *FFmpegWriter::add_video_stream() {
AV_FORMAT_NEW_STREAM(oc, video_codec, codec, st)
c->codec_id = codec->id;
-#if LIBAVFORMAT_VERSION_MAJOR >= 53
c->codec_type = AVMEDIA_TYPE_VIDEO;
-#else
- c->codec_type = CODEC_TYPE_VIDEO;
-#endif
/* Init video encoder options */
if (info.video_bit_rate >= 1000) {
@@ -1174,13 +1128,12 @@ AVStream *FFmpegWriter::add_video_stream() {
} else {
// Check if codec supports crf
switch (c->codec_id) {
-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101)
#if (LIBAVCODEC_VERSION_MAJOR >= 58)
+ // FFmpeg 4.0+
case AV_CODEC_ID_AV1 :
#endif
case AV_CODEC_ID_VP9 :
case AV_CODEC_ID_HEVC :
-#endif
case AV_CODEC_ID_VP8 :
case AV_CODEC_ID_H264 :
if (info.video_bit_rate < 40) {
@@ -1217,7 +1170,7 @@ AVStream *FFmpegWriter::add_video_stream() {
identically 1. */
c->time_base.num = info.video_timebase.num;
c->time_base.den = info.video_timebase.den;
-// AVCodecContext->framerate was added in FFmpeg 2.2
+// AVCodecContext->framerate was added in FFmpeg 2.6
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 26, 0)
c->framerate = av_inv_q(c->time_base);
#endif
@@ -1238,6 +1191,7 @@ AVStream *FFmpegWriter::add_video_stream() {
// some formats want stream headers to be separate
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
#if (LIBAVCODEC_VERSION_MAJOR >= 57)
+ // FFmpeg 3.0+
c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
#else
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
@@ -1259,6 +1213,7 @@ AVStream *FFmpegWriter::add_video_stream() {
c->pix_fmt = PIX_FMT_RGB24;
#if (LIBAVFORMAT_VERSION_MAJOR < 58)
+ // FFmpeg < 4.0
if (strcmp(fmt->name, "gif") != 0)
// If not GIF format, skip the encoding process
// Set raw picture flag (so we don't encode this video)
@@ -1272,6 +1227,7 @@ AVStream *FFmpegWriter::add_video_stream() {
AV_COPY_PARAMS_FROM_CONTEXT(st, c);
#if (LIBAVFORMAT_VERSION_MAJOR < 58)
+ // FFmpeg < 4.0
ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::add_video_stream (" + (std::string)fmt->name + " : " + (std::string)av_get_pix_fmt_name(c->pix_fmt) + ")", "c->codec_id", c->codec_id, "c->bit_rate", c->bit_rate, "c->pix_fmt", c->pix_fmt, "oc->oformat->flags", oc->oformat->flags, "AVFMT_RAWPICTURE", AVFMT_RAWPICTURE);
#else
ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::add_video_stream (" + (std::string)fmt->name + " : " + (std::string)av_get_pix_fmt_name(c->pix_fmt) + ")", "c->codec_id", c->codec_id, "c->bit_rate", c->bit_rate, "c->pix_fmt", c->pix_fmt, "oc->oformat->flags", oc->oformat->flags);
@@ -1373,9 +1329,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) {
snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128);
// Maybe 127 is better because the first card would be 1?!
adapter_ptr = adapter;
-#elif defined(_WIN32)
- adapter_ptr = NULL;
-#elif defined(__APPLE__)
+#elif defined(_WIN32) || defined(__APPLE__)
adapter_ptr = NULL;
#endif
}
@@ -1385,9 +1339,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) {
// Check if it is there and writable
#if defined(__linux__)
if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == 0 ) {
-#elif defined(_WIN32)
- if( adapter_ptr != NULL ) {
-#elif defined(__APPLE__)
+#elif defined(_WIN32) || defined(__APPLE__)
if( adapter_ptr != NULL ) {
#endif
ZmqLogger::Instance()->AppendDebugMethod("Encode Device present using device", "adapter", adapter_num);
@@ -1948,6 +1900,7 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) {
// write video frame
bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *frame_final) {
#if (LIBAVFORMAT_VERSION_MAJOR >= 58)
+ // FFmpeg 4.0+
ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet", "frame->number", frame->number, "oc->oformat->flags", oc->oformat->flags);
#else
ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet", "frame->number", frame->number, "oc->oformat->flags & AVFMT_RAWPICTURE", oc->oformat->flags & AVFMT_RAWPICTURE);
@@ -1977,7 +1930,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra
AV_FREE_PACKET(&pkt);
} else
-#endif
+#endif // LIBAVFORMAT_VERSION_MAJOR >= 58
{
AVPacket pkt;
@@ -1986,9 +1939,6 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra
pkt.size = 0;
pkt.pts = pkt.dts = AV_NOPTS_VALUE;
- // Pointer for video buffer (if using old FFmpeg version)
- uint8_t *video_outbuf = NULL;
-
// Increment PTS (in frames and scaled to the codec's timebase)
write_video_count += av_rescale_q(1, (AVRational) {info.fps.den, info.fps.num}, video_codec->time_base);
@@ -2049,7 +1999,6 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra
}
}
#else
-#if LIBAVFORMAT_VERSION_MAJOR >= 54
// Write video packet (older than FFmpeg 3.2)
error_code = avcodec_encode_video2(video_codec, &pkt, frame_final, &got_packet_ptr);
if (error_code != 0) {
@@ -2058,25 +2007,6 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra
if (got_packet_ptr == 0) {
ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet (Frame gotpacket error)");
}
-#else
- // Write video packet (even older versions of FFmpeg)
- int video_outbuf_size = 200000;
- video_outbuf = (uint8_t*) av_malloc(200000);
-
- /* encode the image */
- int out_size = avcodec_encode_video(video_codec, video_outbuf, video_outbuf_size, frame_final);
-
- /* if zero size, it means the image was buffered */
- if (out_size > 0) {
- if(video_codec->coded_frame->key_frame)
- pkt.flags |= AV_PKT_FLAG_KEY;
- pkt.data= video_outbuf;
- pkt.size= out_size;
-
- // got data back (so encode this frame)
- got_packet_ptr = 1;
- }
-#endif // LIBAVFORMAT_VERSION_MAJOR >= 54
#endif // IS_FFMPEG_3_2
/* if zero size, it means the image was buffered */
@@ -2103,10 +2033,6 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra
}
}
- // Deallocate memory (if needed)
- if (video_outbuf)
- delete[] video_outbuf;
-
// Deallocate packet
AV_FREE_PACKET(&pkt);
#if HAVE_HW_ACCEL