mirror of
				https://github.com/nyanmisaka/ffmpeg-rockchip.git
				synced 2025-10-31 04:26:37 +08:00 
			
		
		
		
	Merge remote-tracking branch 'hexene/stagefright'
* hexene/stagefright: libstagefright: avoid memory leak libstagefright: support more output pixel formats libstagefright: avoid potential deadlock on output MediaBuffer libstagefright: explicitly set positive timestamps as stagefright expects them so Merge branches 'stagefright' and 'stagefright-test' into stagefright-test Merged-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
		
							
								
								
									
										2
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| @@ -3201,7 +3201,7 @@ enabled libschroedinger && require_pkg_config schroedinger-1.0 schroedinger/schr | ||||
| enabled libspeex   && require  libspeex speex/speex.h speex_decoder_init -lspeex | ||||
| enabled libstagefright_h264  && require_cpp libstagefright_h264 "binder/ProcessState.h media/stagefright/MetaData.h | ||||
|     media/stagefright/MediaBufferGroup.h media/stagefright/MediaDebug.h media/stagefright/MediaDefs.h | ||||
|     media/stagefright/OMXClient.h media/stagefright/OMXCodec.h" android::OMXClient -lstagefright -lmedia -lutils -lbinder | ||||
|     media/stagefright/OMXClient.h media/stagefright/OMXCodec.h" android::OMXClient -lstagefright -lmedia -lutils -lbinder -lgnustl_static | ||||
| enabled libtheora  && require  libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg | ||||
| enabled libutvideo    && require_cpp utvideo "stdint.h stdlib.h utvideo/utvideo.h utvideo/Codec.h" 'CCodec*' -lutvideo -lstdc++ | ||||
| enabled libv4l2    && require_pkg_config libv4l2 libv4l2.h v4l2_ioctl | ||||
|   | ||||
| @@ -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->mbuffer; | ||||
|     ret_frame = frame->vframe; | ||||
|     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 (s->prev_frame) { | ||||
|         avctx->release_buffer(avctx, s->prev_frame); | ||||
|         av_freep(&s->prev_frame); | ||||
|     } | ||||
|  | ||||
|     if (!avctx->width || !avctx->height || avctx->width > w || avctx->height > h) { | ||||
|         avctx->width  = w; | ||||
|         avctx->height = h; | ||||
|     } | ||||
|  | ||||
|     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; | ||||
|   | ||||
| @@ -28,6 +28,7 @@ TOOLCHAIN=`echo $NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/*-x86` | ||||
| export PATH=$TOOLCHAIN/bin:$PATH | ||||
| ANDROID_SOURCE=../android-source | ||||
| ANDROID_LIBS=../android-libs | ||||
| ABI="armeabi-v7a" | ||||
|  | ||||
| rm -rf ../build/stagefright | ||||
| mkdir -p ../build/stagefright | ||||
| @@ -40,12 +41,11 @@ FLAGS="$FLAGS --disable-avdevice --disable-decoder=h264 --disable-decoder=h264_v | ||||
| EXTRA_CFLAGS="-I$ANDROID_SOURCE/frameworks/base/include -I$ANDROID_SOURCE/system/core/include" | ||||
| EXTRA_CFLAGS="$EXTRA_CFLAGS -I$ANDROID_SOURCE/frameworks/base/media/libstagefright" | ||||
| EXTRA_CFLAGS="$EXTRA_CFLAGS -I$ANDROID_SOURCE/frameworks/base/include/media/stagefright/openmax" | ||||
| EXTRA_CFLAGS="$EXTRA_CFLAGS -I$NDK/sources/cxx-stl/system/include" | ||||
| EXTRA_CFLAGS="$EXTRA_CFLAGS -I$NDK/sources/cxx-stl/gnu-libstdc++/include -I$NDK/sources/cxx-stl/gnu-libstdc++/libs/$ABI/include" | ||||
|  | ||||
| EXTRA_CFLAGS="$EXTRA_CFLAGS -march=armv7-a -mfloat-abi=softfp -mfpu=neon" | ||||
| EXTRA_LDFLAGS="-Wl,--fix-cortex-a8 -L$ANDROID_LIBS -Wl,-rpath-link,$ANDROID_LIBS" | ||||
| EXTRA_LDFLAGS="-Wl,--fix-cortex-a8 -L$ANDROID_LIBS -Wl,-rpath-link,$ANDROID_LIBS -L$NDK/sources/cxx-stl/gnu-libstdc++/libs/$ABI" | ||||
| EXTRA_CXXFLAGS="-Wno-multichar -fno-exceptions -fno-rtti" | ||||
| ABI="armeabi-v7a" | ||||
| DEST="$DEST/$ABI" | ||||
| FLAGS="$FLAGS --prefix=$DEST" | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Michael Niedermayer
					Michael Niedermayer