@ -31,6 +31,7 @@
# include <media/stagefright/OMXCodec.h>
# include <utils/List.h>
# include <new>
# include <map>
extern " C " {
# include "avcodec.h"
@ -47,8 +48,12 @@ struct Frame {
int64_t time ;
int key ;
uint8_t * buffer ;
MediaBuffer * mbuffer ;
int32_t w , h ;
AVFrame * vframe ;
} ;
struct TimeStamp {
int64_t pts ;
int64_t reordered_opaque ;
} ;
class CustomSource ;
@ -68,7 +73,9 @@ struct StagefrightContext {
bool source_done ;
volatile sig_atomic_t thread_started , thread_exited , stop_decode ;
AVFrame ret_frame ;
AVFrame * prev_frame ;
std : : map < int64_t , TimeStamp > * ts_map ;
int64_t frame_index ;
uint8_t * dummy_buf ;
int dummy_bufsize ;
@ -146,9 +153,16 @@ void* decode_thread(void *arg)
{
AVCodecContext * avctx = ( AVCodecContext * ) arg ;
StagefrightContext * s = ( StagefrightContext * ) avctx - > priv_data ;
const AVPixFmtDescriptor * pix_desc = & av_pix_fmt_descriptors [ avctx - > pix_fmt ] ;
Frame * frame ;
MediaBuffer * buffer ;
int32_t w , h ;
int decode_done = 0 ;
int ret ;
int src_linesize [ 3 ] ;
const uint8_t * src_data [ 3 ] ;
int64_t out_frame_index = 0 ;
do {
buffer = NULL ;
frame = ( Frame * ) av_mallocz ( sizeof ( Frame ) ) ;
@ -157,14 +171,61 @@ void* decode_thread(void *arg)
frame - > status = AVERROR ( ENOMEM ) ;
decode_done = 1 ;
s - > end_frame = NULL ;
} else {
frame - > status = ( * s - > decoder ) - > read ( & buffer ) ;
if ( frame - > status = = OK ) {
sp < MetaData > outFormat = ( * s - > decoder ) - > getFormat ( ) ;
outFormat - > findInt32 ( kKeyWidth , & frame - > w ) ;
outFormat - > findInt32 ( kKeyHeight , & frame - > h ) ;
frame - > size = buffer - > range_length ( ) ;
frame - > mbuffer = buffer ;
goto push_frame ;
}
frame - > status = ( * s - > decoder ) - > read ( & buffer ) ;
if ( frame - > status = = OK ) {
sp < MetaData > outFormat = ( * s - > decoder ) - > getFormat ( ) ;
outFormat - > findInt32 ( kKeyWidth , & w ) ;
outFormat - > findInt32 ( kKeyHeight , & h ) ;
frame - > vframe = ( AVFrame * ) av_mallocz ( sizeof ( AVFrame ) ) ;
if ( ! frame - > vframe ) {
frame - > status = AVERROR ( ENOMEM ) ;
decode_done = 1 ;
buffer - > release ( ) ;
goto push_frame ;
}
ret = avctx - > get_buffer ( avctx , frame - > vframe ) ;
if ( ret < 0 ) {
av_log ( avctx , AV_LOG_ERROR , " get_buffer() failed \n " ) ;
frame - > status = ret ;
decode_done = 1 ;
buffer - > release ( ) ;
goto push_frame ;
}
// The OMX.SEC decoder doesn't signal the modified width/height
if ( s - > decoder_component & & ! strncmp ( s - > decoder_component , " OMX.SEC " , 7 ) & &
( w & 15 | | h & 15 ) ) {
if ( ( ( w + 15 ) & ~ 15 ) * ( ( h + 15 ) & ~ 15 ) * 3 / 2 = = buffer - > range_length ( ) ) {
w = ( w + 15 ) & ~ 15 ;
h = ( h + 15 ) & ~ 15 ;
}
}
if ( ! avctx - > width | | ! avctx - > height | | avctx - > width > w | | avctx - > height > h ) {
avctx - > width = w ;
avctx - > height = h ;
}
src_linesize [ 0 ] = av_image_get_linesize ( avctx - > pix_fmt , w , 0 ) ;
src_linesize [ 1 ] = av_image_get_linesize ( avctx - > pix_fmt , w , 1 ) ;
src_linesize [ 2 ] = av_image_get_linesize ( avctx - > pix_fmt , w , 2 ) ;
src_data [ 0 ] = ( uint8_t * ) buffer - > data ( ) ;
src_data [ 1 ] = src_data [ 0 ] + src_linesize [ 0 ] * h ;
src_data [ 2 ] = src_data [ 1 ] + src_linesize [ 1 ] * - ( - h > > pix_desc - > log2_chroma_h ) ;
av_image_copy ( frame - > vframe - > data , frame - > vframe - > linesize ,
src_data , src_linesize ,
avctx - > pix_fmt , avctx - > width , avctx - > height ) ;
buffer - > meta_data ( ) - > findInt64 ( kKeyTime , & out_frame_index ) ;
if ( out_frame_index & & s - > ts_map - > count ( out_frame_index ) > 0 ) {
frame - > vframe - > pts = ( * s - > ts_map ) [ out_frame_index ] . pts ;
frame - > vframe - > reordered_opaque = ( * s - > ts_map ) [ out_frame_index ] . reordered_opaque ;
s - > ts_map - > erase ( out_frame_index ) ;
}
buffer - > release ( ) ;
} else if ( frame - > status = = INFO_FORMAT_CHANGED ) {
if ( buffer )
buffer - > release ( ) ;
@ -173,7 +234,7 @@ void* decode_thread(void *arg)
} else {
decode_done = 1 ;
}
}
push_frame :
while ( true ) {
pthread_mutex_lock ( & s - > out_mutex ) ;
if ( s - > out_queue - > size ( ) > = 10 ) {
@ -234,10 +295,11 @@ static av_cold int Stagefright_init(AVCodecContext *avctx)
* s - > source = new CustomSource ( avctx , meta ) ;
s - > in_queue = new List < Frame * > ;
s - > out_queue = new List < Frame * > ;
s - > ts_map = new std : : map < int64_t , TimeStamp > ;
s - > client = new OMXClient ;
s - > end_frame = ( Frame * ) av_mallocz ( sizeof ( Frame ) ) ;
if ( s - > source = = NULL | | ! s - > in_queue | | ! s - > out_queue | | ! s - > client | |
! s - > end_frame ) {
! s - > ts_map | | ! s - > end_frame ) {
ret = AVERROR ( ENOMEM ) ;
goto fail ;
}
@ -264,6 +326,10 @@ static av_cold int Stagefright_init(AVCodecContext *avctx)
if ( colorFormat = = OMX_QCOM_COLOR_FormatYVU420SemiPlanar | |
colorFormat = = OMX_COLOR_FormatYUV420SemiPlanar )
avctx - > pix_fmt = PIX_FMT_NV21 ;
else if ( colorFormat = = OMX_COLOR_FormatYCbYCr )
avctx - > pix_fmt = PIX_FMT_YUYV422 ;
else if ( colorFormat = = OMX_COLOR_FormatCbYCrY )
avctx - > pix_fmt = PIX_FMT_UYVY422 ;
else
avctx - > pix_fmt = PIX_FMT_YUV420P ;
@ -282,6 +348,7 @@ fail:
av_freep ( & s - > end_frame ) ;
delete s - > in_queue ;
delete s - > out_queue ;
delete s - > ts_map ;
delete s - > client ;
return ret ;
}
@ -291,16 +358,10 @@ static int Stagefright_decode_frame(AVCodecContext *avctx, void *data,
{
StagefrightContext * s = ( StagefrightContext * ) avctx - > priv_data ;
Frame * frame ;
MediaBuffer * mbuffer ;
status_t status ;
size_t size ;
uint8_t * buf ;
const uint8_t * src_data [ 3 ] ;
int w , h ;
int src_linesize [ 3 ] ;
int orig_size = avpkt - > size ;
AVPacket pkt = * avpkt ;
int ret ;
AVFrame * ret_frame ;
if ( ! s - > thread_started ) {
pthread_create ( & s - > decode_thread_id , NULL , & decode_thread , avctx ) ;
@ -326,10 +387,6 @@ static int Stagefright_decode_frame(AVCodecContext *avctx, void *data,
if ( avpkt - > data ) {
frame - > status = OK ;
frame - > size = avpkt - > size ;
// Stagefright can't handle negative timestamps -
// if needed, work around this by offsetting them manually?
if ( avpkt - > pts > = 0 )
frame - > time = avpkt - > pts ;
frame - > key = avpkt - > flags & AV_PKT_FLAG_KEY ? 1 : 0 ;
frame - > buffer = ( uint8_t * ) av_malloc ( avpkt - > size ) ;
if ( ! frame - > buffer ) {
@ -343,6 +400,12 @@ static int Stagefright_decode_frame(AVCodecContext *avctx, void *data,
frame - > size = orig_size ;
}
memcpy ( frame - > buffer , ptr , orig_size ) ;
if ( avpkt = = & pkt )
av_free ( avpkt - > data ) ;
frame - > time = + + s - > frame_index ;
( * s - > ts_map ) [ s - > frame_index ] . pts = avpkt - > pts ;
( * s - > ts_map ) [ s - > frame_index ] . reordered_opaque = avctx - > reordered_opaque ;
} else {
frame - > status = ERROR_END_OF_STREAM ;
s - > source_done = true ;
@ -381,11 +444,8 @@ static int Stagefright_decode_frame(AVCodecContext *avctx, void *data,
s - > out_queue - > erase ( s - > out_queue - > begin ( ) ) ;
pthread_mutex_unlock ( & s - > out_mutex ) ;
mbuffer = frame - > mbuff er ;
ret_frame = frame - > vfra me;
status = frame - > status ;
size = frame - > size ;
w = frame - > w ;
h = frame - > h ;
av_freep ( & frame ) ;
if ( status = = ERROR_END_OF_STREAM )
@ -397,46 +457,15 @@ static int Stagefright_decode_frame(AVCodecContext *avctx, void *data,
return - 1 ;
}
// The OMX.SEC decoder doesn't signal the modified width/height
if ( s - > decoder_component & & ! strncmp ( s - > decoder_component , " OMX.SEC " , 7 ) & &
( w & 15 | | h & 15 ) ) {
if ( ( ( w + 15 ) & ~ 15 ) * ( ( h + 15 ) & ~ 15 ) * 3 / 2 = = size ) {
w = ( w + 15 ) & ~ 15 ;
h = ( h + 15 ) & ~ 15 ;
}
}
if ( ! avctx - > width | | ! avctx - > height | | avctx - > width > w | | avctx - > height > h ) {
avctx - > width = w ;
avctx - > height = h ;
if ( s - > prev_frame ) {
avctx - > release_buffer ( avctx , s - > prev_frame ) ;
av_freep ( & s - > prev_frame ) ;
}
ret = avctx - > reget_buffer ( avctx , & s - > ret_frame ) ;
if ( ret < 0 ) {
av_log ( avctx , AV_LOG_ERROR , " reget buffer() failed \n " ) ;
goto end ;
}
src_linesize [ 0 ] = w ;
if ( avctx - > pix_fmt = = PIX_FMT_YUV420P )
src_linesize [ 1 ] = src_linesize [ 2 ] = w / 2 ;
else if ( avctx - > pix_fmt = = PIX_FMT_NV21 )
src_linesize [ 1 ] = w ;
buf = ( uint8_t * ) mbuffer - > data ( ) ;
src_data [ 0 ] = buf ;
src_data [ 1 ] = buf + src_linesize [ 0 ] * h ;
src_data [ 2 ] = src_data [ 1 ] + src_linesize [ 1 ] * h / 2 ;
av_image_copy ( s - > ret_frame . data , s - > ret_frame . linesize ,
src_data , src_linesize ,
avctx - > pix_fmt , avctx - > width , avctx - > height ) ;
s - > prev_frame = ret_frame ;
* data_size = sizeof ( AVFrame ) ;
* ( AVFrame * ) data = s - > ret_frame ;
ret = orig_size ;
end :
mbuffer - > release ( ) ;
return ret ;
* ( AVFrame * ) data = * ret_frame ;
return orig_size ;
}
static av_cold int Stagefright_close ( AVCodecContext * avctx )
@ -453,8 +482,10 @@ static av_cold int Stagefright_close(AVCodecContext *avctx)
while ( ! s - > out_queue - > empty ( ) ) {
frame = * s - > out_queue - > begin ( ) ;
s - > out_queue - > erase ( s - > out_queue - > begin ( ) ) ;
if ( frame - > size )
frame - > mbuffer - > release ( ) ;
if ( frame - > vframe ) {
avctx - > release_buffer ( avctx , frame - > vframe ) ;
av_freep ( & frame - > vframe ) ;
}
av_freep ( & frame ) ;
}
pthread_mutex_unlock ( & s - > out_mutex ) ;
@ -484,8 +515,10 @@ static av_cold int Stagefright_close(AVCodecContext *avctx)
pthread_join ( s - > decode_thread_id , NULL ) ;
if ( s - > ret_frame . data [ 0 ] )
avctx - > release_buffer ( avctx , & s - > ret_frame ) ;
if ( s - > prev_frame ) {
avctx - > release_buffer ( avctx , s - > prev_frame ) ;
av_freep ( & s - > prev_frame ) ;
}
s - > thread_started = false ;
}
@ -501,8 +534,10 @@ static av_cold int Stagefright_close(AVCodecContext *avctx)
while ( ! s - > out_queue - > empty ( ) ) {
frame = * s - > out_queue - > begin ( ) ;
s - > out_queue - > erase ( s - > out_queue - > begin ( ) ) ;
if ( frame - > size )
frame - > mbuffer - > release ( ) ;
if ( frame - > vframe ) {
avctx - > release_buffer ( avctx , frame - > vframe ) ;
av_freep ( & frame - > vframe ) ;
}
av_freep ( & frame ) ;
}
@ -523,6 +558,7 @@ static av_cold int Stagefright_close(AVCodecContext *avctx)
delete s - > in_queue ;
delete s - > out_queue ;
delete s - > ts_map ;
delete s - > client ;
delete s - > decoder ;
delete s - > source ;