@ -47,17 +47,35 @@ typedef struct QSVH2645Context {
int load_plugin ;
// the filter for converting to Annex B
AVBit Stream Filter Context * bsf ;
AVBSFContext * bsf ;
AVFifoBuffer * packet_fifo ;
AVPacket pkt_filtered ;
} QSVH2645Context ;
static void qsv_clear_buffers ( QSVH2645Context * s )
{
AVPacket pkt ;
while ( av_fifo_size ( s - > packet_fifo ) > = sizeof ( pkt ) ) {
av_fifo_generic_read ( s - > packet_fifo , & pkt , sizeof ( pkt ) , NULL ) ;
av_packet_unref ( & pkt ) ;
}
av_bsf_free ( & s - > bsf ) ;
av_packet_unref ( & s - > pkt_filtered ) ;
}
static av_cold int qsv_decode_close ( AVCodecContext * avctx )
{
QSVH2645Context * s = avctx - > priv_data ;
ff_qsv_decode_close ( & s - > qsv ) ;
av_bitstream_filter_close ( s - > bsf ) ;
qsv_clear_buffers ( s ) ;
av_fifo_free ( s - > packet_fifo ) ;
return 0 ;
}
@ -81,16 +99,15 @@ static av_cold int qsv_decode_init(AVCodecContext *avctx)
return AVERROR ( ENOMEM ) ;
}
}
s - > packet_fifo = av_fifo_alloc ( sizeof ( AVPacket ) ) ;
if ( ! s - > packet_fifo ) {
ret = AVERROR ( ENOMEM ) ;
goto fail ;
}
if ( avctx - > codec_id = = AV_CODEC_ID_H264 ) {
s - > bsf = av_bitstream_filter_init ( " h264_mp4toannexb " ) ;
//regarding ticks_per_frame description, should be 2 for h.264:
avctx - > ticks_per_frame = 2 ;
} else
s - > bsf = av_bitstream_filter_init ( " hevc_mp4toannexb " ) ;
if ( ! s - > bsf ) {
ret = AVERROR ( ENOMEM ) ;
goto fail ;
}
return 0 ;
@ -99,42 +116,101 @@ fail:
return ret ;
}
static int qsv_init_bsf ( AVCodecContext * avctx , QSVH2645Context * s )
{
const char * filter_name = avctx - > codec_id = = AV_CODEC_ID_HEVC ?
" hevc_mp4toannexb " : " h264_mp4toannexb " ;
const AVBitStreamFilter * filter ;
int ret ;
if ( s - > bsf )
return 0 ;
filter = av_bsf_get_by_name ( filter_name ) ;
if ( ! filter )
return AVERROR_BUG ;
ret = av_bsf_alloc ( filter , & s - > bsf ) ;
if ( ret < 0 )
return ret ;
ret = avcodec_parameters_from_context ( s - > bsf - > par_in , avctx ) ;
if ( ret < 0 )
return ret ;
s - > bsf - > time_base_in = avctx - > time_base ;
ret = av_bsf_init ( s - > bsf ) ;
if ( ret < 0 )
return ret ;
return ret ;
}
static int qsv_decode_frame ( AVCodecContext * avctx , void * data ,
int * got_frame , AVPacket * avpkt )
{
QSVH2645Context * s = avctx - > priv_data ;
AVFrame * frame = data ;
int ret ;
uint8_t * p_filtered = NULL ;
int n_filtered = NULL ;
AVPacket pkt_filtered = { 0 } ;
/* make sure the bitstream filter is initialized */
ret = qsv_init_bsf ( avctx , s ) ;
if ( ret < 0 )
return ret ;
/* buffer the input packet */
if ( avpkt - > size ) {
if ( avpkt - > size > 3 & & ! avpkt - > data [ 0 ] & &
! avpkt - > data [ 1 ] & & ! avpkt - > data [ 2 ] & & 1 = = avpkt - > data [ 3 ] ) {
/* we already have annex-b prefix */
return ff_qsv_decode ( avctx , & s - > qsv , frame , got_frame , avpkt ) ;
AVPacket input_ref = { 0 } ;
} else {
/* no annex-b prefix. try to restore: */
ret = av_bitstream_filter_filter ( s - > bsf , avctx , " private_spspps_buf " ,
& p_filtered , & n_filtered ,
avpkt - > data , avpkt - > size , 0 ) ;
if ( ret > = 0 ) {
pkt_filtered . pts = avpkt - > pts ;
pkt_filtered . data = p_filtered ;
pkt_filtered . size = n_filtered ;
ret = ff_qsv_decode ( avctx , & s - > qsv , frame , got_frame , & pkt_filtered ) ;
if ( p_filtered ! = avpkt - > data )
av_free ( p_filtered ) ;
return ret > 0 ? avpkt - > size : ret ;
if ( av_fifo_space ( s - > packet_fifo ) < sizeof ( input_ref ) ) {
ret = av_fifo_realloc2 ( s - > packet_fifo ,
av_fifo_size ( s - > packet_fifo ) + sizeof ( input_ref ) ) ;
if ( ret < 0 )
return ret ;
}
ret = av_packet_ref ( & input_ref , avpkt ) ;
if ( ret < 0 )
return ret ;
av_fifo_generic_write ( s - > packet_fifo , & input_ref , sizeof ( input_ref ) , NULL ) ;
}
/* process buffered data */
while ( ! * got_frame ) {
/* prepare the input data -- convert to Annex B if needed */
if ( s - > pkt_filtered . size < = 0 ) {
AVPacket input_ref ;
/* no more data */
if ( av_fifo_size ( s - > packet_fifo ) < sizeof ( AVPacket ) )
return avpkt - > size ? avpkt - > size : ff_qsv_decode ( avctx , & s - > qsv , frame , got_frame , avpkt ) ;
av_packet_unref ( & s - > pkt_filtered ) ;
av_fifo_generic_read ( s - > packet_fifo , & input_ref , sizeof ( input_ref ) , NULL ) ;
ret = av_bsf_send_packet ( s - > bsf , & input_ref ) ;
if ( ret < 0 ) {
av_packet_unref ( & input_ref ) ;
return ret ;
}
ret = av_bsf_receive_packet ( s - > bsf , & s - > pkt_filtered ) ;
if ( ret < 0 )
av_packet_move_ref ( & s - > pkt_filtered , & input_ref ) ;
else
av_packet_unref ( & input_ref ) ;
}
ret = ff_qsv_decode ( avctx , & s - > qsv , frame , got_frame , & s - > pkt_filtered ) ;
if ( ret < 0 )
return ret ;
s - > pkt_filtered . size - = ret ;
s - > pkt_filtered . data + = ret ;
}
return ff_qsv_decode ( avctx , & s - > qsv , frame , got_frame , avpkt ) ;
return avpkt - > size ;
}
static void qsv_decode_flush ( AVCodecContext * avctx )