X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fcodec%2Favcodec%2Fvideo.c;h=7f5b8abb936d48f1d54d43606902f7db3a23f7a4;hb=df252eac618091d156cf986f38a98c2bddbc8437;hp=7697ef98cc1b1182706ce3afd16c2a3db4edd9f9;hpb=d9e90b4d925a09506407a6c0300213d3f7149658;p=vlc diff --git a/modules/codec/avcodec/video.c b/modules/codec/avcodec/video.c index 7697ef98cc..7f5b8abb93 100644 --- a/modules/codec/avcodec/video.c +++ b/modules/codec/avcodec/video.c @@ -104,7 +104,6 @@ struct decoder_sys_t static void ffmpeg_InitCodec ( decoder_t * ); static void ffmpeg_CopyPicture ( decoder_t *, picture_t *, AVFrame * ); static int ffmpeg_GetFrameBuf ( struct AVCodecContext *, AVFrame * ); -static int ffmpeg_ReGetFrameBuf( struct AVCodecContext *, AVFrame * ); static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *, AVFrame * ); static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *, const enum PixelFormat * ); @@ -172,7 +171,7 @@ static inline picture_t *ffmpeg_NewPictBuf( decoder_t *p_dec, else if( p_context->time_base.num > 0 && p_context->time_base.den > 0 ) { p_dec->fmt_out.video.i_frame_rate = p_context->time_base.den; - p_dec->fmt_out.video.i_frame_rate_base = p_context->time_base.num; + p_dec->fmt_out.video.i_frame_rate_base = p_context->time_base.num * __MAX( p_context->ticks_per_frame, 1 ); } return decoder_NewPicture( p_dec ); @@ -314,7 +313,7 @@ int InitVideoDec( decoder_t *p_dec, AVCodecContext *p_context, /* Always use our get_buffer wrapper so we can calculate the * PTS correctly */ p_sys->p_context->get_buffer = ffmpeg_GetFrameBuf; - p_sys->p_context->reget_buffer = ffmpeg_ReGetFrameBuf; + p_sys->p_context->reget_buffer = avcodec_default_reget_buffer; p_sys->p_context->release_buffer = ffmpeg_ReleaseFrameBuf; p_sys->p_context->opaque = p_dec; @@ -332,25 +331,29 @@ int InitVideoDec( decoder_t *p_dec, AVCodecContext *p_context, i_thread_count = __MIN( i_thread_count, 16 ); msg_Dbg( p_dec, "allowing %d thread(s) for decoding", i_thread_count ); p_sys->p_context->thread_count = i_thread_count; + + if( i_codec_id == AV_CODEC_ID_MPEG4 ) + p_sys->p_context->thread_count = 1; + #endif char *hw = var_CreateGetString( p_dec, "avcodec-hw" ); /* FIXME */ if( (hw == NULL || strcasecmp( hw, "none" )) && (i_codec_id == AV_CODEC_ID_MPEG1VIDEO || i_codec_id == AV_CODEC_ID_MPEG2VIDEO || - i_codec_id == AV_CODEC_ID_MPEG4 || + i_codec_id == AV_CODEC_ID_MPEG4 || i_codec_id == AV_CODEC_ID_H263 || i_codec_id == AV_CODEC_ID_H264 || i_codec_id == AV_CODEC_ID_VC1 || i_codec_id == AV_CODEC_ID_WMV3) ) { -#ifdef HAVE_AVCODEC_MT +#if defined(HAVE_AVCODEC_MT) //&& LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 1, 0) if( p_sys->p_context->thread_type & FF_THREAD_FRAME ) { - msg_Warn( p_dec, "threaded frame decoding is not compatible with libavcodec-hw, disabled" ); + msg_Warn( p_dec, "threaded frame decoding is not compatible with avcodec-hw, disabled" ); p_sys->p_context->thread_type &= ~FF_THREAD_FRAME; } if( ( p_sys->p_context->thread_type & FF_THREAD_SLICE ) && ( i_codec_id == AV_CODEC_ID_MPEG1VIDEO || i_codec_id == AV_CODEC_ID_MPEG2VIDEO ) ) { - msg_Warn( p_dec, "threaded slice decoding is not compatible with libavcodec-hw, disabled" ); + msg_Warn( p_dec, "threaded slice decoding is not compatible with avcodec-hw, disabled" ); p_sys->p_context->thread_type &= ~FF_THREAD_SLICE; } #endif @@ -568,24 +571,18 @@ picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block ) picture_t *p_pic; AVPacket pkt; - /* Set the PTS/DTS in the context reordered_opaque field */ - if( p_block->i_pts > VLC_TS_INVALID ) - p_context->reordered_opaque = (p_block->i_pts << 1) | 0; - else if( p_block->i_dts > VLC_TS_INVALID ) - p_context->reordered_opaque = (p_block->i_dts << 1) | 1; - else - p_context->reordered_opaque = INT64_MIN; - p_sys->p_ff_pic->reordered_opaque = p_context->reordered_opaque; - - /* Make sure we don't reuse the same timestamps twice */ - p_block->i_pts = - p_block->i_dts = VLC_TS_INVALID; - post_mt( p_sys ); av_init_packet( &pkt ); pkt.data = p_block->p_buffer; pkt.size = p_block->i_buffer; + pkt.pts = p_block->i_pts; + pkt.dts = p_block->i_dts; + + /* Make sure we don't reuse the same timestamps twice */ + p_block->i_pts = + p_block->i_dts = VLC_TS_INVALID; + i_used = avcodec_decode_video2( p_context, p_sys->p_ff_pic, &b_gotpicture, &pkt ); @@ -639,33 +636,11 @@ picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block ) } /* Compute the PTS */ - mtime_t i_pts = VLC_TS_INVALID; - if( p_sys->p_ff_pic->reordered_opaque != INT64_MIN ) - { - mtime_t i_ts = p_sys->p_ff_pic->reordered_opaque >> 1; - bool b_dts = p_sys->p_ff_pic->reordered_opaque & 1; - if( b_dts ) - { - if( !p_context->has_b_frames || - !p_sys->b_has_b_frames || - !p_sys->p_ff_pic->reference || - p_sys->i_pts <= VLC_TS_INVALID ) - i_pts = i_ts; - - /* Guess what ? The rules are different for Real Video :( */ - if( (p_dec->fmt_in.i_codec == VLC_CODEC_RV30 || - p_dec->fmt_in.i_codec == VLC_CODEC_RV40) && - p_sys->b_has_b_frames ) - { - i_pts = VLC_TS_INVALID; - if(p_sys->p_ff_pic->reference) i_pts = i_ts; - } - } - else - { - i_pts = i_ts; - } - } + mtime_t i_pts = + p_sys->p_ff_pic->pkt_pts; + if (i_pts <= VLC_TS_INVALID) + i_pts = p_sys->p_ff_pic->pkt_dts; + if( i_pts <= VLC_TS_INVALID ) i_pts = p_sys->i_pts; @@ -796,13 +771,12 @@ void EndVideoDec( decoder_t *p_dec ) wait_mt( p_sys ); - if( p_sys->p_ff_pic ) av_free( p_sys->p_ff_pic ); + if( p_sys->p_ff_pic ) + av_free( p_sys->p_ff_pic ); if( p_sys->p_va ) - { vlc_va_Delete( p_sys->p_va ); - p_sys->p_va = NULL; - } + vlc_sem_destroy( &p_sys->sem_mt ); } @@ -915,77 +889,58 @@ static void ffmpeg_CopyPicture( decoder_t *p_dec, } } -/***************************************************************************** - * ffmpeg_GetFrameBuf: callback used by ffmpeg to get a frame buffer. - ***************************************************************************** - * It is used for direct rendering as well as to get the right PTS for each - * decoded picture (even in indirect rendering mode). - *****************************************************************************/ -static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context, - AVFrame *p_ff_pic ) +static int ffmpeg_va_GetFrameBuf( struct AVCodecContext *p_context, AVFrame *p_ff_pic ) { decoder_t *p_dec = (decoder_t *)p_context->opaque; decoder_sys_t *p_sys = p_dec->p_sys; - picture_t *p_pic; - - /* */ - p_ff_pic->reordered_opaque = p_context->reordered_opaque; - p_ff_pic->opaque = NULL; + vlc_va_t *p_va = p_sys->p_va; - if( p_sys->p_va ) + /* hwaccel_context is not present in old ffmpeg version */ + if( vlc_va_Setup( p_va, + &p_context->hwaccel_context, &p_dec->fmt_out.video.i_chroma, + p_context->width, p_context->height ) ) { - /* hwaccel_context is not present in old ffmpeg version */ - if( vlc_va_Setup( p_sys->p_va, - &p_context->hwaccel_context, &p_dec->fmt_out.video.i_chroma, - p_context->width, p_context->height ) ) - { - msg_Err( p_dec, "vlc_va_Setup failed" ); - return -1; - } - - /* */ - p_ff_pic->type = FF_BUFFER_TYPE_USER; - -#if LIBAVCODEC_VERSION_MAJOR < 54 - p_ff_pic->age = 256*256*256*64; -#endif - - if( vlc_va_Get( p_sys->p_va, p_ff_pic ) ) - { - msg_Err( p_dec, "VaGrabSurface failed" ); - return -1; - } - return 0; + msg_Err( p_dec, "vlc_va_Setup failed" ); + return -1; } - else if( !p_sys->b_direct_rendering ) + + if( vlc_va_Get( p_va, p_ff_pic ) ) { - /* Not much to do in indirect rendering mode. */ - return avcodec_default_get_buffer( p_context, p_ff_pic ); + msg_Err( p_dec, "vlc_va_Get failed" ); + return -1; } - wait_mt( p_sys ); - /* Some codecs set pix_fmt only after the 1st frame has been decoded, - * so we need to check for direct rendering again. */ + p_ff_pic->type = FF_BUFFER_TYPE_USER; + return 0; +} + +static picture_t *ffmpeg_dr_GetFrameBuf(struct AVCodecContext *p_context) +{ + decoder_t *p_dec = (decoder_t *)p_context->opaque; + decoder_sys_t *p_sys = p_dec->p_sys; int i_width = p_context->width; int i_height = p_context->height; avcodec_align_dimensions( p_context, &i_width, &i_height ); - if( GetVlcChroma( &p_dec->fmt_out.video, p_context->pix_fmt ) != VLC_SUCCESS || - p_context->pix_fmt == PIX_FMT_PAL8 ) + picture_t *p_pic = NULL; + if (GetVlcChroma(&p_dec->fmt_out.video, p_context->pix_fmt) != VLC_SUCCESS) + goto no_dr; + + if (p_context->pix_fmt == PIX_FMT_PAL8) goto no_dr; p_dec->fmt_out.i_codec = p_dec->fmt_out.video.i_chroma; - /* Get a new picture */ p_pic = ffmpeg_NewPictBuf( p_dec, p_context ); if( !p_pic ) goto no_dr; - bool b_compatible = true; + if( p_pic->p[0].i_pitch / p_pic->p[0].i_pixel_pitch < i_width || p_pic->p[0].i_lines < i_height ) - b_compatible = false; - for( int i = 0; i < p_pic->i_planes && b_compatible; i++ ) + goto no_dr; + + for( int i = 0; i < p_pic->i_planes; i++ ) { unsigned i_align; switch( p_sys->i_codec_id ) @@ -1002,29 +957,77 @@ static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context, break; } if( p_pic->p[i].i_pitch % i_align ) - b_compatible = false; + goto no_dr; if( (intptr_t)p_pic->p[i].p_pixels % i_align ) - b_compatible = false; + goto no_dr; } - if( p_context->pix_fmt == PIX_FMT_YUV422P && b_compatible ) + + if( p_context->pix_fmt == PIX_FMT_YUV422P ) { if( 2 * p_pic->p[1].i_pitch != p_pic->p[0].i_pitch || 2 * p_pic->p[2].i_pitch != p_pic->p[0].i_pitch ) - b_compatible = false; + goto no_dr; } - if( !b_compatible ) - { + + return p_pic; + +no_dr: + if (p_pic) decoder_DeletePicture( p_dec, p_pic ); - goto no_dr; + + return NULL; +} + +/***************************************************************************** + * ffmpeg_GetFrameBuf: callback used by ffmpeg to get a frame buffer. + ***************************************************************************** + * It is used for direct rendering as well as to get the right PTS for each + * decoded picture (even in indirect rendering mode). + *****************************************************************************/ +static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context, + AVFrame *p_ff_pic ) +{ + decoder_t *p_dec = (decoder_t *)p_context->opaque; + decoder_sys_t *p_sys = p_dec->p_sys; + + /* */ + p_ff_pic->opaque = NULL; +#if ! LIBAVCODEC_VERSION_CHECK(54, 34, 0, 79, 101) + p_ff_pic->pkt_pts = p_context->pkt ? p_context->pkt->pts : AV_NOPTS_VALUE; +#endif +#if LIBAVCODEC_VERSION_MAJOR < 54 + p_ff_pic->age = 256*256*256*64; +#endif + + if( p_sys->p_va ) + return ffmpeg_va_GetFrameBuf(p_context, p_ff_pic); + + if( !p_sys->b_direct_rendering ) + return avcodec_default_get_buffer( p_context, p_ff_pic ); + + wait_mt( p_sys ); + /* Some codecs set pix_fmt only after the 1st frame has been decoded, + * so we need to check for direct rendering again. */ + + picture_t *p_pic = ffmpeg_dr_GetFrameBuf(p_context); + if (!p_pic) { + if( p_sys->i_direct_rendering_used != 0 ) + { + msg_Warn( p_dec, "disabling direct rendering" ); + p_sys->i_direct_rendering_used = 0; + } + + post_mt( p_sys ); + return avcodec_default_get_buffer( p_context, p_ff_pic ); } - if( p_sys->i_direct_rendering_used != 1 ) - { + if( p_sys->i_direct_rendering_used != 1 ) { msg_Dbg( p_dec, "using direct rendering" ); p_sys->i_direct_rendering_used = 1; } p_context->draw_horiz_band = NULL; + post_mt( p_sys ); p_ff_pic->opaque = (void*)p_pic; p_ff_pic->type = FF_BUFFER_TYPE_USER; @@ -1038,28 +1041,7 @@ static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context, p_ff_pic->linesize[2] = p_pic->p[2].i_pitch; p_ff_pic->linesize[3] = 0; -#if LIBAVCODEC_VERSION_MAJOR < 54 - p_ff_pic->age = 256*256*256*64; -#endif - - post_mt( p_sys ); return 0; - -no_dr: - if( p_sys->i_direct_rendering_used != 0 ) - { - msg_Warn( p_dec, "disabling direct rendering" ); - p_sys->i_direct_rendering_used = 0; - } - post_mt( p_sys ); - return avcodec_default_get_buffer( p_context, p_ff_pic ); -} -static int ffmpeg_ReGetFrameBuf( struct AVCodecContext *p_context, AVFrame *p_ff_pic ) -{ - p_ff_pic->reordered_opaque = p_context->reordered_opaque; - - /* We always use default reget function, it works perfectly fine */ - return avcodec_default_reget_buffer( p_context, p_ff_pic ); } static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context, @@ -1069,24 +1051,16 @@ static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context, decoder_sys_t *p_sys = p_dec->p_sys; if( p_sys->p_va ) - { vlc_va_Release( p_sys->p_va, p_ff_pic ); - } - else if( !p_ff_pic->opaque ) - { + else if( p_ff_pic->opaque ) + decoder_UnlinkPicture( p_dec, (picture_t*)p_ff_pic->opaque); + else if( p_ff_pic->type == FF_BUFFER_TYPE_INTERNAL ) /* We can end up here without the AVFrame being allocated by * avcodec_default_get_buffer() if VA is used and the frame is * released when the decoder is closed */ - if( p_ff_pic->type == FF_BUFFER_TYPE_INTERNAL ) - avcodec_default_release_buffer( p_context, p_ff_pic ); - } - else - { - picture_t *p_pic = (picture_t*)p_ff_pic->opaque; + avcodec_default_release_buffer( p_context, p_ff_pic ); - decoder_UnlinkPicture( p_dec, p_pic ); - } for( int i = 0; i < 4; i++ ) p_ff_pic->data[i] = NULL; } @@ -1143,47 +1117,56 @@ static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *p_context, if( p_va != NULL ) vlc_va_Delete( p_va ); + /* Profile and level informations are needed now. + * TODO: avoid code duplication with avcodec.c */ + if( p_context->profile != FF_PROFILE_UNKNOWN) + p_dec->fmt_in.i_profile = p_context->profile; + if( p_context->level != FF_LEVEL_UNKNOWN) + p_dec->fmt_in.i_level = p_context->level; + p_va = vlc_va_New( VLC_OBJECT(p_dec), p_sys->i_codec_id, &p_dec->fmt_in ); - if( p_va != NULL ) + if( p_va == NULL ) + goto end; + + /* Try too look for a supported hw acceleration */ + for( size_t i = 0; pi_fmt[i] != PIX_FMT_NONE; i++ ) { - /* Try too look for a supported hw acceleration */ - for( size_t i = 0; pi_fmt[i] != PIX_FMT_NONE; i++ ) - { - const char *name = av_get_pix_fmt_name(pi_fmt[i]); - msg_Dbg( p_dec, "Available decoder output format %d (%s)", - pi_fmt[i], name ? name : "unknown" ); - if( p_va->pix_fmt != pi_fmt[i] ) - continue; - - /* We try to call vlc_va_Setup when possible to detect errors when - * possible (later is too late) */ - if( p_context->width > 0 && p_context->height > 0 - && vlc_va_Setup( p_va, &p_context->hwaccel_context, - &p_dec->fmt_out.video.i_chroma, - p_context->width, p_context->height ) ) - { - msg_Err( p_dec, "acceleration setup failure" ); - break; - } + const char *name = av_get_pix_fmt_name(pi_fmt[i]); + msg_Dbg( p_dec, "Available decoder output format %d (%s)", + pi_fmt[i], name ? name : "unknown" ); + if( p_va->pix_fmt != pi_fmt[i] ) + continue; - if( p_va->description ) - msg_Info( p_dec, "Using %s for hardware decoding.", - p_va->description ); - - /* FIXME this will disable direct rendering - * even if a new pixel format is renegotiated - */ - p_sys->b_direct_rendering = false; - p_sys->p_va = p_va; - p_context->draw_horiz_band = NULL; - return pi_fmt[i]; + /* We try to call vlc_va_Setup when possible to detect errors when + * possible (later is too late) */ + if( p_context->width > 0 && p_context->height > 0 + && vlc_va_Setup( p_va, &p_context->hwaccel_context, + &p_dec->fmt_out.video.i_chroma, + p_context->width, p_context->height ) ) + { + msg_Err( p_dec, "acceleration setup failure" ); + break; } - msg_Err( p_dec, "acceleration not available" ); - vlc_va_Delete( p_va ); + if( p_va->description ) + msg_Info( p_dec, "Using %s for hardware decoding.", + p_va->description ); + + /* FIXME this will disable direct rendering + * even if a new pixel format is renegotiated + */ + p_sys->b_direct_rendering = false; + p_sys->p_va = p_va; + p_context->draw_horiz_band = NULL; + return pi_fmt[i]; } + + msg_Err( p_dec, "acceleration not available" ); + vlc_va_Delete( p_va ); + p_sys->p_va = NULL; +end: /* Fallback to default behaviour */ return avcodec_default_get_format( p_context, pi_fmt ); }