1 /* $Id: decavcodec.c,v 1.6 2005/03/06 04:08:54 titer Exp $
3 This file is part of the HandBrake source code.
4 Homepage: <http://handbrake.fr/>.
5 It may be used under the terms of the GNU General Public License. */
7 /* This module is Handbrake's interface to the ffmpeg decoder library
8 (libavcodec & small parts of libavformat). It contains four Handbrake
11 decavcodec connects HB to an ffmpeg audio decoder
12 decavcodecv connects HB to an ffmpeg video decoder
14 (Two different routines are needed because the ffmpeg library
15 has different decoder calling conventions for audio & video.
16 The audio decoder should have had its name changed to "decavcodeca"
17 but I got lazy.) These work objects are self-contained & follow all
18 of HB's conventions for a decoder module. They can be used like
19 any other HB decoder (deca52, decmpeg2, etc.).
21 decavcodecai "internal" (incestuous?) version of decavcodec
22 decavcodecvi "internal" (incestuous?) version of decavcodecv
24 These routine are functionally equivalent to the routines above but
25 can only be used by the ffmpeg-based stream reader in libhb/stream.c.
26 The reason they exist is because the ffmpeg library leaves some of
27 the information needed by the decoder in the AVStream (the data
28 structure used by the stream reader) and we need to retrieve it
29 to successfully decode frames. But in HB the reader and decoder
30 modules are in completely separate threads and nothing goes between
31 them but hb_buffers containing frames to be decoded. I.e., there's
32 no easy way for the ffmpeg stream reader to pass a pointer to its
33 AVStream over to the ffmpeg video or audio decoder. So the *i work
34 objects use a private back door to the stream reader to get access
35 to the AVStream (routines hb_ffmpeg_avstream and hb_ffmpeg_context)
36 and the codec_param passed to these work objects is the key to this
37 back door (it's basically an index that allows the correct AVStream
40 The normal & *i objects share a lot of code (the basic frame decoding
41 and bitstream info code is factored out into subroutines that can be
42 called by either) but the top level routines of the *i objects
43 (decavcodecviWork, decavcodecviInfo, etc.) are different because:
44 1) they *have* to use the AVCodecContext that's contained in the
45 reader's AVStream rather than just allocating & using their own,
46 2) the Info routines have access to stuff kept in the AVStream in addition
47 to stuff kept in the AVCodecContext. This shouldn't be necessary but
48 crucial information like video frame rate that should be in the
49 AVCodecContext is either missing or wrong in the version of ffmpeg
50 we're currently using.
52 A consequence of the above is that the non-i work objects *can't* use
53 information from the AVStream because there isn't one - they get their
54 data from either the dvd reader or the mpeg reader, not the ffmpeg stream
55 reader. That means that they have to make up for deficiencies in the
56 AVCodecContext info by using stuff kept in the HB "title" struct. It
57 also means that ffmpeg codecs that randomly scatter state needed by
58 the decoder across both the AVCodecContext & the AVStream (e.g., the
59 VC1 decoder) can't easily be used by the HB mpeg stream reader.
64 #include "libavcodec/avcodec.h"
65 #include "libavformat/avformat.h"
67 static int decavcodecInit( hb_work_object_t *, hb_job_t * );
68 static int decavcodecWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
69 static void decavcodecClose( hb_work_object_t * );
70 static int decavcodecInfo( hb_work_object_t *, hb_work_info_t * );
71 static int decavcodecBSInfo( hb_work_object_t *, const hb_buffer_t *, hb_work_info_t * );
73 hb_work_object_t hb_decavcodec =
76 "MPGA decoder (libavcodec)",
84 struct hb_work_private_s
87 AVCodecContext *context;
88 AVCodecParserContext *parser;
90 double pts_next; // next pts we expect to generate
91 int64_t pts; // (video) pts passing from parser to decoder
92 int64_t chap_time; // time of next chap mark (if new_chap != 0)
94 int ignore_pts; // workaround M$ bugs
97 double duration; // frame duration (for video)
102 /***********************************************************************
103 * hb_work_decavcodec_init
104 ***********************************************************************
106 **********************************************************************/
107 static int decavcodecInit( hb_work_object_t * w, hb_job_t * job )
111 hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
112 w->private_data = pv;
116 int codec_id = w->codec_param;
119 codec_id = CODEC_ID_MP2;
120 codec = avcodec_find_decoder( codec_id );
121 pv->parser = av_parser_init( codec_id );
123 pv->context = avcodec_alloc_context();
124 avcodec_open( pv->context, codec );
129 /***********************************************************************
131 ***********************************************************************
133 **********************************************************************/
134 static void decavcodecClose( hb_work_object_t * w )
136 hb_work_private_t * pv = w->private_data;
139 av_parser_close(pv->parser);
141 if ( pv->context && pv->context->codec )
143 avcodec_close( pv->context );
147 hb_list_close( &pv->list );
151 /***********************************************************************
153 ***********************************************************************
155 **********************************************************************/
156 static int decavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
157 hb_buffer_t ** buf_out )
159 hb_work_private_t * pv = w->private_data;
160 hb_buffer_t * in = *buf_in, * buf, * last = NULL;
161 int pos, len, out_size, i, uncompressed_len;
162 short buffer[AVCODEC_MAX_AUDIO_FRAME_SIZE];
164 unsigned char *parser_output_buffer;
165 int parser_output_buffer_len;
169 cur = ( in->start < 0 )? pv->pts_next : in->start;
172 while( pos < in->size )
174 len = av_parser_parse( pv->parser, pv->context,
175 &parser_output_buffer, &parser_output_buffer_len,
176 in->data + pos, in->size - pos, cur, cur );
178 uncompressed_len = 0;
179 if (parser_output_buffer_len)
181 out_size = sizeof(buffer);
182 uncompressed_len = avcodec_decode_audio2( pv->context, buffer,
184 parser_output_buffer,
185 parser_output_buffer_len );
192 buf = hb_buffer_init( 2 * out_size );
194 int sample_size_in_bytes = 2; // Default to 2 bytes
195 switch (pv->context->sample_fmt)
198 sample_size_in_bytes = 2;
200 /* We should handle other formats here - but that needs additional format conversion work below */
201 /* For now we'll just report the error and try to carry on */
203 hb_log("decavcodecWork - Unknown Sample Format from avcodec_decode_audio (%d) !", pv->context->sample_fmt);
208 buf->stop = cur + 90000 * ( out_size / (sample_size_in_bytes * pv->context->channels) ) /
209 pv->context->sample_rate;
213 fl32 = (float *) buf->data;
214 for( i = 0; i < out_size / 2; i++ )
221 last = last->next = buf;
225 *buf_out = last = buf;
237 static int decavcodecInfo( hb_work_object_t *w, hb_work_info_t *info )
239 hb_work_private_t *pv = w->private_data;
241 memset( info, 0, sizeof(*info) );
243 if ( pv && pv->context )
245 AVCodecContext *context = pv->context;
246 info->bitrate = context->bit_rate;
247 info->rate = context->time_base.num;
248 info->rate_base = context->time_base.den;
249 info->profile = context->profile;
250 info->level = context->level;
256 static int decavcodecBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
257 hb_work_info_t *info )
259 hb_work_private_t *pv = w->private_data;
261 memset( info, 0, sizeof(*info) );
263 if ( pv && pv->context )
265 return decavcodecInfo( w, info );
268 // We should parse the bitstream to find its parameters but for right
269 // now we just return dummy values if there's a codec that will handle it.
270 AVCodec *codec = avcodec_find_decoder( w->codec_param? w->codec_param :
274 static char codec_name[64];
276 info->name = strncpy( codec_name, codec->name, sizeof(codec_name)-1 );
277 info->bitrate = 384000;
280 info->channel_layout = HB_INPUT_CH_LAYOUT_STEREO;
286 /* -------------------------------------------------------------
287 * General purpose video decoder using libavcodec
290 static uint8_t *copy_plane( uint8_t *dst, uint8_t* src, int dstride, int sstride,
293 if ( dstride == sstride )
295 memcpy( dst, src, dstride * h );
296 return dst + dstride * h;
298 int lbytes = dstride <= sstride? dstride : sstride;
301 memcpy( dst, src, lbytes );
308 /* Note: assumes frame format is PIX_FMT_YUV420P */
309 static hb_buffer_t *copy_frame( AVCodecContext *context, AVFrame *frame )
311 int w = context->width, h = context->height;
312 hb_buffer_t *buf = hb_buffer_init( w * h * 3 / 2 );
313 uint8_t *dst = buf->data;
315 dst = copy_plane( dst, frame->data[0], w, frame->linesize[0], h );
317 dst = copy_plane( dst, frame->data[1], w, frame->linesize[1], h );
318 dst = copy_plane( dst, frame->data[2], w, frame->linesize[2], h );
323 static int get_frame_buf( AVCodecContext *context, AVFrame *frame )
325 hb_work_private_t *pv = context->opaque;
326 frame->pts = pv->pts;
329 return avcodec_default_get_buffer( context, frame );
332 static void log_chapter( hb_work_private_t *pv, int chap_num, int64_t pts )
334 hb_chapter_t *c = hb_list_item( pv->job->title->list_chapter, chap_num - 1 );
335 hb_log( "%s: \"%s\" (%d) at frame %u time %lld", pv->context->codec->name,
336 c->title, chap_num, pv->nframes, pts );
339 static int decodeFrame( hb_work_private_t *pv, uint8_t *data, int size )
344 avcodec_decode_video( pv->context, &frame, &got_picture, data, size );
347 // ffmpeg makes it hard to attach a pts to a frame. if the MPEG ES
348 // packet had a pts we handed it to av_parser_parse (if the packet had
349 // no pts we set it to -1 but before the parse we can't distinguish between
350 // the start of a video frame with no pts & an intermediate packet of
351 // some frame which never has a pts). we hope that when parse returns
352 // the frame to us the pts we originally handed it will be in parser->pts.
353 // we put this pts into pv->pts so that when a avcodec_decode_video
354 // finally gets around to allocating an AVFrame to hold the decoded
355 // frame we can stuff that pts into the frame. if all of these relays
356 // worked at this point frame.pts should hold the frame's pts from the
357 // original data stream or -1 if it didn't have one. in the latter case
358 // we generate the next pts in sequence for it.
359 double pts = frame.pts;
364 if ( pv->duration == 0 )
366 pv->duration = 90000. * pv->context->time_base.num /
367 pv->context->time_base.den;
369 double frame_dur = pv->duration;
370 frame_dur += frame.repeat_pict * frame_dur * 0.5;
371 pv->pts_next = pts + frame_dur;
373 hb_buffer_t *buf = copy_frame( pv->context, &frame );
376 if ( pv->new_chap && buf->start >= pv->chap_time )
378 buf->new_chap = pv->new_chap;
383 log_chapter( pv, buf->new_chap, buf->start );
386 else if ( pv->job && pv->nframes == 0 )
388 log_chapter( pv, pv->job->chapter_start, buf->start );
390 hb_list_add( pv->list, buf );
396 static void decodeVideo( hb_work_private_t *pv, uint8_t *data, int size,
397 int64_t pts, int64_t dts )
400 * The following loop is a do..while because we need to handle both
401 * data & the flush at the end (signaled by size=0). At the end there's
402 * generally a frame in the parser & one or more frames in the decoder
403 * (depending on the bframes setting).
409 int len = av_parser_parse( pv->parser, pv->context, &pout, &pout_len,
410 data + pos, size - pos, pts, dts );
415 pv->pts = pv->parser->pts;
416 decodeFrame( pv, pout, pout_len );
418 } while ( pos < size );
420 /* the stuff above flushed the parser, now flush the decoder */
421 while ( size == 0 && decodeFrame( pv, NULL, 0 ) )
426 static hb_buffer_t *link_buf_list( hb_work_private_t *pv )
428 hb_buffer_t *head = hb_list_item( pv->list, 0 );
432 hb_list_rem( pv->list, head );
434 hb_buffer_t *last = head, *buf;
436 while ( ( buf = hb_list_item( pv->list, 0 ) ) != NULL )
438 hb_list_rem( pv->list, buf );
447 static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job )
450 hb_work_private_t *pv = calloc( 1, sizeof( hb_work_private_t ) );
451 w->private_data = pv;
453 pv->list = hb_list_init();
455 int codec_id = w->codec_param;
456 pv->parser = av_parser_init( codec_id );
457 pv->context = avcodec_alloc_context2( CODEC_TYPE_VIDEO );
459 /* we have to wrap ffmpeg's get_buffer to be able to set the pts (?!) */
460 pv->context->opaque = pv;
461 pv->context->get_buffer = get_frame_buf;
463 AVCodec *codec = avcodec_find_decoder( codec_id );
465 // we can't call the avstream funcs but the read_header func in the
466 // AVInputFormat may set up some state in the AVContext. In particular
467 // vc1t_read_header allocates 'extradata' to deal with header issues
468 // related to Microsoft's bizarre engineering notions. We alloc a chunk
469 // of space to make vc1 work then associate the codec with the context.
470 pv->context->extradata_size = 32;
471 pv->context->extradata = av_malloc(pv->context->extradata_size);
472 avcodec_open( pv->context, codec );
477 static int decavcodecvWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
478 hb_buffer_t ** buf_out )
480 hb_work_private_t *pv = w->private_data;
481 hb_buffer_t *in = *buf_in;
487 /* if we got an empty buffer signaling end-of-stream send it downstream */
490 decodeVideo( pv, in->data, in->size, pts, dts );
491 hb_list_add( pv->list, in );
492 *buf_out = link_buf_list( pv );
493 hb_log( "%s done: %d frames", pv->context->codec->name, pv->nframes );
500 dts = in->renderOffset;
504 pv->new_chap = in->new_chap;
505 pv->chap_time = pts >= 0? pts : pv->pts_next;
507 decodeVideo( pv, in->data, in->size, pts, dts );
508 hb_buffer_close( &in );
509 *buf_out = link_buf_list( pv );
513 static int decavcodecvInfo( hb_work_object_t *w, hb_work_info_t *info )
515 hb_work_private_t *pv = w->private_data;
517 memset( info, 0, sizeof(*info) );
519 if ( pv && pv->context )
521 AVCodecContext *context = pv->context;
522 info->bitrate = context->bit_rate;
523 info->width = context->width;
524 info->height = context->height;
526 /* ffmpeg gives the frame rate in frames per second while HB wants
527 * it in units of the 27MHz MPEG clock. */
528 info->rate = 27000000;
529 info->rate_base = (int64_t)context->time_base.num * 27000000LL /
530 context->time_base.den;
532 /* Sometimes there's no pixel aspect set in the source. In that case,
533 assume a 1:1 PAR. Otherwise, preserve the source PAR. */
534 info->pixel_aspect_width = context->sample_aspect_ratio.num ?
535 context->sample_aspect_ratio.num : 1;
536 info->pixel_aspect_height = context->sample_aspect_ratio.den ?
537 context->sample_aspect_ratio.den : 1;
539 /* ffmpeg returns the Pixel Aspect Ratio (PAR). Handbrake wants the
540 * Display Aspect Ratio so we convert by scaling by the Storage
541 * Aspect Ratio (w/h). We do the calc in floating point to get the
542 * rounding right. We round in the second decimal digit because we
543 * scale the (integer) aspect by 9 to preserve the 1st digit. */
544 info->aspect = ( (double)info->pixel_aspect_width *
545 (double)context->width /
546 (double)info->pixel_aspect_height /
547 (double)context->height + 0.05 ) * HB_ASPECT_BASE;
549 info->profile = context->profile;
550 info->level = context->level;
551 info->name = context->codec->name;
557 static int decavcodecvBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
558 hb_work_info_t *info )
563 hb_work_object_t hb_decavcodecv =
566 "Video decoder (libavcodec)",
575 // This is a special decoder for ffmpeg streams. The ffmpeg stream reader
576 // includes a parser and passes information from the parser to the decoder
577 // via a codec context kept in the AVStream of the reader's AVFormatContext.
578 // We *have* to use that codec context to decode the stream or we'll get
579 // garbage. ffmpeg_title_scan put a cookie that can be used to get to that
580 // codec context in our codec_param.
582 // this routine gets the appropriate context pointer from the ffmpeg
583 // stream reader. it can't be called until we get the first buffer because
584 // we can't guarantee that reader will be called before the our init
585 // routine and if our init is called first we'll get a pointer to the
586 // old scan stream (which has already been closed).
587 static void init_ffmpeg_context( hb_work_object_t *w )
589 hb_work_private_t *pv = w->private_data;
590 pv->context = hb_ffmpeg_context( w->codec_param );
592 // during scan the decoder gets closed & reopened which will
593 // close the codec so reopen it if it's not there
594 if ( ! pv->context->codec )
596 AVCodec *codec = avcodec_find_decoder( pv->context->codec_id );
597 avcodec_open( pv->context, codec );
599 // set up our best guess at the frame duration.
600 // the frame rate in the codec is usually bogus but it's sometimes
602 AVStream *st = hb_ffmpeg_avstream( w->codec_param );
604 // XXX because the time bases are so screwed up, we only take values
605 // in the range 8fps - 64fps.
606 if ( st->time_base.num * 64 > st->time_base.den &&
607 st->time_base.den > st->time_base.num * 8 )
611 else if ( st->codec->time_base.num * 64 > st->codec->time_base.den &&
612 st->codec->time_base.den > st->codec->time_base.num * 8 )
614 tb = st->codec->time_base;
616 else if ( st->r_frame_rate.den * 64 > st->r_frame_rate.num &&
617 st->r_frame_rate.num > st->r_frame_rate.den * 8 )
619 tb.num = st->r_frame_rate.den;
620 tb.den = st->r_frame_rate.num;
624 tb.num = 1001; /*XXX*/
625 tb.den = 30000; /*XXX*/
627 pv->duration = 90000. * tb.num / tb.den;
629 // we have to wrap ffmpeg's get_buffer to be able to set the pts (?!)
630 pv->context->opaque = pv;
631 pv->context->get_buffer = get_frame_buf;
634 static void prepare_ffmpeg_buffer( hb_buffer_t * in )
636 // ffmpeg requires an extra 8 bytes of zero at the end of the buffer and
637 // will seg fault in odd, data dependent ways if it's not there. (my guess
638 // is this is a case of a local performance optimization creating a global
639 // performance degradation since all the time wasted by extraneous data
640 // copies & memory zeroing has to be huge compared to the minor reduction
641 // in inner-loop instructions this affords - modern cpus bottleneck on
642 // memory bandwidth not instruction bandwidth).
643 if ( in->size + FF_INPUT_BUFFER_PADDING_SIZE > in->alloc )
645 // have to realloc to add the padding
646 hb_buffer_realloc( in, in->size + FF_INPUT_BUFFER_PADDING_SIZE );
648 memset( in->data + in->size, 0, FF_INPUT_BUFFER_PADDING_SIZE );
651 static int decavcodecviInit( hb_work_object_t * w, hb_job_t * job )
654 hb_work_private_t *pv = calloc( 1, sizeof( hb_work_private_t ) );
655 w->private_data = pv;
657 pv->list = hb_list_init();
662 static int decavcodecviWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
663 hb_buffer_t ** buf_out )
665 hb_work_private_t *pv = w->private_data;
668 init_ffmpeg_context( w );
670 switch ( pv->context->codec_id )
672 // These are the only formats whose timestamps we'll believe.
673 // All others are treated as CFR (i.e., we take the first timestamp
674 // then generate all the others from the frame rate). The reason for
675 // this is that the M$ encoders are so frigging buggy with garbage
676 // like packed b-frames (vfw divx mpeg4) that believing their timestamps
677 // results in discarding more than half the video frames because they'll
678 // be out of sequence (and attempting to reseqence them doesn't work
679 // because it's the timestamps that are wrong, not the decoded frame
680 // order). All hail Redmond, ancestral home of the rich & stupid.
681 case CODEC_ID_MPEG2VIDEO:
682 case CODEC_ID_RAWVIDEO:
692 hb_buffer_t *in = *buf_in;
697 /* if we got an empty buffer signaling end-of-stream send it downstream */
700 /* flush any frames left in the decoder */
701 while ( decodeFrame( pv, NULL, 0 ) )
704 hb_list_add( pv->list, in );
705 *buf_out = link_buf_list( pv );
706 hb_log( "%s done: %d frames %d drops", pv->context->codec->name,
707 pv->nframes, pv->ndrops );
713 // use the first timestamp as our 'next expected' pts
714 if ( pv->pts_next <= 0 )
716 pv->pts_next = in->start;
719 if ( ! pv->ignore_pts )
724 hb_log( "overwriting pts %lld with %lld (diff %d)",
725 pv->pts, pts, pts - pv->pts );
727 if ( pv->pts_next - pts >= pv->duration )
729 // this frame starts more than a frame time before where
730 // the nominal frame rate says it should - drop it.
731 // log the first 10 drops so we'll know what's going on.
732 if ( pv->ndrops++ < 10 )
734 hb_log( "time reversal next %.0f pts %lld (diff %g)",
735 pv->pts_next, pts, pv->pts_next - pts );
737 hb_buffer_close( &in );
746 pv->new_chap = in->new_chap;
747 pv->chap_time = pts >= 0? pts : pv->pts_next;
749 prepare_ffmpeg_buffer( in );
750 decodeFrame( pv, in->data, in->size );
751 hb_buffer_close( &in );
752 *buf_out = link_buf_list( pv );
756 static int decavcodecviInfo( hb_work_object_t *w, hb_work_info_t *info )
758 if ( decavcodecvInfo( w, info ) )
760 // There are at least three different video frame rates in ffmpeg:
761 // - time_base in the AVStream
762 // - time_base in the AVCodecContext
763 // - r_frame_rate in the AVStream
764 // There's no guidence on which if any of these to believe but the
765 // routine compute_frame_duration tries the stream first then the codec.
766 // In general the codec time base seems bogus & the stream time base is
767 // ok except for wmv's where the stream time base is also bogus but
768 // r_frame_rate is sometimes ok & sometimes a random number.
769 AVStream *st = hb_ffmpeg_avstream( w->codec_param );
771 // XXX because the time bases are so screwed up, we only take values
772 // in the range 8fps - 64fps.
773 if ( st->time_base.num * 64 > st->time_base.den &&
774 st->time_base.den > st->time_base.num * 8 )
778 else if ( st->codec->time_base.num * 64 > st->codec->time_base.den &&
779 st->codec->time_base.den > st->codec->time_base.num * 8 )
781 tb = st->codec->time_base;
783 else if ( st->r_frame_rate.den * 64 > st->r_frame_rate.num &&
784 st->r_frame_rate.num > st->r_frame_rate.den * 8 )
786 tb.num = st->r_frame_rate.den;
787 tb.den = st->r_frame_rate.num;
791 tb.num = 1001; /*XXX*/
792 tb.den = 30000; /*XXX*/
795 // ffmpeg gives the frame rate in frames per second while HB wants
796 // it in units of the 27MHz MPEG clock. */
797 info->rate = 27000000;
798 info->rate_base = (int64_t)tb.num * 27000000LL / tb.den;
804 static void decodeAudio( hb_work_private_t *pv, uint8_t *data, int size )
806 AVCodecContext *context = pv->context;
811 int16_t buffer[AVCODEC_MAX_AUDIO_FRAME_SIZE];
812 int out_size = sizeof(buffer);
813 int len = avcodec_decode_audio2( context, buffer, &out_size,
814 data + pos, size - pos );
822 hb_buffer_t *buf = hb_buffer_init( 2 * out_size );
824 double pts = pv->pts_next;
827 pts += out_size * pv->duration;
831 float *fl32 = (float *)buf->data;
833 for( i = 0; i < out_size; ++i )
837 hb_list_add( pv->list, buf );
842 static int decavcodecaiWork( hb_work_object_t *w, hb_buffer_t **buf_in,
843 hb_buffer_t **buf_out )
845 hb_work_private_t *pv = w->private_data;
848 init_ffmpeg_context( w );
849 pv->duration = 90000. /
850 (double)( pv->context->sample_rate * pv->context->channels );
852 hb_buffer_t *in = *buf_in;
854 if ( in->start >= 0 &&
855 ( pv->pts_next < 0 || ( in->start - pv->pts_next ) > 90*100 ) )
857 pv->pts_next = in->start;
859 prepare_ffmpeg_buffer( in );
860 decodeAudio( pv, in->data, in->size );
861 *buf_out = link_buf_list( pv );
866 hb_work_object_t hb_decavcodecvi =
869 "Video decoder (ffmpeg streams)",
877 hb_work_object_t hb_decavcodecai =
880 "Audio decoder (ffmpeg streams)",