@@ -55,16 +55,24 @@ FFmpegWriter::FFmpegWriter(string path) :
5555// Open the writer
5656void FFmpegWriter::Open ()
5757{
58- // Open the writer
59- is_open = true ;
60-
61- // Prepare streams (if needed)
62- if (!prepare_streams)
63- PrepareStreams ();
64-
65- // Write header (if needed)
66- if (!write_header)
67- WriteHeader ();
58+ if (!is_open) {
59+ // Open the writer
60+ is_open = true ;
61+
62+ // Prepare streams (if needed)
63+ if (!prepare_streams)
64+ PrepareStreams ();
65+
66+ // Now that all the parameters are set, we can open the audio and video codecs and allocate the necessary encode buffers
67+ if (info.has_video && video_st)
68+ open_video (oc, video_st);
69+ if (info.has_audio && audio_st)
70+ open_audio (oc, audio_st);
71+
72+ // Write header (if needed)
73+ if (!write_header)
74+ WriteHeader ();
75+ }
6876}
6977
7078// auto detect format (from path)
@@ -148,8 +156,8 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i
148156 }
149157 if (bit_rate >= 1000 ) // bit_rate is the bitrate in b/s
150158 info.video_bit_rate = bit_rate;
151- else
152- info.video_bit_rate = 0 ;
159+ if ((bit_rate >= 0 ) && (bit_rate < 64 ) ) // bit_rate is the bitrate in crf
160+ info.video_bit_rate = bit_rate ;
153161
154162 info.interlaced_frame = interlaced;
155163 info.top_field_first = top_field_first;
@@ -293,29 +301,50 @@ void FFmpegWriter::SetOption(StreamType stream, string name, string value)
293301 // and way to set quality are possible
294302 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101)
295303 switch (c->codec_id ) {
296- case AV_CODEC_ID_VP8 :
304+ #if (LIBAVCODEC_VERSION_MAJOR >= 58)
305+ case AV_CODEC_ID_AV1 :
306+ c->bit_rate = 0 ;
297307 av_opt_set_int (c->priv_data , " crf" , min (stoi (value),63 ), 0 );
298308 break ;
309+ #endif
310+ case AV_CODEC_ID_VP8 :
311+ c->bit_rate = 10000000 ;
312+ av_opt_set_int (c->priv_data , " crf" , max (min (stoi (value),63 ),4 ), 0 ); // 4-63
313+ break ;
299314 case AV_CODEC_ID_VP9 :
300- av_opt_set_int (c->priv_data , " crf" , min (stoi (value),63 ), 0 );
315+ c->bit_rate = 0 ; // Must be zero!
316+ av_opt_set_int (c->priv_data , " crf" , min (stoi (value),63 ), 0 ); // 0-63
301317 if (stoi (value) == 0 ) {
318+ av_opt_set (c->priv_data , " preset" , " veryslow" , 0 );
302319 av_opt_set_int (c->priv_data , " lossless" , 1 , 0 );
303320 }
304321 break ;
305322 case AV_CODEC_ID_H264 :
306- av_opt_set_int (c->priv_data , " crf" , min (stoi (value),51 ), 0 );
323+ av_opt_set_int (c->priv_data , " crf" , min (stoi (value),51 ), 0 ); // 0-51
324+ if (stoi (value) == 0 ) {
325+ av_opt_set (c->priv_data , " preset" , " veryslow" , 0 );
326+ }
307327 break ;
308328 case AV_CODEC_ID_H265 :
309- av_opt_set_int (c->priv_data , " crf" , min (stoi (value),51 ), 0 );
329+ av_opt_set_int (c->priv_data , " crf" , min (stoi (value),51 ), 0 ); // 0-51
310330 if (stoi (value) == 0 ) {
331+ av_opt_set (c->priv_data , " preset" , " veryslow" , 0 );
311332 av_opt_set_int (c->priv_data , " lossless" , 1 , 0 );
312- }
313- break ;
314- #ifdef AV_CODEC_ID_AV1
315- case AV_CODEC_ID_AV1 :
316- av_opt_set_int (c->priv_data , " crf" , min (stoi (value),63 ), 0 );
333+ }
317334 break ;
318- #endif
335+ default :
336+ // If this codec doesn't support crf calculate a bitrate
337+ // TODO: find better formula
338+ double mbs = 15000000.0 ;
339+ if (info.video_bit_rate > 0 ) {
340+ if (info.video_bit_rate > 42 ) {
341+ mbs = 380.0 ;
342+ }
343+ else {
344+ mbs *= pow (0.912 ,info.video_bit_rate );
345+ }
346+ }
347+ c->bit_rate = (int )(mbs);
319348 }
320349 #endif
321350 }
@@ -355,12 +384,6 @@ void FFmpegWriter::PrepareStreams()
355384 // Initialize the streams (i.e. add the streams)
356385 initialize_streams ();
357386
358- // Now that all the parameters are set, we can open the audio and video codecs and allocate the necessary encode buffers
359- if (info.has_video && video_st)
360- open_video (oc, video_st);
361- if (info.has_audio && audio_st)
362- open_audio (oc, audio_st);
363-
364387 // Mark as 'prepared'
365388 prepare_streams = true ;
366389}
@@ -973,9 +996,6 @@ AVStream* FFmpegWriter::add_video_stream()
973996 if (info.video_bit_rate >= 1000 ) {
974997 c->bit_rate = info.video_bit_rate ;
975998 }
976- else {
977- c->bit_rate = 0 ;
978- }
979999
9801000 // TODO: Implement variable bitrate feature (which actually works). This implementation throws
9811001 // invalid bitrate errors and rc buffer underflow errors, etc...
0 commit comments