repair vaapi encode_frame, fix segv on unreadable asset, update crop resource icon...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / ffmpeg.C
index 3bb9dd8018c9075810154bf112e3843e4677dcb9..70098ca189c5267b3aeea8bfdb9de8ea19f051ff 100644 (file)
@@ -374,7 +374,21 @@ int FFStream::decode_activate()
                }
                while( ret >= 0 && st != 0 && !reading ) {
                        AVCodecID codec_id = st->codecpar->codec_id;
-                       AVCodec *decoder = avcodec_find_decoder(codec_id);
+                       AVCodec *decoder = 0;
+                       if( is_video() ) {
+                               if( ffmpeg->opt_video_decoder )
+                                       decoder = avcodec_find_decoder_by_name(ffmpeg->opt_video_decoder);
+                               else
+                                       ffmpeg->video_codec_remaps.update(codec_id, decoder);
+                       }
+                       else if( is_audio() ) {
+                               if( ffmpeg->opt_audio_decoder )
+                                       decoder = avcodec_find_decoder_by_name(ffmpeg->opt_audio_decoder);
+                               else
+                                       ffmpeg->audio_codec_remaps.update(codec_id, decoder);
+                       }
+                       if( !decoder )
+                               decoder = avcodec_find_decoder(codec_id);
                        avctx = avcodec_alloc_context3(decoder);
                        if( !avctx ) {
                                eprintf(_("cant allocate codec context\n"));
@@ -455,7 +469,7 @@ int FFStream::decode(AVFrame *frame)
                        AVPacket *pkt = ret > 0 ? (AVPacket*)ipkt : 0;
                        if( pkt ) {
                                if( pkt->stream_index != st->index ) continue;
-                               if( !pkt->data | !pkt->size ) continue;
+                               if( !pkt->data || !pkt->size ) continue;
                        }
                        if( (ret=avcodec_send_packet(avctx, pkt)) < 0 ) {
                                ff_err(ret, "FFStream::decode: avcodec_send_packet failed.\nfile:%s\n",
@@ -835,7 +849,8 @@ int FFAudioStream::decode_frame(AVFrame *frame)
        frame->best_effort_timestamp = AV_NOPTS_VALUE;
        int ret = avcodec_receive_frame(avctx, frame);
        if( ret < 0 ) {
-               if( first_frame || ret == AVERROR(EAGAIN) ) return 0;
+               if( first_frame ) return 0;
+               if( ret == AVERROR(EAGAIN) ) return 0;
                if( ret == AVERROR_EOF ) { st_eof(1); return 0; }
                ff_err(ret, "FFAudioStream::decode_frame: Could not read audio frame.\nfile:%s\n",
                                ffmpeg->fmt_ctx->url);
@@ -1135,7 +1150,7 @@ int FFVideoStream::decode_frame(AVFrame *frame)
        int first_frame = seeked;  seeked = 0;
        int ret = avcodec_receive_frame(avctx, frame);
        if( ret < 0 ) {
-               if( first_frame || ret == AVERROR(EAGAIN) ) return 0;
+               if( first_frame ) return 0;
                if( ret == AVERROR(EAGAIN) ) return 0;
                if( ret == AVERROR_EOF ) { st_eof(1); return 0; }
                ff_err(ret, "FFVideoStream::decode_frame: Could not read video frame.\nfile:%s\n,",
@@ -1237,6 +1252,26 @@ int FFVideoStream::encode_frame(AVFrame *frame)
                frame->interlaced_frame = interlaced;
                frame->top_field_first = top_field_first;
        }
+       if( frame && frame->format == AV_PIX_FMT_VAAPI ) { // ugly
+               int ret = avcodec_send_frame(avctx, frame);
+               for( int retry=MAX_RETRY; !ret && --retry>=0; ) {
+                       FFPacket pkt;  av_init_packet(pkt);
+                       pkt->data = NULL;  pkt->size = 0;
+                       if( (ret=avcodec_receive_packet(avctx, pkt)) < 0 ) {
+                               if( ret == AVERROR(EAGAIN) ) ret = 0; // weird
+                               break;
+                       }
+                       ret = write_packet(pkt);
+                       pkt->stream_index = 0;
+                       av_packet_unref(pkt);
+               }
+               if( ret < 0 ) {
+                       ff_err(ret, "FFStream::encode_frame: vaapi encode failed.\nfile: %s\n",
+                               ffmpeg->fmt_ctx->url);
+                       return -1;
+               }
+               return 0;
+       }
        return FFStream::encode_frame(frame);
 }
 
@@ -1546,6 +1581,8 @@ FFMPEG::FFMPEG(FileBase *file_base)
        opt_video_filter = 0;
        opt_audio_filter = 0;
        opt_hw_dev = 0;
+       opt_video_decoder = 0;
+       opt_audio_decoder = 0;
        fflags = 0;
        char option_path[BCTEXTLEN];
        set_option_path(option_path, "%s", "ffmpeg.opts");
@@ -1991,6 +2028,45 @@ int FFMPEG::scan_options(const char *options, AVDictionary *&opts, AVStream *st)
        return ret;
 }
 
+FFCodecRemap::FFCodecRemap()
+{
+       old_codec = 0;
+       new_codec = 0;
+}
+FFCodecRemap::~FFCodecRemap()
+{
+       delete [] old_codec;
+       delete [] new_codec;
+}
+
+int FFCodecRemaps::add(const char *val)
+{
+       char old_codec[BCSTRLEN], new_codec[BCSTRLEN];
+       if( sscanf(val, " %63[a-zA-z0-9_-] = %63[a-z0-9_-]",
+               &old_codec[0], &new_codec[0]) != 2 ) return 1;
+       FFCodecRemap &remap = append();
+       remap.old_codec = cstrdup(old_codec);
+       remap.new_codec = cstrdup(new_codec);
+       return 0;
+}
+
+
+int FFCodecRemaps::update(AVCodecID &codec_id, AVCodec *&decoder)
+{
+       AVCodec *codec = avcodec_find_decoder(codec_id);
+       if( !codec ) return -1;
+       const char *name = codec->name;
+       FFCodecRemaps &map = *this;
+       int k = map.size();
+       while( --k >= 0 && strcmp(map[k].old_codec, name) );
+       if( k < 0 ) return 1;
+       const char *new_codec = map[k].new_codec;
+       codec = avcodec_find_decoder_by_name(new_codec);
+       if( !codec ) return -1;
+       decoder = codec;
+       return 0;
+}
+
 int FFMPEG::read_options(FILE *fp, const char *options, AVDictionary *&opts)
 {
        int ret = 0, no = 0;
@@ -2007,6 +2083,14 @@ int FFMPEG::read_options(FILE *fp, const char *options, AVDictionary *&opts)
                if( !ret ) {
                        if( !strcmp(key, "duration") )
                                opt_duration = strtod(val, 0);
+                       else if( !strcmp(key, "video_decoder") )
+                               opt_video_decoder = cstrdup(val);
+                       else if( !strcmp(key, "audio_decoder") )
+                               opt_audio_decoder = cstrdup(val);
+                       else if( !strcmp(key, "remap_video_decoder") )
+                               video_codec_remaps.add(val);
+                       else if( !strcmp(key, "remap_audio_decoder") )
+                               audio_codec_remaps.add(val);
                        else if( !strcmp(key, "video_filter") )
                                opt_video_filter = cstrdup(val);
                        else if( !strcmp(key, "audio_filter") )
@@ -2487,7 +2571,7 @@ int FFMPEG::open_encoder(const char *type, const char *spec)
                        vid->height = asset->height;
                        vid->frame_rate = asset->frame_rate;
 
-                       AVPixelFormat pix_fmt = AV_PIX_FMT_NONE;
+                       AVPixelFormat pix_fmt = av_get_pix_fmt(asset->ff_pixel_format);
                        if( opt_hw_dev != 0 ) {
                                AVHWDeviceType hw_type = vid->encode_hw_activate(opt_hw_dev);
                                switch( hw_type ) {
@@ -2495,9 +2579,7 @@ int FFMPEG::open_encoder(const char *type, const char *spec)
                                        pix_fmt = AV_PIX_FMT_VAAPI;
                                        break;
                                case AV_HWDEVICE_TYPE_NONE:
-                               default:
-                                       pix_fmt = av_get_pix_fmt(asset->ff_pixel_format);
-                                       break;
+                               default: break;
                                }
                        }
                        if( pix_fmt == AV_PIX_FMT_NONE )