2023-04-11 13:21:56 +02:00
/*
* This file is part of FFmpeg .
*
* FFmpeg is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* FFmpeg is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2023-05-17 09:36:14 +02:00
# include "libavutil/avassert.h"
2023-04-11 13:21:56 +02:00
# include "libavutil/dict.h"
# include "libavutil/error.h"
# include "libavutil/log.h"
# include "libavutil/pixdesc.h"
# include "libavutil/pixfmt.h"
2023-11-24 20:08:15 +02:00
# include "libavutil/time.h"
2023-05-17 09:36:14 +02:00
# include "libavutil/timestamp.h"
2023-04-11 13:21:56 +02:00
# include "libavcodec/avcodec.h"
# include "libavcodec/codec.h"
2023-05-17 09:36:14 +02:00
# include "libavfilter/buffersrc.h"
2023-04-11 13:21:56 +02:00
# include "ffmpeg.h"
2023-10-25 13:48:50 +02:00
# include "ffmpeg_utils.h"
2023-06-02 09:59:31 +02:00
# include "thread_queue.h"
2023-04-11 13:21:56 +02:00
2024-01-10 13:10:58 +02:00
typedef struct DecoderPriv {
Decoder dec ;
2023-05-18 05:39:39 +02:00
AVFrame * frame ;
2023-05-18 05:41:53 +02:00
AVPacket * pkt ;
2023-05-18 05:52:23 +02:00
2023-06-06 13:00:01 +02:00
enum AVPixelFormat hwaccel_pix_fmt ;
2023-05-18 05:52:23 +02:00
// pts/estimated duration of the last decoded frame
// * in decoder timebase for video,
// * in last_frame_tb (may change during decoding) for audio
int64_t last_frame_pts ;
int64_t last_frame_duration_est ;
AVRational last_frame_tb ;
int64_t last_filter_in_rescale_delta ;
int last_frame_sample_rate ;
2023-06-02 09:59:31 +02:00
2023-06-14 18:08:10 +02:00
/* previous decoded subtitles */
AVFrame * sub_prev [ 2 ] ;
AVFrame * sub_heartbeat ;
2023-06-14 16:16:50 +02:00
2023-05-18 16:56:15 +02:00
Scheduler * sch ;
unsigned sch_idx ;
2024-01-10 13:10:58 +02:00
} DecoderPriv ;
static DecoderPriv * dp_from_dec ( Decoder * d )
{
return ( DecoderPriv * ) d ;
}
2023-05-18 05:39:39 +02:00
2023-06-02 09:59:31 +02:00
// data that is local to the decoder thread and not visible outside of it
typedef struct DecThreadContext {
AVFrame * frame ;
AVPacket * pkt ;
} DecThreadContext ;
2023-05-18 05:39:39 +02:00
void dec_free ( Decoder * * pdec )
{
Decoder * dec = * pdec ;
2024-01-10 13:10:58 +02:00
DecoderPriv * dp ;
2023-05-18 05:39:39 +02:00
if ( ! dec )
return ;
2024-01-10 13:10:58 +02:00
dp = dp_from_dec ( dec ) ;
2023-05-18 05:39:39 +02:00
2024-01-10 13:10:58 +02:00
av_frame_free ( & dp - > frame ) ;
av_packet_free ( & dp - > pkt ) ;
2023-05-18 05:39:39 +02:00
2024-01-10 13:10:58 +02:00
for ( int i = 0 ; i < FF_ARRAY_ELEMS ( dp - > sub_prev ) ; i + + )
av_frame_free ( & dp - > sub_prev [ i ] ) ;
av_frame_free ( & dp - > sub_heartbeat ) ;
2023-06-14 16:16:50 +02:00
2023-05-18 05:39:39 +02:00
av_freep ( pdec ) ;
}
static int dec_alloc ( Decoder * * pdec )
{
2024-01-10 13:10:58 +02:00
DecoderPriv * dp ;
2023-05-18 05:39:39 +02:00
* pdec = NULL ;
2024-01-10 13:10:58 +02:00
dp = av_mallocz ( sizeof ( * dp ) ) ;
if ( ! dp )
2023-05-18 05:39:39 +02:00
return AVERROR ( ENOMEM ) ;
2024-01-10 13:10:58 +02:00
dp - > frame = av_frame_alloc ( ) ;
if ( ! dp - > frame )
2023-05-18 05:39:39 +02:00
goto fail ;
2024-01-10 13:10:58 +02:00
dp - > pkt = av_packet_alloc ( ) ;
if ( ! dp - > pkt )
2023-05-18 05:41:53 +02:00
goto fail ;
2024-01-10 13:10:58 +02:00
dp - > last_filter_in_rescale_delta = AV_NOPTS_VALUE ;
dp - > last_frame_pts = AV_NOPTS_VALUE ;
dp - > last_frame_tb = ( AVRational ) { 1 , 1 } ;
dp - > hwaccel_pix_fmt = AV_PIX_FMT_NONE ;
2023-05-18 05:39:39 +02:00
2024-01-10 13:10:58 +02:00
* pdec = & dp - > dec ;
2023-05-18 05:39:39 +02:00
return 0 ;
fail :
2024-01-10 13:10:58 +02:00
dec_free ( ( Decoder * * ) & dp ) ;
2023-05-18 05:39:39 +02:00
return AVERROR ( ENOMEM ) ;
}
2024-01-10 13:10:58 +02:00
static AVRational audio_samplerate_update ( void * logctx , DecoderPriv * dp ,
2023-05-18 05:52:23 +02:00
const AVFrame * frame )
2023-05-17 09:36:14 +02:00
{
2024-01-10 13:10:58 +02:00
const int prev = dp - > last_frame_tb . den ;
2023-05-17 09:36:14 +02:00
const int sr = frame - > sample_rate ;
AVRational tb_new ;
int64_t gcd ;
2024-01-10 13:10:58 +02:00
if ( frame - > sample_rate = = dp - > last_frame_sample_rate )
2023-05-17 09:36:14 +02:00
goto finish ;
gcd = av_gcd ( prev , sr ) ;
if ( prev / gcd > = INT_MAX / sr ) {
2023-05-18 05:52:23 +02:00
av_log ( logctx , AV_LOG_WARNING ,
2023-05-17 09:36:14 +02:00
" Audio timestamps cannot be represented exactly after "
" sample rate change: %d -> %d \n " , prev , sr ) ;
// LCM of 192000, 44100, allows to represent all common samplerates
tb_new = ( AVRational ) { 1 , 28224000 } ;
} else
tb_new = ( AVRational ) { 1 , prev / gcd * sr } ;
// keep the frame timebase if it is strictly better than
// the samplerate-defined one
if ( frame - > time_base . num = = 1 & & frame - > time_base . den > tb_new . den & &
! ( frame - > time_base . den % tb_new . den ) )
tb_new = frame - > time_base ;
2024-01-10 13:10:58 +02:00
if ( dp - > last_frame_pts ! = AV_NOPTS_VALUE )
dp - > last_frame_pts = av_rescale_q ( dp - > last_frame_pts ,
dp - > last_frame_tb , tb_new ) ;
dp - > last_frame_duration_est = av_rescale_q ( dp - > last_frame_duration_est ,
dp - > last_frame_tb , tb_new ) ;
2023-05-17 09:36:14 +02:00
2024-01-10 13:10:58 +02:00
dp - > last_frame_tb = tb_new ;
dp - > last_frame_sample_rate = frame - > sample_rate ;
2023-05-17 09:36:14 +02:00
finish :
2024-01-10 13:10:58 +02:00
return dp - > last_frame_tb ;
2023-05-17 09:36:14 +02:00
}
2024-01-10 13:10:58 +02:00
static void audio_ts_process ( void * logctx , DecoderPriv * dp , AVFrame * frame )
2023-05-17 09:36:14 +02:00
{
AVRational tb_filter = ( AVRational ) { 1 , frame - > sample_rate } ;
AVRational tb ;
int64_t pts_pred ;
// on samplerate change, choose a new internal timebase for timestamp
// generation that can represent timestamps from all the samplerates
// seen so far
2024-01-10 13:10:58 +02:00
tb = audio_samplerate_update ( logctx , dp , frame ) ;
pts_pred = dp - > last_frame_pts = = AV_NOPTS_VALUE ? 0 :
dp - > last_frame_pts + dp - > last_frame_duration_est ;
2023-05-17 09:36:14 +02:00
if ( frame - > pts = = AV_NOPTS_VALUE ) {
frame - > pts = pts_pred ;
frame - > time_base = tb ;
2024-01-10 13:10:58 +02:00
} else if ( dp - > last_frame_pts ! = AV_NOPTS_VALUE & &
2023-05-17 09:36:14 +02:00
frame - > pts > av_rescale_q_rnd ( pts_pred , tb , frame - > time_base ,
AV_ROUND_UP ) ) {
// there was a gap in timestamps, reset conversion state
2024-01-10 13:10:58 +02:00
dp - > last_filter_in_rescale_delta = AV_NOPTS_VALUE ;
2023-05-17 09:36:14 +02:00
}
frame - > pts = av_rescale_delta ( frame - > time_base , frame - > pts ,
tb , frame - > nb_samples ,
2024-01-10 13:10:58 +02:00
& dp - > last_filter_in_rescale_delta , tb ) ;
2023-05-17 09:36:14 +02:00
2024-01-10 13:10:58 +02:00
dp - > last_frame_pts = frame - > pts ;
dp - > last_frame_duration_est = av_rescale_q ( frame - > nb_samples ,
tb_filter , tb ) ;
2023-05-17 09:36:14 +02:00
// finally convert to filtering timebase
frame - > pts = av_rescale_q ( frame - > pts , tb , tb_filter ) ;
frame - > duration = frame - > nb_samples ;
frame - > time_base = tb_filter ;
}
static int64_t video_duration_estimate ( const InputStream * ist , const AVFrame * frame )
{
2024-01-10 13:10:58 +02:00
const DecoderPriv * dp = dp_from_dec ( ist - > decoder ) ;
2023-12-13 19:39:02 +02:00
const InputFile * ifile = ist - > file ;
2023-05-17 09:36:14 +02:00
int64_t codec_duration = 0 ;
// XXX lavf currently makes up frame durations when they are not provided by
// the container. As there is no way to reliably distinguish real container
// durations from the fake made-up ones, we use heuristics based on whether
// the container has timestamps. Eventually lavf should stop making up
// durations, then this should be simplified.
// prefer frame duration for containers with timestamps
if ( frame - > duration > 0 & & ( ! ifile - > format_nots | | ist - > framerate . num ) )
return frame - > duration ;
if ( ist - > dec_ctx - > framerate . den & & ist - > dec_ctx - > framerate . num ) {
int fields = frame - > repeat_pict + 2 ;
AVRational field_rate = av_mul_q ( ist - > dec_ctx - > framerate ,
( AVRational ) { 2 , 1 } ) ;
codec_duration = av_rescale_q ( fields , av_inv_q ( field_rate ) ,
frame - > time_base ) ;
}
// prefer codec-layer duration for containers without timestamps
if ( codec_duration > 0 & & ifile - > format_nots )
return codec_duration ;
// when timestamps are available, repeat last frame's actual duration
// (i.e. pts difference between this and last frame)
2024-01-10 13:10:58 +02:00
if ( frame - > pts ! = AV_NOPTS_VALUE & & dp - > last_frame_pts ! = AV_NOPTS_VALUE & &
frame - > pts > dp - > last_frame_pts )
return frame - > pts - dp - > last_frame_pts ;
2023-05-17 09:36:14 +02:00
// try frame/codec duration
if ( frame - > duration > 0 )
return frame - > duration ;
if ( codec_duration > 0 )
return codec_duration ;
// try average framerate
if ( ist - > st - > avg_frame_rate . num & & ist - > st - > avg_frame_rate . den ) {
int64_t d = av_rescale_q ( 1 , av_inv_q ( ist - > st - > avg_frame_rate ) ,
frame - > time_base ) ;
if ( d > 0 )
return d ;
}
// last resort is last frame's estimated duration, and 1
2024-01-10 13:10:58 +02:00
return FFMAX ( dp - > last_frame_duration_est , 1 ) ;
2023-05-17 09:36:14 +02:00
}
2023-05-17 12:08:13 +02:00
static int video_frame_process ( InputStream * ist , AVFrame * frame )
2023-05-17 09:36:14 +02:00
{
2024-01-10 13:10:58 +02:00
DecoderPriv * dp = dp_from_dec ( ist - > decoder ) ;
2023-05-18 05:52:23 +02:00
2023-05-17 09:36:14 +02:00
// The following line may be required in some cases where there is no parser
// or the parser does not has_b_frames correctly
if ( ist - > par - > video_delay < ist - > dec_ctx - > has_b_frames ) {
if ( ist - > dec_ctx - > codec_id = = AV_CODEC_ID_H264 ) {
ist - > par - > video_delay = ist - > dec_ctx - > has_b_frames ;
} else
av_log ( ist - > dec_ctx , AV_LOG_WARNING ,
" video_delay is larger in decoder than demuxer %d > %d. \n "
" If you want to help, upload a sample "
" of this file to https://streams.videolan.org/upload/ "
" and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org) \n " ,
ist - > dec_ctx - > has_b_frames ,
ist - > par - > video_delay ) ;
}
2023-05-17 11:46:15 +02:00
if ( ist - > dec_ctx - > width ! = frame - > width | |
ist - > dec_ctx - > height ! = frame - > height | |
ist - > dec_ctx - > pix_fmt ! = frame - > format ) {
av_log ( NULL , AV_LOG_DEBUG , " Frame parameters mismatch context %d,%d,%d != %d,%d,%d \n " ,
frame - > width ,
frame - > height ,
frame - > format ,
ist - > dec_ctx - > width ,
ist - > dec_ctx - > height ,
ist - > dec_ctx - > pix_fmt ) ;
}
2023-05-17 09:36:14 +02:00
2023-09-14 17:07:29 +02:00
# if FFMPEG_OPT_TOP
if ( ist - > top_field_first > = 0 ) {
av_log ( ist , AV_LOG_WARNING , " -top is deprecated, use the setfield filter instead \n " ) ;
2023-05-17 09:36:14 +02:00
frame - > flags | = AV_FRAME_FLAG_TOP_FIELD_FIRST ;
2023-09-14 17:07:29 +02:00
}
# endif
2023-05-17 09:36:14 +02:00
2024-01-10 13:10:58 +02:00
if ( frame - > format = = dp - > hwaccel_pix_fmt ) {
2023-06-06 12:55:53 +02:00
int err = hwaccel_retrieve_data ( ist - > dec_ctx , frame ) ;
2023-05-17 09:36:14 +02:00
if ( err < 0 )
2023-05-17 11:55:04 +02:00
return err ;
2023-05-17 09:36:14 +02:00
}
frame - > pts = frame - > best_effort_timestamp ;
// forced fixed framerate
if ( ist - > framerate . num ) {
frame - > pts = AV_NOPTS_VALUE ;
frame - > duration = 1 ;
frame - > time_base = av_inv_q ( ist - > framerate ) ;
}
// no timestamp available - extrapolate from previous frame duration
if ( frame - > pts = = AV_NOPTS_VALUE )
2024-01-10 13:10:58 +02:00
frame - > pts = dp - > last_frame_pts = = AV_NOPTS_VALUE ? 0 :
dp - > last_frame_pts + dp - > last_frame_duration_est ;
2023-05-17 09:36:14 +02:00
// update timestamp history
2024-01-10 13:10:58 +02:00
dp - > last_frame_duration_est = video_duration_estimate ( ist , frame ) ;
dp - > last_frame_pts = frame - > pts ;
dp - > last_frame_tb = frame - > time_base ;
2023-05-17 09:36:14 +02:00
if ( debug_ts ) {
av_log ( ist , AV_LOG_INFO ,
" decoder -> pts:%s pts_time:%s "
" pkt_dts:%s pkt_dts_time:%s "
" duration:%s duration_time:%s "
" keyframe:%d frame_type:%d time_base:%d/%d \n " ,
av_ts2str ( frame - > pts ) ,
av_ts2timestr ( frame - > pts , & frame - > time_base ) ,
av_ts2str ( frame - > pkt_dts ) ,
av_ts2timestr ( frame - > pkt_dts , & frame - > time_base ) ,
av_ts2str ( frame - > duration ) ,
av_ts2timestr ( frame - > duration , & frame - > time_base ) ,
! ! ( frame - > flags & AV_FRAME_FLAG_KEY ) , frame - > pict_type ,
frame - > time_base . num , frame - > time_base . den ) ;
}
if ( ist - > st - > sample_aspect_ratio . num )
frame - > sample_aspect_ratio = ist - > st - > sample_aspect_ratio ;
2023-05-17 11:55:04 +02:00
return 0 ;
2023-05-17 09:36:14 +02:00
}
2023-06-14 18:08:10 +02:00
static int process_subtitle ( InputStream * ist , AVFrame * frame )
2023-05-17 09:36:14 +02:00
{
2024-01-10 13:10:58 +02:00
DecoderPriv * dp = dp_from_dec ( ist - > decoder ) ;
2023-06-14 18:08:10 +02:00
const AVSubtitle * subtitle = ( AVSubtitle * ) frame - > buf [ 0 ] - > data ;
2023-05-17 09:36:14 +02:00
int ret = 0 ;
if ( ist - > fix_sub_duration ) {
2024-01-10 13:10:58 +02:00
AVSubtitle * sub_prev = dp - > sub_prev [ 0 ] - > buf [ 0 ] ?
( AVSubtitle * ) dp - > sub_prev [ 0 ] - > buf [ 0 ] - > data : NULL ;
2023-05-17 09:36:14 +02:00
int end = 1 ;
2023-06-14 18:08:10 +02:00
if ( sub_prev ) {
end = av_rescale ( subtitle - > pts - sub_prev - > pts ,
2023-05-17 09:36:14 +02:00
1000 , AV_TIME_BASE ) ;
2023-06-14 18:08:10 +02:00
if ( end < sub_prev - > end_display_time ) {
2023-05-17 09:36:14 +02:00
av_log ( NULL , AV_LOG_DEBUG ,
" Subtitle duration reduced from % " PRId32 " to %d%s \n " ,
2023-06-14 18:08:10 +02:00
sub_prev - > end_display_time , end ,
2023-05-17 09:36:14 +02:00
end < = 0 ? " , dropping it " : " " ) ;
2023-06-14 18:08:10 +02:00
sub_prev - > end_display_time = end ;
2023-05-17 09:36:14 +02:00
}
}
2023-06-14 18:08:10 +02:00
2024-01-10 13:10:58 +02:00
av_frame_unref ( dp - > sub_prev [ 1 ] ) ;
av_frame_move_ref ( dp - > sub_prev [ 1 ] , frame ) ;
2023-06-14 18:08:10 +02:00
2024-01-10 13:10:58 +02:00
frame = dp - > sub_prev [ 0 ] ;
2023-06-14 18:08:10 +02:00
subtitle = frame - > buf [ 0 ] ? ( AVSubtitle * ) frame - > buf [ 0 ] - > data : NULL ;
2024-01-10 13:10:58 +02:00
FFSWAP ( AVFrame * , dp - > sub_prev [ 0 ] , dp - > sub_prev [ 1 ] ) ;
2023-06-14 18:08:10 +02:00
2023-05-17 09:36:14 +02:00
if ( end < = 0 )
2023-06-14 18:08:10 +02:00
return 0 ;
2023-05-17 09:36:14 +02:00
}
2023-06-14 18:08:10 +02:00
if ( ! subtitle )
2023-06-02 16:32:55 +02:00
return 0 ;
2023-05-17 09:36:14 +02:00
2024-01-10 13:10:58 +02:00
ret = sch_dec_send ( dp - > sch , dp - > sch_idx , frame ) ;
2023-06-08 20:36:33 +02:00
if ( ret < 0 )
2023-07-18 16:37:52 +02:00
av_frame_unref ( frame ) ;
2023-05-17 09:36:14 +02:00
2023-07-18 16:37:52 +02:00
return ret = = AVERROR_EOF ? AVERROR_EXIT : ret ;
2023-05-17 09:36:14 +02:00
}
2023-07-18 16:37:52 +02:00
static int fix_sub_duration_heartbeat ( InputStream * ist , int64_t signal_pts )
2023-06-14 16:09:25 +02:00
{
2024-01-10 13:10:58 +02:00
DecoderPriv * dp = dp_from_dec ( ist - > decoder ) ;
2023-06-14 16:09:25 +02:00
int ret = AVERROR_BUG ;
2024-01-10 13:10:58 +02:00
AVSubtitle * prev_subtitle = dp - > sub_prev [ 0 ] - > buf [ 0 ] ?
( AVSubtitle * ) dp - > sub_prev [ 0 ] - > buf [ 0 ] - > data : NULL ;
2023-06-14 18:08:10 +02:00
AVSubtitle * subtitle ;
2023-06-14 16:09:25 +02:00
2023-06-14 18:08:10 +02:00
if ( ! ist - > fix_sub_duration | | ! prev_subtitle | |
! prev_subtitle - > num_rects | | signal_pts < = prev_subtitle - > pts )
2023-06-14 16:09:25 +02:00
return 0 ;
2024-01-10 13:10:58 +02:00
av_frame_unref ( dp - > sub_heartbeat ) ;
ret = subtitle_wrap_frame ( dp - > sub_heartbeat , prev_subtitle , 1 ) ;
2023-06-14 18:08:10 +02:00
if ( ret < 0 )
2023-06-14 16:09:25 +02:00
return ret ;
2024-01-10 13:10:58 +02:00
subtitle = ( AVSubtitle * ) dp - > sub_heartbeat - > buf [ 0 ] - > data ;
2023-06-14 18:08:10 +02:00
subtitle - > pts = signal_pts ;
2023-06-14 16:09:25 +02:00
2024-01-10 13:10:58 +02:00
return process_subtitle ( ist , dp - > sub_heartbeat ) ;
2023-06-14 16:09:25 +02:00
}
2023-06-02 09:59:31 +02:00
static int transcode_subtitles ( InputStream * ist , const AVPacket * pkt ,
AVFrame * frame )
2023-05-17 09:36:14 +02:00
{
2024-01-10 13:10:58 +02:00
DecoderPriv * dp = dp_from_dec ( ist - > decoder ) ;
2023-06-02 15:12:58 +02:00
AVPacket * flush_pkt = NULL ;
2023-05-17 09:36:14 +02:00
AVSubtitle subtitle ;
2023-05-17 09:44:37 +02:00
int got_output ;
2023-06-02 15:12:58 +02:00
int ret ;
2023-07-18 16:37:52 +02:00
if ( pkt & & ( intptr_t ) pkt - > opaque = = PKT_OPAQUE_SUB_HEARTBEAT ) {
frame - > pts = pkt - > pts ;
frame - > time_base = pkt - > time_base ;
frame - > opaque = ( void * ) ( intptr_t ) FRAME_OPAQUE_SUB_HEARTBEAT ;
2024-01-10 13:10:58 +02:00
ret = sch_dec_send ( dp - > sch , dp - > sch_idx , frame ) ;
2023-07-18 16:37:52 +02:00
return ret = = AVERROR_EOF ? AVERROR_EXIT : ret ;
} else if ( pkt & & ( intptr_t ) pkt - > opaque = = PKT_OPAQUE_FIX_SUB_DURATION ) {
return fix_sub_duration_heartbeat ( ist , av_rescale_q ( pkt - > pts , pkt - > time_base ,
AV_TIME_BASE_Q ) ) ;
}
2023-06-02 15:12:58 +02:00
if ( ! pkt ) {
flush_pkt = av_packet_alloc ( ) ;
if ( ! flush_pkt )
return AVERROR ( ENOMEM ) ;
}
ret = avcodec_decode_subtitle2 ( ist - > dec_ctx , & subtitle , & got_output ,
pkt ? pkt : flush_pkt ) ;
av_packet_free ( & flush_pkt ) ;
2023-05-17 09:36:14 +02:00
2023-05-17 09:44:37 +02:00
if ( ret < 0 ) {
av_log ( ist , AV_LOG_ERROR , " Error decoding subtitles: %s \n " ,
av_err2str ( ret ) ) ;
2023-05-17 11:49:01 +02:00
ist - > decode_errors + + ;
2023-06-02 09:59:31 +02:00
return exit_on_error ? ret : 0 ;
2023-05-17 09:44:37 +02:00
}
2023-05-17 09:36:14 +02:00
2023-06-02 09:59:31 +02:00
if ( ! got_output )
return pkt ? 0 : AVERROR_EOF ;
2023-05-17 09:36:14 +02:00
ist - > frames_decoded + + ;
2023-07-18 16:37:52 +02:00
// XXX the queue for transferring data to consumers runs
2023-06-02 09:59:31 +02:00
// on AVFrames, so we wrap AVSubtitle in an AVBufferRef and put that
// inside the frame
// eventually, subtitles should be switched to use AVFrames natively
ret = subtitle_wrap_frame ( frame , & subtitle , 0 ) ;
if ( ret < 0 ) {
avsubtitle_free ( & subtitle ) ;
return ret ;
}
2023-06-14 18:34:57 +02:00
frame - > width = ist - > dec_ctx - > width ;
frame - > height = ist - > dec_ctx - > height ;
2023-07-18 16:37:52 +02:00
return process_subtitle ( ist , frame ) ;
2023-05-17 09:36:14 +02:00
}
2023-10-01 13:04:33 +02:00
static int packet_decode ( InputStream * ist , AVPacket * pkt , AVFrame * frame )
2023-05-17 09:36:14 +02:00
{
2023-12-13 19:39:02 +02:00
const InputFile * ifile = ist - > file ;
2024-01-10 13:10:58 +02:00
DecoderPriv * dp = dp_from_dec ( ist - > decoder ) ;
2023-05-17 09:44:37 +02:00
AVCodecContext * dec = ist - > dec_ctx ;
2023-05-17 11:34:55 +02:00
const char * type_desc = av_get_media_type_string ( dec - > codec_type ) ;
int ret ;
2023-05-17 09:36:14 +02:00
2023-05-17 09:44:37 +02:00
if ( dec - > codec_type = = AVMEDIA_TYPE_SUBTITLE )
2023-06-02 09:59:31 +02:00
return transcode_subtitles ( ist , pkt , frame ) ;
2023-05-17 09:44:37 +02:00
2023-05-17 11:34:55 +02:00
// With fate-indeo3-2, we're getting 0-sized packets before EOF for some
// reason. This seems like a semi-critical bug. Don't trigger EOF, and
// skip the packet.
if ( pkt & & pkt - > size = = 0 )
return 0 ;
2023-10-01 13:04:33 +02:00
if ( pkt & & ifile - > format_nots ) {
pkt - > pts = AV_NOPTS_VALUE ;
pkt - > dts = AV_NOPTS_VALUE ;
}
2023-11-24 20:08:15 +02:00
if ( pkt ) {
FrameData * fd = packet_data ( pkt ) ;
if ( ! fd )
return AVERROR ( ENOMEM ) ;
fd - > wallclock [ LATENCY_PROBE_DEC_PRE ] = av_gettime_relative ( ) ;
}
2023-05-17 11:34:55 +02:00
ret = avcodec_send_packet ( dec , pkt ) ;
if ( ret < 0 & & ! ( ret = = AVERROR_EOF & & ! pkt ) ) {
// In particular, we don't expect AVERROR(EAGAIN), because we read all
// decoded frames with avcodec_receive_frame() until done.
2023-05-23 00:13:25 +02:00
if ( ret = = AVERROR ( EAGAIN ) ) {
av_log ( ist , AV_LOG_FATAL , " A decoder returned an unexpected error code. "
" This is a bug, please report it. \n " ) ;
2023-06-02 09:59:31 +02:00
return AVERROR_BUG ;
2023-05-23 00:13:25 +02:00
}
2023-05-17 11:34:55 +02:00
av_log ( ist , AV_LOG_ERROR , " Error submitting %s to decoder: %s \n " ,
pkt ? " packet " : " EOF " , av_err2str ( ret ) ) ;
2023-06-02 09:59:31 +02:00
if ( ret ! = AVERROR_EOF ) {
2023-05-17 11:34:55 +02:00
ist - > decode_errors + + ;
2023-06-02 09:59:31 +02:00
if ( ! exit_on_error )
ret = 0 ;
}
2023-05-17 11:34:55 +02:00
return ret ;
2023-05-17 09:36:14 +02:00
}
while ( 1 ) {
2023-05-27 17:38:36 +02:00
FrameData * fd ;
2023-05-17 09:36:14 +02:00
2023-06-02 09:59:31 +02:00
av_frame_unref ( frame ) ;
2023-05-17 11:34:55 +02:00
update_benchmark ( NULL ) ;
ret = avcodec_receive_frame ( dec , frame ) ;
update_benchmark ( " decode_%s %d.%d " , type_desc ,
2023-12-13 19:39:02 +02:00
ifile - > index , ist - > index ) ;
2023-05-17 11:34:55 +02:00
if ( ret = = AVERROR ( EAGAIN ) ) {
av_assert0 ( pkt ) ; // should never happen during flushing
return 0 ;
} else if ( ret = = AVERROR_EOF ) {
2023-06-02 09:59:31 +02:00
return ret ;
2023-05-17 11:34:55 +02:00
} else if ( ret < 0 ) {
av_log ( ist , AV_LOG_ERROR , " Decoding error: %s \n " , av_err2str ( ret ) ) ;
2023-05-17 11:49:01 +02:00
ist - > decode_errors + + ;
2023-06-02 09:59:31 +02:00
if ( exit_on_error )
return ret ;
continue ;
2023-05-17 09:36:14 +02:00
}
2023-05-17 11:49:01 +02:00
if ( frame - > decode_error_flags | | ( frame - > flags & AV_FRAME_FLAG_CORRUPT ) ) {
av_log ( ist , exit_on_error ? AV_LOG_FATAL : AV_LOG_WARNING ,
" corrupt decoded frame \n " ) ;
if ( exit_on_error )
2023-06-02 09:59:31 +02:00
return AVERROR_INVALIDDATA ;
2023-05-17 11:49:01 +02:00
}
2023-05-27 17:38:36 +02:00
fd = frame_data ( frame ) ;
if ( ! fd ) {
av_frame_unref ( frame ) ;
2023-06-02 09:59:31 +02:00
return AVERROR ( ENOMEM ) ;
2023-05-17 09:36:14 +02:00
}
2023-07-07 11:02:15 +02:00
fd - > dec . pts = frame - > pts ;
fd - > dec . tb = dec - > pkt_timebase ;
fd - > dec . frame_num = dec - > frame_num - 1 ;
2023-05-27 17:38:36 +02:00
fd - > bits_per_raw_sample = dec - > bits_per_raw_sample ;
2023-05-17 09:36:14 +02:00
2023-11-24 20:08:15 +02:00
fd - > wallclock [ LATENCY_PROBE_DEC_POST ] = av_gettime_relative ( ) ;
2023-05-17 11:34:55 +02:00
frame - > time_base = dec - > pkt_timebase ;
2023-05-17 11:58:50 +02:00
if ( dec - > codec_type = = AVMEDIA_TYPE_AUDIO ) {
ist - > samples_decoded + = frame - > nb_samples ;
2023-05-17 09:36:14 +02:00
2024-01-10 13:10:58 +02:00
audio_ts_process ( ist , dp , frame ) ;
2023-05-17 11:58:50 +02:00
} else {
2023-05-17 12:08:13 +02:00
ret = video_frame_process ( ist , frame ) ;
2023-05-17 11:58:50 +02:00
if ( ret < 0 ) {
av_log ( NULL , AV_LOG_FATAL , " Error while processing the decoded "
2023-12-13 19:39:02 +02:00
" data for stream #%d:%d \n " , ifile - > index , ist - > index ) ;
2023-06-02 09:59:31 +02:00
return ret ;
2023-05-17 11:58:50 +02:00
}
2023-05-17 11:34:55 +02:00
}
2023-05-17 11:55:04 +02:00
ist - > frames_decoded + + ;
2024-01-10 13:10:58 +02:00
ret = sch_dec_send ( dp - > sch , dp - > sch_idx , frame ) ;
2023-07-18 16:37:52 +02:00
if ( ret < 0 ) {
av_frame_unref ( frame ) ;
return ret = = AVERROR_EOF ? AVERROR_EXIT : ret ;
}
2023-06-02 09:59:31 +02:00
}
}
static void dec_thread_set_name ( const InputStream * ist )
{
char name [ 16 ] ;
2023-12-13 19:39:02 +02:00
snprintf ( name , sizeof ( name ) , " dec%d:%d:%s " , ist - > file - > index , ist - > index ,
2023-06-02 09:59:31 +02:00
ist - > dec_ctx - > codec - > name ) ;
ff_thread_setname ( name ) ;
}
static void dec_thread_uninit ( DecThreadContext * dt )
{
av_packet_free ( & dt - > pkt ) ;
av_frame_free ( & dt - > frame ) ;
memset ( dt , 0 , sizeof ( * dt ) ) ;
}
static int dec_thread_init ( DecThreadContext * dt )
{
memset ( dt , 0 , sizeof ( * dt ) ) ;
dt - > frame = av_frame_alloc ( ) ;
if ( ! dt - > frame )
goto fail ;
dt - > pkt = av_packet_alloc ( ) ;
if ( ! dt - > pkt )
goto fail ;
return 0 ;
fail :
dec_thread_uninit ( dt ) ;
return AVERROR ( ENOMEM ) ;
}
2023-05-18 16:56:15 +02:00
void * decoder_thread ( void * arg )
2023-06-02 09:59:31 +02:00
{
InputStream * ist = arg ;
2024-01-10 13:10:58 +02:00
DecoderPriv * dp = dp_from_dec ( ist - > decoder ) ;
2023-06-02 09:59:31 +02:00
DecThreadContext dt ;
int ret = 0 , input_status = 0 ;
ret = dec_thread_init ( & dt ) ;
if ( ret < 0 )
goto finish ;
dec_thread_set_name ( ist ) ;
while ( ! input_status ) {
2023-07-18 16:37:52 +02:00
int flush_buffers , have_data ;
2024-01-10 13:10:58 +02:00
input_status = sch_dec_receive ( dp - > sch , dp - > sch_idx , dt . pkt ) ;
2023-07-18 16:37:52 +02:00
have_data = input_status > = 0 & &
( dt . pkt - > buf | | dt . pkt - > side_data_elems | |
( intptr_t ) dt . pkt - > opaque = = PKT_OPAQUE_SUB_HEARTBEAT | |
( intptr_t ) dt . pkt - > opaque = = PKT_OPAQUE_FIX_SUB_DURATION ) ;
flush_buffers = input_status > = 0 & & ! have_data ;
if ( ! have_data )
2023-06-02 09:59:31 +02:00
av_log ( ist , AV_LOG_VERBOSE , " Decoder thread received %s packet \n " ,
flush_buffers ? " flush " : " EOF " ) ;
2023-07-18 16:37:52 +02:00
ret = packet_decode ( ist , have_data ? dt . pkt : NULL , dt . frame ) ;
2023-06-02 09:59:31 +02:00
av_packet_unref ( dt . pkt ) ;
av_frame_unref ( dt . frame ) ;
2023-07-18 16:37:52 +02:00
// AVERROR_EOF - EOF from the decoder
// AVERROR_EXIT - EOF from the scheduler
// we treat them differently when flushing
if ( ret = = AVERROR_EXIT ) {
ret = AVERROR_EOF ;
flush_buffers = 0 ;
}
2023-06-02 09:59:31 +02:00
if ( ret = = AVERROR_EOF ) {
av_log ( ist , AV_LOG_VERBOSE , " Decoder returned EOF, %s \n " ,
flush_buffers ? " resetting " : " finishing " ) ;
if ( ! flush_buffers )
break ;
2023-07-18 16:37:52 +02:00
/* report last frame duration to the scheduler */
2023-06-02 09:59:31 +02:00
if ( ist - > dec - > type = = AVMEDIA_TYPE_AUDIO ) {
2024-01-10 13:10:58 +02:00
dt . pkt - > pts = dp - > last_frame_pts + dp - > last_frame_duration_est ;
dt . pkt - > time_base = dp - > last_frame_tb ;
2023-06-02 09:59:31 +02:00
}
avcodec_flush_buffers ( ist - > dec_ctx ) ;
} else if ( ret < 0 ) {
av_log ( ist , AV_LOG_ERROR , " Error processing packet in decoder: %s \n " ,
av_err2str ( ret ) ) ;
break ;
}
}
// EOF is normal thread termination
if ( ret = = AVERROR_EOF )
ret = 0 ;
2023-07-18 16:37:52 +02:00
// on success send EOF timestamp to our downstreams
if ( ret > = 0 ) {
float err_rate ;
2023-06-02 09:59:31 +02:00
2023-07-18 16:37:52 +02:00
av_frame_unref ( dt . frame ) ;
2023-06-02 09:59:31 +02:00
2023-07-18 16:37:52 +02:00
dt . frame - > opaque = ( void * ) ( intptr_t ) FRAME_OPAQUE_EOF ;
2024-01-10 13:10:58 +02:00
dt . frame - > pts = dp - > last_frame_pts = = AV_NOPTS_VALUE ? AV_NOPTS_VALUE :
dp - > last_frame_pts + dp - > last_frame_duration_est ;
dt . frame - > time_base = dp - > last_frame_tb ;
2023-06-02 09:59:31 +02:00
2024-01-10 13:10:58 +02:00
ret = sch_dec_send ( dp - > sch , dp - > sch_idx , dt . frame ) ;
2023-07-18 16:37:52 +02:00
if ( ret < 0 & & ret ! = AVERROR_EOF ) {
av_log ( NULL , AV_LOG_FATAL ,
" Error signalling EOF timestamp: %s \n " , av_err2str ( ret ) ) ;
2023-06-02 09:59:31 +02:00
goto finish ;
}
2023-07-18 16:37:52 +02:00
ret = 0 ;
2023-06-02 09:59:31 +02:00
2023-07-18 16:37:52 +02:00
err_rate = ( ist - > frames_decoded | | ist - > decode_errors ) ?
ist - > decode_errors / ( ist - > frames_decoded + ist - > decode_errors ) : 0.f ;
if ( err_rate > max_error_rate ) {
av_log ( ist , AV_LOG_FATAL , " Decode error rate %g exceeds maximum %g \n " ,
err_rate , max_error_rate ) ;
ret = FFMPEG_ERROR_RATE_EXCEEDED ;
} else if ( err_rate )
av_log ( ist , AV_LOG_VERBOSE , " Decode error rate %g \n " , err_rate ) ;
2023-06-02 09:59:31 +02:00
}
2023-07-18 16:37:52 +02:00
finish :
dec_thread_uninit ( & dt ) ;
2023-06-02 09:59:31 +02:00
2023-07-18 16:37:52 +02:00
return ( void * ) ( intptr_t ) ret ;
2023-05-17 09:36:14 +02:00
}
2023-04-11 13:21:56 +02:00
static enum AVPixelFormat get_format ( AVCodecContext * s , const enum AVPixelFormat * pix_fmts )
{
InputStream * ist = s - > opaque ;
2024-01-10 13:10:58 +02:00
DecoderPriv * dp = dp_from_dec ( ist - > decoder ) ;
2023-04-11 13:21:56 +02:00
const enum AVPixelFormat * p ;
for ( p = pix_fmts ; * p ! = AV_PIX_FMT_NONE ; p + + ) {
const AVPixFmtDescriptor * desc = av_pix_fmt_desc_get ( * p ) ;
const AVCodecHWConfig * config = NULL ;
int i ;
if ( ! ( desc - > flags & AV_PIX_FMT_FLAG_HWACCEL ) )
break ;
if ( ist - > hwaccel_id = = HWACCEL_GENERIC | |
ist - > hwaccel_id = = HWACCEL_AUTO ) {
for ( i = 0 ; ; i + + ) {
config = avcodec_get_hw_config ( s - > codec , i ) ;
if ( ! config )
break ;
if ( ! ( config - > methods &
AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX ) )
continue ;
if ( config - > pix_fmt = = * p )
break ;
}
}
if ( config & & config - > device_type = = ist - > hwaccel_device_type ) {
2024-01-10 13:10:58 +02:00
dp - > hwaccel_pix_fmt = * p ;
2023-04-11 13:21:56 +02:00
break ;
}
}
return * p ;
}
2023-05-17 17:04:28 +02:00
static HWDevice * hw_device_match_by_codec ( const AVCodec * codec )
{
const AVCodecHWConfig * config ;
HWDevice * dev ;
int i ;
for ( i = 0 ; ; i + + ) {
config = avcodec_get_hw_config ( codec , i ) ;
if ( ! config )
return NULL ;
if ( ! ( config - > methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX ) )
continue ;
dev = hw_device_get_by_type ( config - > device_type ) ;
if ( dev )
return dev ;
}
}
static int hw_device_setup_for_decode ( InputStream * ist )
{
const AVCodecHWConfig * config ;
enum AVHWDeviceType type ;
HWDevice * dev = NULL ;
int err , auto_device = 0 ;
if ( ist - > hwaccel_device ) {
dev = hw_device_get_by_name ( ist - > hwaccel_device ) ;
if ( ! dev ) {
if ( ist - > hwaccel_id = = HWACCEL_AUTO ) {
auto_device = 1 ;
} else if ( ist - > hwaccel_id = = HWACCEL_GENERIC ) {
type = ist - > hwaccel_device_type ;
err = hw_device_init_from_type ( type , ist - > hwaccel_device ,
& dev ) ;
} else {
// This will be dealt with by API-specific initialisation
// (using hwaccel_device), so nothing further needed here.
return 0 ;
}
} else {
if ( ist - > hwaccel_id = = HWACCEL_AUTO ) {
ist - > hwaccel_device_type = dev - > type ;
} else if ( ist - > hwaccel_device_type ! = dev - > type ) {
av_log ( NULL , AV_LOG_ERROR , " Invalid hwaccel device "
" specified for decoder: device %s of type %s is not "
" usable with hwaccel %s. \n " , dev - > name ,
av_hwdevice_get_type_name ( dev - > type ) ,
av_hwdevice_get_type_name ( ist - > hwaccel_device_type ) ) ;
return AVERROR ( EINVAL ) ;
}
}
} else {
if ( ist - > hwaccel_id = = HWACCEL_AUTO ) {
auto_device = 1 ;
} else if ( ist - > hwaccel_id = = HWACCEL_GENERIC ) {
type = ist - > hwaccel_device_type ;
dev = hw_device_get_by_type ( type ) ;
// When "-qsv_device device" is used, an internal QSV device named
// as "__qsv_device" is created. Another QSV device is created too
// if "-init_hw_device qsv=name:device" is used. There are 2 QSV devices
// if both "-qsv_device device" and "-init_hw_device qsv=name:device"
// are used, hw_device_get_by_type(AV_HWDEVICE_TYPE_QSV) returns NULL.
// To keep back-compatibility with the removed ad-hoc libmfx setup code,
// call hw_device_get_by_name("__qsv_device") to select the internal QSV
// device.
if ( ! dev & & type = = AV_HWDEVICE_TYPE_QSV )
dev = hw_device_get_by_name ( " __qsv_device " ) ;
if ( ! dev )
err = hw_device_init_from_type ( type , NULL , & dev ) ;
} else {
dev = hw_device_match_by_codec ( ist - > dec ) ;
if ( ! dev ) {
// No device for this codec, but not using generic hwaccel
// and therefore may well not need one - ignore.
return 0 ;
}
}
}
if ( auto_device ) {
int i ;
if ( ! avcodec_get_hw_config ( ist - > dec , 0 ) ) {
// Decoder does not support any hardware devices.
return 0 ;
}
for ( i = 0 ; ! dev ; i + + ) {
config = avcodec_get_hw_config ( ist - > dec , i ) ;
if ( ! config )
break ;
type = config - > device_type ;
dev = hw_device_get_by_type ( type ) ;
if ( dev ) {
av_log ( NULL , AV_LOG_INFO , " Using auto "
" hwaccel type %s with existing device %s. \n " ,
av_hwdevice_get_type_name ( type ) , dev - > name ) ;
}
}
for ( i = 0 ; ! dev ; i + + ) {
config = avcodec_get_hw_config ( ist - > dec , i ) ;
if ( ! config )
break ;
type = config - > device_type ;
// Try to make a new device of this type.
err = hw_device_init_from_type ( type , ist - > hwaccel_device ,
& dev ) ;
if ( err < 0 ) {
// Can't make a device of this type.
continue ;
}
if ( ist - > hwaccel_device ) {
av_log ( NULL , AV_LOG_INFO , " Using auto "
" hwaccel type %s with new device created "
" from %s. \n " , av_hwdevice_get_type_name ( type ) ,
ist - > hwaccel_device ) ;
} else {
av_log ( NULL , AV_LOG_INFO , " Using auto "
" hwaccel type %s with new default device. \n " ,
av_hwdevice_get_type_name ( type ) ) ;
}
}
if ( dev ) {
ist - > hwaccel_device_type = type ;
} else {
av_log ( NULL , AV_LOG_INFO , " Auto hwaccel "
" disabled: no device found. \n " ) ;
ist - > hwaccel_id = HWACCEL_NONE ;
return 0 ;
}
}
if ( ! dev ) {
av_log ( NULL , AV_LOG_ERROR , " No device available "
" for decoder: device type %s needed for codec %s. \n " ,
av_hwdevice_get_type_name ( type ) , ist - > dec - > name ) ;
return err ;
}
ist - > dec_ctx - > hw_device_ctx = av_buffer_ref ( dev - > device_ref ) ;
if ( ! ist - > dec_ctx - > hw_device_ctx )
return AVERROR ( ENOMEM ) ;
return 0 ;
}
2023-05-18 16:56:15 +02:00
int dec_open ( InputStream * ist , Scheduler * sch , unsigned sch_idx )
2023-04-11 13:21:56 +02:00
{
2024-01-10 13:10:58 +02:00
DecoderPriv * dp ;
2023-04-11 13:23:47 +02:00
const AVCodec * codec = ist - > dec ;
2023-04-11 13:21:56 +02:00
int ret ;
2023-04-11 13:23:47 +02:00
if ( ! codec ) {
av_log ( ist , AV_LOG_ERROR ,
" Decoding requested, but no decoder found for: %s \n " ,
avcodec_get_name ( ist - > dec_ctx - > codec_id ) ) ;
return AVERROR ( EINVAL ) ;
}
2023-04-11 13:21:56 +02:00
2023-05-18 05:39:39 +02:00
ret = dec_alloc ( & ist - > decoder ) ;
if ( ret < 0 )
return ret ;
2024-01-10 13:10:58 +02:00
dp = dp_from_dec ( ist - > decoder ) ;
2023-06-14 18:08:10 +02:00
2024-01-10 13:10:58 +02:00
dp - > sch = sch ;
dp - > sch_idx = sch_idx ;
2023-05-18 16:56:15 +02:00
2023-06-14 18:08:10 +02:00
if ( codec - > type = = AVMEDIA_TYPE_SUBTITLE & & ist - > fix_sub_duration ) {
2024-01-10 13:10:58 +02:00
for ( int i = 0 ; i < FF_ARRAY_ELEMS ( dp - > sub_prev ) ; i + + ) {
dp - > sub_prev [ i ] = av_frame_alloc ( ) ;
if ( ! dp - > sub_prev [ i ] )
2023-06-14 18:08:10 +02:00
return AVERROR ( ENOMEM ) ;
}
2024-01-10 13:10:58 +02:00
dp - > sub_heartbeat = av_frame_alloc ( ) ;
if ( ! dp - > sub_heartbeat )
2023-06-14 18:08:10 +02:00
return AVERROR ( ENOMEM ) ;
}
2023-05-18 05:39:39 +02:00
2023-04-11 13:23:47 +02:00
ist - > dec_ctx - > opaque = ist ;
ist - > dec_ctx - > get_format = get_format ;
2023-04-11 13:21:56 +02:00
2023-04-11 13:23:47 +02:00
if ( ist - > dec_ctx - > codec_id = = AV_CODEC_ID_DVB_SUBTITLE & &
( ist - > decoding_needed & DECODING_FOR_OST ) ) {
av_dict_set ( & ist - > decoder_opts , " compute_edt " , " 1 " , AV_DICT_DONT_OVERWRITE ) ;
if ( ist - > decoding_needed & DECODING_FOR_FILTER )
av_log ( NULL , AV_LOG_WARNING , " Warning using DVB subtitles for filtering and output at the same time is not fully supported, also see -compute_edt [0|1] \n " ) ;
}
2023-04-11 13:21:56 +02:00
2023-04-11 13:23:47 +02:00
/* Useful for subtitles retiming by lavf (FIXME), skipping samples in
* audio , and video decoders such as cuvid or mediacodec */
ist - > dec_ctx - > pkt_timebase = ist - > st - > time_base ;
if ( ! av_dict_get ( ist - > decoder_opts , " threads " , NULL , 0 ) )
av_dict_set ( & ist - > decoder_opts , " threads " , " auto " , 0 ) ;
/* Attached pics are sparse, therefore we would not want to delay their decoding till EOF. */
if ( ist - > st - > disposition & AV_DISPOSITION_ATTACHED_PIC )
av_dict_set ( & ist - > decoder_opts , " threads " , " 1 " , 0 ) ;
2023-11-24 20:08:15 +02:00
av_dict_set ( & ist - > decoder_opts , " flags " , " +copy_opaque " , AV_DICT_MULTIKEY ) ;
2023-04-11 13:23:47 +02:00
ret = hw_device_setup_for_decode ( ist ) ;
if ( ret < 0 ) {
av_log ( ist , AV_LOG_ERROR ,
" Hardware device setup failed for decoder: %s \n " ,
av_err2str ( ret ) ) ;
return ret ;
}
2023-04-11 13:21:56 +02:00
2023-04-11 13:23:47 +02:00
if ( ( ret = avcodec_open2 ( ist - > dec_ctx , codec , & ist - > decoder_opts ) ) < 0 ) {
av_log ( ist , AV_LOG_ERROR , " Error while opening decoder: %s \n " ,
av_err2str ( ret ) ) ;
return ret ;
}
2023-07-14 18:18:57 +02:00
ret = check_avoptions ( ist - > decoder_opts ) ;
if ( ret < 0 )
return ret ;
2023-04-11 13:21:56 +02:00
2024-01-10 13:20:32 +02:00
dp - > dec . subtitle_header = ist - > dec_ctx - > subtitle_header ;
dp - > dec . subtitle_header_size = ist - > dec_ctx - > subtitle_header_size ;
2023-04-11 13:21:56 +02:00
return 0 ;
}