/*
* Copyright ( c ) 2015 Ludmila Glinskih
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
*/
/**
* draw_horiz_band test .
*/
# include "libavutil/adler32.h"
# include "libavcodec/avcodec.h"
# include "libavformat/avformat.h"
# include "libavutil/imgutils.h"
uint8_t * slice_byte_buffer ;
uint8_t slice_byte_buffer_size ;
int draw_horiz_band_called ;
static void draw_horiz_band ( AVCodecContext * ctx , const AVFrame * fr , int offset [ 4 ] ,
int slice_position , int type , int height )
{
int i ;
const AVPixFmtDescriptor * pix_fmt_desc ;
int chroma_w , chroma_h ;
int shift_slice_position ;
int shift_height ;
draw_horiz_band_called = 1 ;
pix_fmt_desc = av_pix_fmt_desc_get ( ctx - > pix_fmt ) ;
chroma_w = - ( ( - ctx - > width ) > > pix_fmt_desc - > log2_chroma_w ) ;
chroma_h = - ( ( - height ) > > pix_fmt_desc - > log2_chroma_h ) ;
shift_slice_position = - ( ( - slice_position ) > > pix_fmt_desc - > log2_chroma_h ) ;
shift_height = - ( ( - ctx - > height ) > > pix_fmt_desc - > log2_chroma_h ) ;
for ( i = 0 ; i < height ; i + + ) {
memcpy ( slice_byte_buffer + ctx - > width * slice_position + i * ctx - > width ,
fr - > data [ 0 ] + offset [ 0 ] + i * fr - > linesize [ 0 ] , ctx - > width ) ;
}
for ( i = 0 ; i < chroma_h ; i + + ) {
memcpy ( slice_byte_buffer + ctx - > width * ctx - > height + chroma_w * shift_slice_position + i * chroma_w ,
fr - > data [ 1 ] + offset [ 1 ] + i * fr - > linesize [ 1 ] , chroma_w ) ;
}
for ( i = 0 ; i < chroma_h ; i + + ) {
memcpy ( slice_byte_buffer + ctx - > width * ctx - > height + chroma_w * shift_height + chroma_w * shift_slice_position + i * chroma_w ,
fr - > data [ 2 ] + offset [ 2 ] + i * fr - > linesize [ 2 ] , chroma_w ) ;
}
}
static int video_decode ( const char * input_filename )
{
AVCodec * codec = NULL ;
AVCodecContext * ctx = NULL ;
AVCodecParameters * origin_par = NULL ;
uint8_t * byte_buffer = NULL ;
AVFrame * fr = NULL ;
AVPacket * pkt ;
AVFormatContext * fmt_ctx = NULL ;
int number_of_written_bytes ;
int video_stream ;
int byte_buffer_size ;
int result ;
draw_horiz_band_called = 0 ;
result = avformat_open_input ( & fmt_ctx , input_filename , NULL , NULL ) ;
if ( result < 0 ) {
av_log ( NULL , AV_LOG_ERROR , " Can't open file \n " ) ;
return result ;
}
result = avformat_find_stream_info ( fmt_ctx , NULL ) ;
if ( result < 0 ) {
av_log ( NULL , AV_LOG_ERROR , " Can't get stream info \n " ) ;
return result ;
}
video_stream = av_find_best_stream ( fmt_ctx , AVMEDIA_TYPE_VIDEO , - 1 , - 1 , NULL , 0 ) ;
if ( video_stream < 0 ) {
av_log ( NULL , AV_LOG_ERROR , " Can't find video stream in input file \n " ) ;
return - 1 ;
}
origin_par = fmt_ctx - > streams [ video_stream ] - > codecpar ;
codec = avcodec_find_decoder ( origin_par - > codec_id ) ;
if ( ! codec ) {
av_log ( NULL , AV_LOG_ERROR , " Can't find decoder \n " ) ;
return - 1 ;
}
ctx = avcodec_alloc_context3 ( codec ) ;
if ( ! ctx ) {
av_log ( NULL , AV_LOG_ERROR , " Can't allocate decoder context \n " ) ;
return AVERROR ( ENOMEM ) ;
}
result = avcodec_parameters_to_context ( ctx , origin_par ) ;
if ( result ) {
av_log ( NULL , AV_LOG_ERROR , " Can't copy decoder context \n " ) ;
return result ;
}
ctx - > draw_horiz_band = draw_horiz_band ;
ctx - > thread_count = 1 ;
result = avcodec_open2 ( ctx , codec , NULL ) ;
if ( result < 0 ) {
av_log ( ctx , AV_LOG_ERROR , " Can't open decoder \n " ) ;
return result ;
}
fr = av_frame_alloc ( ) ;
if ( ! fr ) {
av_log ( NULL , AV_LOG_ERROR , " Can't allocate frame \n " ) ;
return AVERROR ( ENOMEM ) ;
}
pkt = av_packet_alloc ( ) ;
if ( ! pkt ) {
av_log ( NULL , AV_LOG_ERROR , " Cannot allocate packet \n " ) ;
return AVERROR ( ENOMEM ) ;
}
if ( strcmp ( codec - > name , " flv " ) & & strcmp ( codec - > name , " mpeg4 " ) & & strcmp ( codec - > name , " huffyuv " ) ) {
av_log ( NULL , AV_LOG_ERROR , " Wrong codec \n " ) ;
return - 1 ;
}
byte_buffer_size = av_image_get_buffer_size ( ctx - > pix_fmt , ctx - > width , ctx - > height , 32 ) ;
byte_buffer = av_malloc ( byte_buffer_size ) ;
if ( ! byte_buffer ) {
av_log ( NULL , AV_LOG_ERROR , " Can't allocate buffer \n " ) ;
return AVERROR ( ENOMEM ) ;
}
slice_byte_buffer = av_malloc ( byte_buffer_size ) ;
if ( ! slice_byte_buffer ) {
av_log ( NULL , AV_LOG_ERROR , " Can't allocate buffer \n " ) ;
return AVERROR ( ENOMEM ) ;
}
memset ( slice_byte_buffer , 0 , byte_buffer_size ) ;
slice_byte_buffer_size = byte_buffer_size ;
result = 0 ;
while ( result > = 0 ) {
result = av_read_frame ( fmt_ctx , pkt ) ;
if ( result > = 0 & & pkt - > stream_index ! = video_stream ) {
av_packet_unref ( pkt ) ;
continue ;
}
if ( result < 0 )
result = avcodec_send_packet ( ctx , NULL ) ;
else
result = avcodec_send_packet ( ctx , pkt ) ;
av_packet_unref ( pkt ) ;
if ( result < 0 ) {
av_log ( NULL , AV_LOG_ERROR , " Error submitting a packet for decoding \n " ) ;
return result ;
}
while ( result > = 0 ) {
result = avcodec_receive_frame ( ctx , fr ) ;
if ( result = = AVERROR_EOF )
goto finish ;
else if ( result = = AVERROR ( EAGAIN ) ) {
result = 0 ;
break ;
} else if ( result < 0 ) {
av_log ( NULL , AV_LOG_ERROR , " Error decoding frame \n " ) ;
return result ;
}
number_of_written_bytes = av_image_copy_to_buffer ( byte_buffer , byte_buffer_size ,
( const uint8_t * const * ) fr - > data , ( const int * ) fr - > linesize ,
ctx - > pix_fmt , ctx - > width , ctx - > height , 1 ) ;
if ( number_of_written_bytes < 0 ) {
av_log ( NULL , AV_LOG_ERROR , " Can't copy image to buffer \n " ) ;
return number_of_written_bytes ;
}
if ( draw_horiz_band_called = = 0 ) {
av_log ( NULL , AV_LOG_ERROR , " draw_horiz_band haven't been called! \n " ) ;
return - 1 ;
}
if ( av_adler32_update ( 0 , ( const uint8_t * ) byte_buffer , number_of_written_bytes ) ! =
av_adler32_update ( 0 , ( const uint8_t * ) slice_byte_buffer , number_of_written_bytes ) ) {
av_log ( NULL , AV_LOG_ERROR , " Decoded frames with and without draw_horiz_band are not the same! \n " ) ;
return - 1 ;
}
av_frame_unref ( fr ) ;
}
}
finish :
av_packet_free ( & pkt ) ;
av_frame_free ( & fr ) ;
avformat_close_input ( & fmt_ctx ) ;
avcodec_free_context ( & ctx ) ;
av_freep ( & byte_buffer ) ;
av_freep ( & slice_byte_buffer ) ;
return 0 ;
}
int main ( int argc , char * * argv )
{
if ( argc < 2 )
{
av_log ( NULL , AV_LOG_ERROR , " Incorrect input: expected %s <name of a video file> \n Note that test works only for huffyuv, flv and mpeg4 decoders \n " , argv [ 0 ] ) ;
return 1 ;
}
if ( video_decode ( argv [ 1 ] ) ! = 0 )
return 1 ;
return 0 ;
}