36 #define __STDC_CONSTANT_MACROS
37 #include "libavcodec/avcodec.h"
38 #include "libavutil/imgutils.h"
39 #include "libavutil/mem.h"
45 #ifndef GCONFIG_LIBAV_NEW_FRAME_ALLOC_FN
46 #if LIBAVCODEC_VERSION_MAJOR >= 56
47 #define GCONFIG_LIBAV_NEW_FRAME_ALLOC_FN 1
49 #define GCONFIG_LIBAV_NEW_FRAME_ALLOC_FN 0
53 #ifndef GCONFIG_LIBAV_NEW_DECODE_FN
54 #if LIBAVCODEC_VERSION_MAJOR >= 57
55 #define GCONFIG_LIBAV_NEW_DECODE_FN 1
57 #define GCONFIG_LIBAV_NEW_DECODE_FN 0
61 #ifndef GCONFIG_LIBAV_NEW_DESCRIPTOR
62 #if LIBAVCODEC_VERSION_MAJOR >= 57
63 #define GCONFIG_LIBAV_NEW_DESCRIPTOR 1
65 #define GCONFIG_LIBAV_NEW_DESCRIPTOR 0
69 #ifndef AV_PIX_FMT_FLAG_BE
70 #define AV_PIX_FMT_FLAG_BE PIX_FMT_BE
71 #define AV_PIX_FMT_FLAG_PAL PIX_FMT_PAL
72 #define AV_PIX_FMT_FLAG_BITSTREAM PIX_FMT_BITSTREAM
73 #define AV_PIX_FMT_FLAG_RGB PIX_FMT_RGB
76 static void logger(
void * p ,
int level ,
const char * s , va_list args )
78 const char * class_name = p && *(AVClass**)p ? (*(AVClass**)p)->class_name : "libav" ;
82 static std::vector<char> buffer( 100U ) ;
84 int rc = vsnprintf( &buffer[0] , buffer.size() , s , args ) ;
85 if( rc <= 0 ) rc = 1 , buffer[0] =
'\0' ;
86 size_t lastpos = std::min(static_cast<size_t>(rc),buffer.size()) - 1 ;
87 if( buffer[lastpos] ==
'\n' ) buffer[lastpos] =
'\0' ;
88 text = std::string(class_name) +
": [" + std::string(&buffer[0]) +
"]" ;
91 if( text.find(
"AVCodecContext: [no frame!]") != std::string::npos )
94 if( level <= AV_LOG_ERROR )
95 G_WARNING(
"Gv::AvcReaderStream: libav error: " << text ) ;
96 else if( level <= AV_LOG_WARNING )
97 G_WARNING(
"Gv::AvcReaderStream: libav warning: " << text ) ;
98 else if( level <= AV_LOG_INFO )
99 G_LOG(
"Gv::AvcReaderStream: libav info: " << text ) ;
101 G_DEBUG(
"Gv::AvcReaderStream: libav info: " << text ) ;
120 AVCodecContext * m_cc ;
121 std::string m_sps_pps ;
125 Gv::AvcReaderStreamImp::AvcReaderStreamImp() :
147 if( avcc_p !=
nullptr )
149 m_dx = avcc_p->
sps(0U).
dx() ;
150 m_dy = avcc_p->
sps(0U).
dy() ;
155 av_log_set_callback( logger ) ;
157 av_log_set_level( AV_LOG_DEBUG ) ;
159 av_log_set_level( AV_LOG_VERBOSE ) ;
164 avcodec_register_all() ;
166 m_codec = avcodec_find_decoder( AV_CODEC_ID_H264 ) ;
167 if( m_codec ==
nullptr )
168 throw std::runtime_error(
"avcodec_find_decoder failed" ) ;
173 m_cc = avcodec_alloc_context3( m_codec ) ;
174 G_ASSERT( m_cc !=
nullptr ) ;
175 m_cc->debug |= FF_DEBUG_STARTCODE ;
176 m_cc->debug |= FF_DEBUG_PICT_INFO ;
180 if( avcc_p !=
nullptr )
185 m_sps_pps = avcc_p->
nalus() ;
186 m_cc->extradata =
reinterpret_cast<uint8_t*
>(
const_cast<char*
>(m_sps_pps.data())) ;
187 m_cc->extradata_size = m_sps_pps.size() ;
192 int e = avcodec_open2( m_cc , m_codec ,
nullptr ) ;
194 throw std::runtime_error(
"avcodec_open2 failed: " +
G::Str::fromInt(e) ) ;
202 #if GCONFIG_LIBAV_NEW_FRAME_ALLOC_FN
203 m_frame = av_frame_alloc() ;
204 G_ASSERT( m_frame !=
nullptr ) ;
206 m_frame = avcodec_alloc_frame() ;
207 G_ASSERT( m_frame !=
nullptr ) ;
208 avcodec_get_frame_defaults( m_frame ) ;
213 Gv::AvcReaderStreamImp::~AvcReaderStreamImp()
215 if( m_cc ) avcodec_close(m_cc) , av_free(m_cc) ;
216 #if GCONFIG_LIBAV_NEW_FRAME_ALLOC_FN
217 if( m_frame ) av_frame_free( &m_frame ) ;
219 if( m_frame ) avcodec_free_frame( &m_frame ) ;
257 <<
"data=" << (
const void*)c.data <<
" "
258 <<
"offset=" << c.offset <<
" "
259 <<
"linesize=" << c.linesize <<
" "
260 <<
"step=" << c.step <<
" "
261 <<
"depth=" << c.depth <<
" "
262 <<
"mask=" << c.mask <<
" "
263 <<
"value-shift=" << c.shift <<
" "
264 <<
"eightbit=" << c.eightbit <<
" "
265 <<
"x-shift=" << c.x_shift <<
" "
266 <<
"y-shift=" << c.y_shift ;
273 const AVComponentDescriptor & pfd_comp )
276 const bool big_endian = !!( pfd.flags & AV_PIX_FMT_FLAG_BE ) ;
277 comp.data = frame.data[pfd_comp.plane] ;
278 comp.linesize = frame.linesize[pfd_comp.plane] ;
279 #if GCONFIG_LIBAV_NEW_DESCRIPTOR
280 comp.offset = pfd_comp.offset ;
281 comp.step = pfd_comp.step ;
282 comp.depth = pfd_comp.depth ;
284 comp.offset = pfd_comp.offset_plus1 - 1U ;
285 comp.step = pfd_comp.step_minus1 + 1U ;
286 comp.depth = pfd_comp.depth_minus1 + 1U ;
288 comp.mask = (1U << comp.depth) - 1U ;
289 comp.shift = pfd_comp.shift ;
290 comp.eightbit = (comp.shift + comp.depth) <= 8U ;
291 comp.offset += ( comp.eightbit && big_endian ? 1U : 0U ) ;
296 bool valid_pfd(
const AVPixFmtDescriptor * pfd )
300 pfd->nb_components >= 3U &&
301 !(pfd->flags&AV_PIX_FMT_FLAG_PAL) &&
302 !(pfd->flags&AV_PIX_FMT_FLAG_BITSTREAM) ;
309 const AVPixFmtDescriptor * pfd = av_pix_fmt_desc_get( static_cast<AVPixelFormat>(frame->format) ) ;
310 const char * format_name = pfd ? pfd->name :
"" ;
311 G_DEBUG(
"Gv::AvcReader::init: pixel format " << format_name ) ;
312 if( !valid_pfd(pfd) )
313 throw std::runtime_error( std::string(
"unexpected pixel format [") + format_name +
"]" ) ;
316 m.m_rgb = !!( pfd->flags & AV_PIX_FMT_FLAG_RGB ) ;
317 m.m_big_endian = !!( pfd->flags & AV_PIX_FMT_FLAG_BE ) ;
318 m.m_x_shift = pfd->log2_chroma_w ;
319 m.m_y_shift = pfd->log2_chroma_h ;
322 unsigned int n = std::min( 4U , static_cast<unsigned int>(pfd->nb_components) ) ;
323 for(
unsigned int c = 0U ; c < n ; c++ )
325 m.m_component[c] = make_component( *frame , *pfd , pfd->comp[c] ) ;
331 const bool do_shift = format_name[0] ==
'a' ;
332 const bool do_swap_1_3 = format_name[0] ==
'b' || ( format_name[0] ==
'a' && format_name[1] ==
'b' ) ;
333 const bool do_swap_2_3 = format_name[0] ==
'y' && format_name[1] ==
'v' ;
336 m.m_component[0] = m.m_component[1] ;
337 m.m_component[1] = m.m_component[2] ;
338 m.m_component[2] = m.m_component[3] ;
341 std::swap( m.m_component[0] , m.m_component[2] ) ;
342 else if( do_swap_2_3 )
343 std::swap( m.m_component[1] , m.m_component[2] ) ;
347 m.m_component[1].x_shift = m.m_x_shift ;
348 m.m_component[1].y_shift = m.m_y_shift ;
349 m.m_component[2].x_shift = m.m_x_shift ;
350 m.m_component[2].y_shift = m.m_y_shift ;
352 for(
unsigned int c = 0 ; c < 3U ; c++ )
354 G_DEBUG(
"Gv::AvcReader::init: component " << c <<
": " << m.m_component[c] ) ;
359 void Gv::AvcReader::init(
const unsigned char * p ,
size_t n )
364 std::string nalu = std::string(reinterpret_cast<const char*>(p+4) , n-4U ) ;
365 unsigned int nalu_type =
static_cast<unsigned int>(nalu.at(0U)) & 0x9f ;
367 static int sps_chroma_format_idc = -1 ;
368 if( nalu_type == 7U )
370 G_LOG_S(
"Gv::AvcReader::init: checking sps nalu" ) ;
373 if( ok ) sps_chroma_format_idc = sps.m_chroma_format_idc ;
375 else if( nalu_type == 8U && sps_chroma_format_idc != -1 )
377 G_LOG_S(
"Gv::AvcReader::init: checking pps nalu" ) ;
382 throw std::runtime_error(
"nalu check failed" ) ;
385 m_data.m_component[0].data = nullptr ;
386 m_data.m_component[1].data = nullptr ;
387 m_data.m_component[2].data = nullptr ;
388 G_ASSERT( !valid() ) ;
390 m_data.m_dx = m_stream.dx() ;
391 m_data.m_dy = m_stream.dy() ;
395 av_init_packet( &av_packet ) ;
397 av_packet.data =
const_cast<uint8_t*
>(p) ;
400 AVCodecContext * cc = m_stream.m_imp->m_cc ;
401 AVFrame * frame = m_stream.m_imp->m_frame ;
404 #if GCONFIG_LIBAV_NEW_DECODE_FN
405 int rc = avcodec_send_packet( cc , &av_packet ) ;
406 if( rc < 0 ) G_DEBUG(
"Gv::AvcReader::init: avcodec_send_packet failed: " << rc ) ;
409 rc = avcodec_receive_frame( cc , frame ) ;
410 if( rc == AVERROR(EAGAIN) )
412 G_DEBUG(
"Gv::AvcReader::init: avcodec_receive_frame eagain" ) ;
415 else if( rc == AVERROR_EOF )
417 throw std::runtime_error(
"avcodec_receive_frame eof" ) ;
422 interpret_frame( frame , m_data ) ;
423 m_data.m_dx = cc->width ;
424 m_data.m_dy = cc->height ;
429 ssize_t rc = avcodec_decode_video2( cc , frame , &done , &av_packet ) ;
430 if( rc >= 0 && done )
432 interpret_frame( frame , m_data ) ;
433 m_data.m_dx = cc->width ;
434 m_data.m_dy = cc->height ;
439 G_LOG(
"Gv::AvcReader::init: libav error: avcodec_decode_video2 failed: " << rc ) ;
446 return !!m_stream.m_imp->m_frame->key_frame ;
449 template <
typename Tout>
450 void fill_imp( Tout out_p ,
const Gv::AvcReader & reader ,
int scale ,
bool monochrome_out )
452 const int dx = reader.
dx() ;
453 const int dy = reader.
dy() ;
458 for(
int y = 0 ; y < dy ; y += scale )
461 for(
int x = 0 ; x < dx ; x += scale , ++in_p )
463 *out_p++ = in_p.luma() ;
469 for(
int y = 0 ; y < dy ; y += scale )
472 for(
int x = 0 ; x < dx ; x += scale , ++in_p )
474 *out_p++ = in_p.r() ;
475 *out_p++ = in_p.g() ;
476 *out_p++ = in_p.b() ;
485 for(
int y = 0 ; y < dy ; y += scale )
488 for(
int x = 0 ; x < dx ; x += scale , ++in_p )
490 *out_p++ = in_p.luma() ;
496 for(
int y = 0 ; y < dy ; y += scale )
499 for(
int x = 0 ; x < dx ; x += scale , ++in_p )
501 *out_p++ = in_p.r() ;
502 *out_p++ = in_p.g() ;
503 *out_p++ = in_p.b() ;
512 scale = std::max( 1 , scale ) ;
515 buffer.resize( image_type.
size() ) ;
516 fill_imp( &buffer[0] , *
this , scale , monochrome ) ;
518 G_ASSERT( image_type.
size() == buffer.size() ) ;
static bool available()
Returns true if the decoder library is built in.
bool simple() const
Returns true if the data format is simple enough for the optimised iterator, Gv::AvcReader::SimpleIte...
A decoder for an AVC (aka H.264) video packet.
int dx() const
Returns the image width.
Contains AVC configuration parameters, initialised from an "avcC" file segment or from an SDP "fmtp" ...
static LogOutput * instance()
Returns a pointer to the controlling LogOutput object.
An encapsulation of image type, including width, height and number of channels, with support for a st...
Describes one plane of a Gv::AvcReader image, and points to its data.
int dx() const
Returns the image width as indicated by the first SPS structure, or zero if default constructed...
static std::string fromInt(int i)
Converts int 'i' to a string.
unsigned int dx() const
Returns the picture width in pixels.
static ImageType raw(int dx, int dy, int channels)
Factory function for a raw image type.
int dy() const
Returns the image height.
A Picture Sequence Parameter Set (PPS) structure.
A Sequence Parameter Set (SPS) structure.
~AvcReaderStream()
Destructor.
size_t size() const
Returns the product of dx, dy and channels.
int dy() const
Returns the image height as indicated by the first SPS structure, or zero if default constructed...
AvcReaderStream()
Default constructor.
static bool enabled()
Returns true if test features are enabled.
bool keyframe() const
Returns true if a key frame.
unsigned int dy() const
Returns the picture height in pixels.
A private pimple class for Gv::AvcReaderStream, holding AVCode, AVCodecContext and AVFrame libav obje...
A row iterator for Gv::AvcReader providing r/g/b or y/u/v across a row.
Gr::ImageType fill(std::vector< char > &, int scale=1, bool monochrome=false)
Fills the supplied buffer with RGB or greyscale image data and returns the raw image type...
const Sps & sps(size_t i) const
Returns a reference to the i-th sps structure.
Describes a Gv::AvcReader image, and points to its data via up to four Components.
std::string nalus() const
Returns the NALU byte-stream comprising the four-byte 00-00-00-01 start-code followed by the byte-stu...
An optimised row iterator for Gv::AvcReader when simple().