diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2011-09-14 01:23:16 +0200 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2011-09-14 01:23:16 +0200 |
commit | 15240feb992b6b41ca4afba928b9cb6edb0dc9fb (patch) | |
tree | 32426c5114bb571a7dba06412ac737a66c1bdd0a | |
parent | f27f68eb4f7cb43a4d023ce5d1ebd2292313bd9f (diff) | |
parent | 9c29ab58517cae8d56c7ed7fd5070d8f8c8d429e (diff) | |
download | ffmpeg-15240feb992b6b41ca4afba928b9cb6edb0dc9fb.tar.gz |
Merge remote-tracking branch 'hexene/scratchpad'
* hexene/scratchpad:
Move & Rename buildscript, remove tabs
Fix regular build
Support (H/W accelerated) H.264 decoding on Android via Stagefright
Add build-script for Android
C++ Support ;)
Conflicts:
Changelog
Makefile
configure
libavcodec/Makefile
libavcodec/allcodecs.c
libavcodec/version.h
Merged-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r-- | Changelog | 2 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | common.mak | 7 | ||||
-rwxr-xr-x | configure | 94 | ||||
-rw-r--r-- | libavcodec/Makefile | 1 | ||||
-rw-r--r-- | libavcodec/allcodecs.c | 1 | ||||
-rw-r--r-- | libavcodec/libstagefright.cpp | 516 | ||||
-rw-r--r-- | libavcodec/version.h | 2 | ||||
-rw-r--r-- | tools/build_libstagefright | 41 |
9 files changed, 655 insertions, 11 deletions
@@ -51,6 +51,8 @@ easier to use. The changes are: - Speex encoder via libspeex - JSON output in ffprobe - WTV muxer +- C++ Support +- H.264 Decoding on Android via Stagefright version 0.8: @@ -2,13 +2,13 @@ MAIN_MAKEFILE=1 include config.mak vpath %.c $(SRC_PATH) +vpath %.cpp $(SRC_PATH) vpath %.h $(SRC_PATH) vpath %.S $(SRC_PATH) vpath %.asm $(SRC_PATH) vpath %.v $(SRC_PATH) vpath %.texi $(SRC_PATH) - PROGS-$(CONFIG_FFMPEG) += ffmpeg PROGS-$(CONFIG_AVCONV) += avconv PROGS-$(CONFIG_FFPLAY) += ffplay diff --git a/common.mak b/common.mak index 0b44034ca1..bad86fde3b 100644 --- a/common.mak +++ b/common.mak @@ -10,7 +10,7 @@ ifndef SUBDIR ifndef V Q = @ ECHO = printf "$(1)\t%s\n" $(2) -BRIEF = CC AS YASM AR LD HOSTCC STRIP CP +BRIEF = CC CXX AS YASM AR LD HOSTCC STRIP CP SILENT = DEPCC YASMDEP RM RANLIB MSG = $@ M = @$(call ECHO,$(TAG),$@); @@ -27,6 +27,7 @@ IFLAGS := -I. -I$(SRC_PATH)/ CPPFLAGS := $(IFLAGS) $(CPPFLAGS) CFLAGS += $(ECFLAGS) CCFLAGS = $(CFLAGS) +CXXFLAGS := $(CFLAGS) $(CXXFLAGS) YASMFLAGS += $(IFLAGS) -I$(SRC_PATH)/libavutil/x86/ -Pconfig.asm HOSTCFLAGS += $(IFLAGS) LDFLAGS := $(ALLFFLIBS:%=-Llib%) $(LDFLAGS) @@ -37,11 +38,15 @@ define COMPILE endef COMPILE_C = $(call COMPILE,CC) +COMPILE_CXX = $(call COMPILE,CXX) COMPILE_S = $(call COMPILE,AS) %.o: %.c $(COMPILE_C) +%.o: %.cpp + $(COMPILE_CXX) + %.o: %.S $(COMPILE_S) @@ -179,6 +179,7 @@ External library support: --enable-librtmp enable RTMP[E] support via librtmp [no] --enable-libschroedinger enable Dirac support via libschroedinger [no] --enable-libspeex enable Speex encoding and decoding via libspeex [no] + --enable-libstagefright-h264 enable H.264 decoding via libstagefright [no] --enable-libtheora enable Theora encoding via libtheora [no] --enable-libvo-aacenc enable AAC encoding via libvo-aacenc [no] --enable-libvo-amrwbenc enable AMR-WB encoding via libvo-amrwbenc [no] @@ -205,12 +206,14 @@ Advanced options (experts only): --ar=AR use archive tool AR [$ar_default] --as=AS use assembler AS [$as_default] --cc=CC use C compiler CC [$cc_default] + --cxx=CXX use C compiler CXX [$cxx_default] --ld=LD use linker LD --host-cc=HOSTCC use host C compiler HOSTCC --host-cflags=HCFLAGS use HCFLAGS when compiling for host --host-ldflags=HLDFLAGS use HLDFLAGS when linking for host --host-libs=HLIBS use libs HLIBS when linking for host --extra-cflags=ECFLAGS add ECFLAGS to CFLAGS [$CFLAGS] + --extra-cxxflags=ECFLAGS add ECFLAGS to CXXFLAGS [$CXXFLAGS] --extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS [$LDFLAGS] --extra-libs=ELIBS add ELIBS [$ELIBS] --extra-version=STRING version string suffix [] @@ -582,6 +585,10 @@ add_cflags(){ append CFLAGS $($filter_cflags "$@") } +add_cxxflags(){ + append CXXFLAGS $($filter_cflags "$@") +} + add_asflags(){ append ASFLAGS $($filter_asflags "$@") } @@ -606,6 +613,13 @@ check_cc(){ check_cmd $cc $CPPFLAGS $CFLAGS "$@" -c -o $TMPO $TMPC } +check_cxx(){ + log check_cxx "$@" + cat > $TMPCPP + log_file $TMPCPP + check_cmd $cxx $CPPFLAGS $CFLAGS $CXXFLAGS "$@" -c -o $TMPO $TMPCPP +} + check_cpp(){ log check_cpp "$@" cat > $TMPC @@ -641,12 +655,14 @@ check_yasm(){ check_ld(){ log check_ld "$@" + type=$1 + shift 1 flags='' libs='' for f; do test "${f}" = "${f#-l}" && flags="$flags $f" || libs="$libs $f" done - check_cc $($filter_cflags $flags) || return + check_$type $($filter_cflags $flags) || return check_cmd $ld $LDFLAGS $flags -o $TMPE $TMPO $libs $extralibs } @@ -666,9 +682,17 @@ int x; EOF } +check_cxxflags(){ + log check_cxxflags "$@" + set -- $($filter_cflags "$@") + check_cxx "$@" <<EOF && append CXXFLAGS "$@" +int x; +EOF +} + test_ldflags(){ log test_ldflags "$@" - check_ld "$@" <<EOF + check_ld "cc" "$@" <<EOF int main(void){ return 0; } EOF } @@ -694,7 +718,7 @@ check_func(){ func=$1 shift disable $func - check_ld "$@" <<EOF && enable $func + check_ld "cc" "$@" <<EOF && enable $func extern int $func(); int main(void){ $func(); } EOF @@ -705,7 +729,7 @@ check_mathfunc(){ func=$1 shift disable $func - check_ld "$@" <<EOF && enable $func + check_ld "cc" "$@" <<EOF && enable $func #include <math.h> float foo(float f) { return $func(f); } int main(void){ return (int) foo; } @@ -725,7 +749,26 @@ check_func_headers(){ echo "long check_$func(void) { return (long) $func; }" done echo "int main(void) { return 0; }" - } | check_ld "$@" && enable $funcs && enable_safe $headers + } | check_ld "cc" "$@" && enable $funcs && enable_safe $headers +} + +check_class_headers_cpp(){ + log check_class_headers_cpp "$@" + headers=$1 + classes=$2 + shift 2 + { + for hdr in $headers; do + echo "#include <$hdr>" + done + echo "int main(void) { " + i=1 + for class in $classes; do + echo "$class obj$i;" + i=$(expr $i + 1) + done + echo "return 0; }" + } | check_ld "cxx" "$@" && enable $funcs && enable_safe $headers } check_cpp_condition(){ @@ -757,6 +800,14 @@ check_lib2(){ check_func_headers "$headers" "$funcs" "$@" && add_extralibs "$@" } +check_lib_cpp(){ + log check_lib_cpp "$@" + headers="$1" + classes="$2" + shift 2 + check_class_headers_cpp "$headers" "$classes" "$@" && add_extralibs "$@" +} + check_pkg_config(){ log check_pkg_config "$@" pkg="$1" @@ -772,7 +823,7 @@ check_pkg_config(){ } check_exec(){ - check_ld "$@" && { enabled cross_compile || $TMPE >> $logfile 2>&1; } + check_ld "cc" "$@" && { enabled cross_compile || $TMPE >> $logfile 2>&1; } } check_exec_crash(){ @@ -852,6 +903,14 @@ require2(){ check_lib2 "$headers" $func "$@" || die "ERROR: $name not found" } +require_cpp(){ + name="$1" + headers="$2" + classes="$3" + shift 3 + check_lib_cpp "$headers" "$classes" "$@" || die "ERROR: $name not found" +} + require_pkg_config(){ pkg="$1" check_pkg_config "$@" || die "ERROR: $pkg not found" @@ -947,6 +1006,7 @@ CONFIG_LIST=" librtmp libschroedinger libspeex + libstagefright_h264 libtheora libvo_aacenc libvo_amrwbenc @@ -1183,6 +1243,7 @@ CMDLINE_SET=" cc cpu cross_prefix + cxx dep_cc extra_version host_cc @@ -1208,6 +1269,7 @@ CMDLINE_SET=" CMDLINE_APPEND=" extra_cflags + extra_cxxflags " # code dependency declarations @@ -1430,6 +1492,7 @@ libschroedinger_decoder_deps="libschroedinger" libschroedinger_encoder_deps="libschroedinger" libspeex_decoder_deps="libspeex" libspeex_encoder_deps="libspeex" +libstagefright_h264_decoder_deps="libstagefright_h264" libtheora_encoder_deps="libtheora" libvo_aacenc_encoder_deps="libvo_aacenc" libvo_amrwbenc_encoder_deps="libvo_amrwbenc" @@ -1651,6 +1714,7 @@ shlibdir_default="$libdir_default" # toolchain ar_default="ar" cc_default="gcc" +cxx_default="g++" cc_version=\"unknown\" host_cc_default="gcc" install="install" @@ -1715,6 +1779,7 @@ SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR) $(SLIBNAME)' AS_O='-o $@' CC_O='-o $@' +CXX_O='-o $@' host_cflags='-D_ISOC99_SOURCE -O3 -g' host_libs='-lm' @@ -1867,6 +1932,7 @@ set_default arch target_os ar_default="${cross_prefix}${ar_default}" cc_default="${cross_prefix}${cc_default}" +cxx_default="${cross_prefix}${cxx_default}" nm_default="${cross_prefix}${nm_default}" pkg_config_default="${cross_prefix}${pkg_config_default}" ranlib="${cross_prefix}${ranlib}" @@ -1874,7 +1940,7 @@ strip_default="${cross_prefix}${strip_default}" sysinclude_default="${sysroot}/usr/include" -set_default cc nm pkg_config strip sysinclude +set_default cc cxx nm pkg_config strip sysinclude enabled cross_compile || host_cc_default=$cc set_default host_cc @@ -1916,6 +1982,7 @@ tmpfile(){ trap 'rm -f -- $TMPFILES' EXIT tmpfile TMPC .c +tmpfile TMPCPP .cpp tmpfile TMPE $EXESUF tmpfile TMPH .h tmpfile TMPO .o @@ -2133,9 +2200,11 @@ test -n "$cc_type" && enable $cc_type || set_default ar as dep_cc ld test -n "$CC_DEPFLAGS" || CCDEP=$DEPEND_CMD +test -n "$CXX_DEPFLAGS" || CXXDEP=$DEPEND_CMD test -n "$AS_DEPFLAGS" || ASDEP=$DEPEND_CMD add_cflags $extra_cflags +add_cxxflags $extra_cxxflags add_asflags $extra_cflags if test -n "$sysroot"; then @@ -2366,6 +2435,7 @@ if test "$?" != 0; then fi add_cppflags -D_ISOC99_SOURCE +add_cxxflags -D__STDC_CONSTANT_MACROS check_cflags -std=c99 check_cc -D_FILE_OFFSET_BITS=64 <<EOF && add_cppflags -D_FILE_OFFSET_BITS=64 #include <stdlib.h> @@ -2663,7 +2733,7 @@ elif enabled arm; then elif ! check_cpp_condition stddef.h "defined __ARM_PCS || defined __SOFTFP__"; then case "${cross_prefix:-$cc}" in *hardfloat*) enable vfp_args; fpabi=vfp ;; - *) check_ld <<EOF && enable vfp_args && fpabi=vfp || fpabi=soft ;; + *) check_ld "cc" <<EOF && enable vfp_args && fpabi=vfp || fpabi=soft ;; __asm__ (".eabi_attribute 28, 1"); int main(void) { return 0; } EOF @@ -2932,6 +3002,9 @@ enabled libopenjpeg && require libopenjpeg openjpeg.h opj_version -lopenjpeg enabled librtmp && require_pkg_config librtmp librtmp/rtmp.h RTMP_Socket enabled libschroedinger && require_pkg_config schroedinger-1.0 schroedinger/schro.h schro_init 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 enabled libtheora && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg enabled libvo_aacenc && require libvo_aacenc vo-aacenc/voAAC.h voGetAACEncAPI -lvo-aacenc enabled libvo_amrwbenc && require libvo_amrwbenc vo-amrwbenc/enc_if.h E_IF_init -lvo-amrwbenc @@ -3246,6 +3319,7 @@ echo "libopenjpeg enabled ${libopenjpeg-no}" echo "librtmp enabled ${librtmp-no}" echo "libschroedinger enabled ${libschroedinger-no}" echo "libspeex enabled ${libspeex-no}" +echo "libstagefright-h264 enabled ${libstagefright_h264-no}" echo "libtheora enabled ${libtheora-no}" echo "libvo-aacenc support ${libvo_aacenc-no}" echo "libvo-amrwbenc support ${libvo_amrwbenc-no}" @@ -3306,6 +3380,7 @@ endif CC_IDENT=$cc_ident ARCH=$arch CC=$cc +CXX=$cxx AS=$as LD=$ld DEPCC=$dep_cc @@ -3318,9 +3393,11 @@ LN_S=$ln_s STRIP=$strip CPPFLAGS=$CPPFLAGS CFLAGS=$CFLAGS +CXXFLAGS=$CXXFLAGS ASFLAGS=$ASFLAGS AS_O=$CC_O CC_O=$CC_O +CXX_O=$CXX_O LDFLAGS=$LDFLAGS FFSERVERLDFLAGS=$FFSERVERLDFLAGS SHFLAGS=$SHFLAGS @@ -3337,6 +3414,7 @@ EXESUF=$EXESUF EXTRA_VERSION=$extra_version DEPFLAGS=$DEPFLAGS CCDEP=$CCDEP +CXXDEP=$CXXDEP ASDEP=$ASDEP CC_DEPFLAGS=$CC_DEPFLAGS AS_DEPFLAGS=$AS_DEPFLAGS diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 17cc1b4b4f..a53ee1dfc6 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -594,6 +594,7 @@ OBJS-$(CONFIG_LIBSCHROEDINGER_ENCODER) += libschroedingerenc.o \ libdirac_libschro.o OBJS-$(CONFIG_LIBSPEEX_DECODER) += libspeexdec.o OBJS-$(CONFIG_LIBSPEEX_ENCODER) += libspeexenc.o +OBJS-$(CONFIG_LIBSTAGEFRIGHT_H264_DECODER)+= libstagefright.o OBJS-$(CONFIG_LIBTHEORA_ENCODER) += libtheoraenc.o OBJS-$(CONFIG_LIBVO_AACENC_ENCODER) += libvo-aacenc.o mpeg4audio.o OBJS-$(CONFIG_LIBVO_AMRWBENC_ENCODER) += libvo-amrwbenc.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 305e7985b0..0e6a64824b 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -382,6 +382,7 @@ void avcodec_register_all(void) REGISTER_DECODER (LIBOPENJPEG, libopenjpeg); REGISTER_ENCDEC (LIBSCHROEDINGER, libschroedinger); REGISTER_ENCDEC (LIBSPEEX, libspeex); + REGISTER_DECODER (LIBSTAGEFRIGHT_H264, libstagefright_h264); REGISTER_ENCODER (LIBTHEORA, libtheora); REGISTER_ENCODER (LIBVO_AACENC, libvo_aacenc); REGISTER_ENCODER (LIBVO_AMRWBENC, libvo_amrwbenc); diff --git a/libavcodec/libstagefright.cpp b/libavcodec/libstagefright.cpp new file mode 100644 index 0000000000..e31a2ec7b3 --- /dev/null +++ b/libavcodec/libstagefright.cpp @@ -0,0 +1,516 @@ +/* + * Interface to the Android Stagefright library for + * H/W accelerated H.264 decoding + * + * Copyright (C) 2011 Mohamed Naufal + * Copyright (C) 2011 Martin Storsjö + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <binder/ProcessState.h> +#include <media/stagefright/MetaData.h> +#include <media/stagefright/MediaBufferGroup.h> +#include <media/stagefright/MediaDebug.h> +#include <media/stagefright/MediaDefs.h> +#include <media/stagefright/OMXClient.h> +#include <media/stagefright/OMXCodec.h> +#include <utils/List.h> +#include <new> + +extern "C" { +#include "avcodec.h" +#include "libavutil/imgutils.h" +} + +#define OMX_QCOM_COLOR_FormatYVU420SemiPlanar 0x7FA30C00 + +using namespace android; + +struct Frame { + status_t status; + size_t size; + int64_t time; + int key; + uint8_t *buffer; + MediaBuffer* mbuffer; + int32_t w, h; +}; + +class CustomSource; + +struct StagefrightContext { + AVCodecContext *avctx; + AVBitStreamFilterContext *bsfc; + uint8_t* orig_extradata; + int orig_extradata_size; + sp<MediaSource> source; + List<Frame*> *in_queue, *out_queue; + pthread_mutex_t in_mutex, out_mutex; + pthread_cond_t condition; + pthread_t decode_thread_id; + + Frame *end_frame; + bool source_done; + volatile sig_atomic_t thread_exited, stop_decode; + + AVFrame ret_frame; + + uint8_t *dummy_buf; + int dummy_bufsize; + + OMXClient *client; + sp<MediaSource> decoder; + const char *decoder_component; +}; + +class CustomSource : public MediaSource { +public: + CustomSource(AVCodecContext *avctx, sp<MetaData> meta) { + s = (StagefrightContext*)avctx->priv_data; + source_meta = meta; + frame_size = (avctx->width * avctx->height * 3) / 2; + buf_group.add_buffer(new MediaBuffer(frame_size)); + } + + virtual sp<MetaData> getFormat() { + return source_meta; + } + + virtual status_t start(MetaData *params) { + return OK; + } + + virtual status_t stop() { + return OK; + } + + virtual status_t read(MediaBuffer **buffer, + const MediaSource::ReadOptions *options) { + Frame *frame; + status_t ret; + + pthread_mutex_lock(&s->in_mutex); + + while (s->in_queue->empty()) + pthread_cond_wait(&s->condition, &s->in_mutex); + + frame = *s->in_queue->begin(); + ret = frame->status; + + if (ret == OK) { + ret = buf_group.acquire_buffer(buffer); + if (ret == OK) { + memcpy((*buffer)->data(), frame->buffer, frame->size); + (*buffer)->set_range(0, frame->size); + (*buffer)->meta_data()->clear(); + (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame,frame->key); + (*buffer)->meta_data()->setInt64(kKeyTime, frame->time); + } else { + av_log(s->avctx, AV_LOG_ERROR, "Failed to acquire MediaBuffer\n"); + } + av_freep(&frame->buffer); + } + + s->in_queue->erase(s->in_queue->begin()); + pthread_mutex_unlock(&s->in_mutex); + + av_freep(&frame); + return ret; + } + +private: + MediaBufferGroup buf_group; + sp<MetaData> source_meta; + StagefrightContext *s; + int frame_size; +}; + +void* decode_thread(void *arg) +{ + AVCodecContext *avctx = (AVCodecContext*)arg; + StagefrightContext *s = (StagefrightContext*)avctx->priv_data; + Frame* frame; + MediaBuffer *buffer; + int decode_done = 0; + do { + buffer = NULL; + frame = (Frame*)av_mallocz(sizeof(Frame)); + if (!frame) { + frame = s->end_frame; + 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; + } else if (frame->status == INFO_FORMAT_CHANGED) { + if (buffer) + buffer->release(); + av_free(frame); + continue; + } else { + decode_done = 1; + } + } + pthread_mutex_lock(&s->out_mutex); + s->out_queue->push_back(frame); + pthread_mutex_unlock(&s->out_mutex); + } while (!decode_done && !s->stop_decode); + + s->thread_exited = true; + + return 0; +} + +static av_cold int Stagefright_init(AVCodecContext *avctx) +{ + StagefrightContext *s = (StagefrightContext*)avctx->priv_data; + sp<MetaData> meta, outFormat; + int32_t colorFormat = 0; + int ret; + + if (!avctx->extradata || !avctx->extradata_size || avctx->extradata[0] != 1) + return -1; + + s->avctx = avctx; + s->bsfc = av_bitstream_filter_init("h264_mp4toannexb"); + if (!s->bsfc) { + av_log(avctx, AV_LOG_ERROR, "Cannot open the h264_mp4toannexb BSF!\n"); + return -1; + } + + s->orig_extradata_size = avctx->extradata_size; + s->orig_extradata = (uint8_t*) av_mallocz(avctx->extradata_size + + FF_INPUT_BUFFER_PADDING_SIZE); + if (!s->orig_extradata) { + ret = AVERROR(ENOMEM); + goto fail; + } + memcpy(s->orig_extradata, avctx->extradata, avctx->extradata_size); + + meta = new MetaData; + if (meta == NULL) { + ret = AVERROR(ENOMEM); + goto fail; + } + meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); + meta->setInt32(kKeyWidth, avctx->width); + meta->setInt32(kKeyHeight, avctx->height); + meta->setData(kKeyAVCC, kTypeAVCC, avctx->extradata, avctx->extradata_size); + + android::ProcessState::self()->startThreadPool(); + + s->source = new CustomSource(avctx, meta); + s->in_queue = new List<Frame*>; + s->out_queue = new List<Frame*>; + 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) { + ret = AVERROR(ENOMEM); + goto fail; + } + + if (s->client->connect() != OK) { + av_log(avctx, AV_LOG_ERROR, "Cannot connect OMX client\n"); + ret = -1; + goto fail; + } + + s->decoder = OMXCodec::Create(s->client->interface(), meta, + false, s->source, NULL, + OMXCodec::kClientNeedsFramebuffer); + if (s->decoder->start() != OK) { + av_log(avctx, AV_LOG_ERROR, "Cannot start decoder\n"); + ret = -1; + s->client->disconnect(); + goto fail; + } + + outFormat = s->decoder->getFormat(); + outFormat->findInt32(kKeyColorFormat, &colorFormat); + if (colorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar || + colorFormat == OMX_COLOR_FormatYUV420SemiPlanar) + avctx->pix_fmt = PIX_FMT_NV21; + else + avctx->pix_fmt = PIX_FMT_YUV420P; + + outFormat->findCString(kKeyDecoderComponent, &s->decoder_component); + if (s->decoder_component) + s->decoder_component = av_strdup(s->decoder_component); + + pthread_mutex_init(&s->in_mutex, NULL); + pthread_mutex_init(&s->out_mutex, NULL); + pthread_cond_init(&s->condition, NULL); + pthread_create(&s->decode_thread_id, NULL, &decode_thread, avctx); + return 0; + +fail: + av_bitstream_filter_close(s->bsfc); + av_freep(&s->orig_extradata); + av_freep(&s->end_frame); + delete s->in_queue; + delete s->out_queue; + delete s->client; + return ret; +} + +static int Stagefright_decode_frame(AVCodecContext *avctx, void *data, + int *data_size, AVPacket *avpkt) +{ + 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; + + if (avpkt && avpkt->data) { + av_bitstream_filter_filter(s->bsfc, avctx, NULL, &pkt.data, &pkt.size, + avpkt->data, avpkt->size, avpkt->flags & AV_PKT_FLAG_KEY); + avpkt = &pkt; + } + + if (!s->source_done) { + if(!s->dummy_buf) { + s->dummy_buf = (uint8_t*)av_malloc(avpkt->size); + if (!s->dummy_buf) + return AVERROR(ENOMEM); + s->dummy_bufsize = avpkt->size; + memcpy(s->dummy_buf, avpkt->data, avpkt->size); + } + + frame = (Frame*)av_mallocz(sizeof(Frame)); + if (avpkt->data) { + frame->status = OK; + frame->size = orig_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) { + av_freep(&frame); + return AVERROR(ENOMEM); + } + uint8_t *ptr = avpkt->data; + // The OMX.SEC decoder fails without this. + if (avpkt->size == orig_size + avctx->extradata_size) + ptr += avctx->extradata_size; + memcpy(frame->buffer, ptr, orig_size); + } else { + frame->status = ERROR_END_OF_STREAM; + s->source_done = true; + } + + while (true) { + if (s->thread_exited) { + s->source_done = true; + break; + } + pthread_mutex_lock(&s->in_mutex); + if (s->in_queue->size() >= 10) { + pthread_mutex_unlock(&s->in_mutex); + usleep(10000); + continue; + } + s->in_queue->push_back(frame); + pthread_cond_signal(&s->condition); + pthread_mutex_unlock(&s->in_mutex); + break; + } + } + while (true) { + pthread_mutex_lock(&s->out_mutex); + if (!s->out_queue->empty()) break; + pthread_mutex_unlock(&s->out_mutex); + if (s->source_done) { + usleep(10000); + continue; + } else { + return orig_size; + } + } + + frame = *s->out_queue->begin(); + s->out_queue->erase(s->out_queue->begin()); + pthread_mutex_unlock(&s->out_mutex); + + mbuffer = frame->mbuffer; + status = frame->status; + size = frame->size; + w = frame->w; + h = frame->h; + av_freep(&frame); + + if (status == ERROR_END_OF_STREAM) + return 0; + if (status != OK) { + if (status == AVERROR(ENOMEM)) + return status; + av_log(avctx, AV_LOG_ERROR, "Decode failed: %x\n", status); + 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; + } + + 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); + + *data_size = sizeof(AVFrame); + *(AVFrame*)data = s->ret_frame; + ret = orig_size; +end: + mbuffer->release(); + return ret; +} + +static av_cold int Stagefright_close(AVCodecContext *avctx) +{ + StagefrightContext *s = (StagefrightContext*)avctx->priv_data; + Frame *frame; + + if (!s->thread_exited) { + s->stop_decode = 1; + + // Feed a dummy frame prior to signalling EOF. + // This is required to terminate the decoder(OMX.SEC) + // when only one frame is read during stream info detection. + if (s->dummy_buf && (frame = (Frame*)av_mallocz(sizeof(Frame)))) { + frame->status = OK; + frame->size = s->dummy_bufsize; + frame->buffer = s->dummy_buf; + pthread_mutex_lock(&s->in_mutex); + s->in_queue->push_back(frame); + pthread_cond_signal(&s->condition); + pthread_mutex_unlock(&s->in_mutex); + s->dummy_buf = NULL; + } + + pthread_mutex_lock(&s->in_mutex); + s->end_frame->status = ERROR_END_OF_STREAM; + s->in_queue->push_back(s->end_frame); + pthread_cond_signal(&s->condition); + pthread_mutex_unlock(&s->in_mutex); + s->end_frame = NULL; + } + + pthread_join(s->decode_thread_id, NULL); + + if (s->ret_frame.data[0]) + avctx->release_buffer(avctx, &s->ret_frame); + + while (!s->in_queue->empty()) { + frame = *s->in_queue->begin(); + s->in_queue->erase(s->in_queue->begin()); + if (frame->size) + av_freep(&frame->buffer); + av_freep(&frame); + } + + while (!s->out_queue->empty()) { + frame = *s->out_queue->begin(); + s->out_queue->erase(s->out_queue->begin()); + if (frame->size) + frame->mbuffer->release(); + av_freep(&frame); + } + + s->decoder->stop(); + s->client->disconnect(); + + if (s->decoder_component) + av_freep(&s->decoder_component); + av_freep(&s->dummy_buf); + av_freep(&s->end_frame); + + // Reset the extradata back to the original mp4 format, so that + // the next invocation (both when decoding and when called from + // av_find_stream_info) get the original mp4 format extradata. + av_freep(&avctx->extradata); + avctx->extradata = s->orig_extradata; + avctx->extradata_size = s->orig_extradata_size; + + delete s->in_queue; + delete s->out_queue; + delete s->client; + + pthread_mutex_destroy(&s->in_mutex); + pthread_mutex_destroy(&s->out_mutex); + pthread_cond_destroy(&s->condition); + av_bitstream_filter_close(s->bsfc); + return 0; +} + +AVCodec ff_libstagefright_h264_decoder = { + "libstagefright_h264", + AVMEDIA_TYPE_VIDEO, + CODEC_ID_H264, + sizeof(StagefrightContext), + Stagefright_init, + NULL, //encode + Stagefright_close, + Stagefright_decode_frame, + CODEC_CAP_DELAY, + NULL, //next + NULL, //flush + NULL, //supported_framerates + NULL, //pixel_formats + NULL_IF_CONFIG_SMALL("libstagefright H.264"), +}; diff --git a/libavcodec/version.h b/libavcodec/version.h index 268db0b844..45e215ac2a 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -21,7 +21,7 @@ #define AVCODEC_VERSION_H #define LIBAVCODEC_VERSION_MAJOR 53 -#define LIBAVCODEC_VERSION_MINOR 13 +#define LIBAVCODEC_VERSION_MINOR 14 #define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ diff --git a/tools/build_libstagefright b/tools/build_libstagefright new file mode 100644 index 0000000000..583c801a56 --- /dev/null +++ b/tools/build_libstagefright @@ -0,0 +1,41 @@ +#!/bin/bash + +if [ "$NDK" = "" ]; then + echo NDK variable not set, assuming ${HOME}/android-ndk + export NDK=${HOME}/android-ndk +fi + +SYSROOT=$NDK/platforms/android-9/arch-arm +# Expand the prebuilt/* path into the correct one +TOOLCHAIN=`echo $NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/*-x86` +export PATH=$TOOLCHAIN/bin:$PATH +ANDROID_SOURCE=$HOME/android +ANDROID_LIBS=$HOME/glib + +rm -rf ../build/libav +mkdir -p ../build/libav + +DEST=../build/libav +FLAGS="--target-os=linux --cross-prefix=arm-linux-androideabi- --arch=arm --cpu=armv7-a" +FLAGS="$FLAGS --sysroot=$SYSROOT" +FLAGS="$FLAGS --disable-avdevice --disable-decoder=h264 --disable-decoder=h264_vdpau --enable-libstagefright-h264" + +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 -march=armv7-a -mfloat-abi=softfp -mfpu=neon" +EXTRA_LDFLAGS="-Wl,--fix-cortex-a8 -L$ANDROID_LIBS -Wl,-rpath-link,$ANDROID_LIBS" +EXTRA_CXXFLAGS="-Wno-multichar -fno-exceptions -fno-rtti" +ABI="armeabi-v7a" +DEST="$DEST/$ABI" +FLAGS="$FLAGS --prefix=$DEST" + +mkdir -p $DEST + +echo $FLAGS --extra-cflags="$EXTRA_CFLAGS" --extra-ldflags="$EXTRA_LDFLAGS" --extra-cxxflags="$EXTRA_CXXFLAGS" > $DEST/info.txt +./configure $FLAGS --extra-cflags="$EXTRA_CFLAGS" --extra-ldflags="$EXTRA_LDFLAGS" --extra-cxxflags="$EXTRA_CXXFLAGS" | tee $DEST/configuration.txt +[ $PIPESTATUS == 0 ] || exit 1 +make clean +make -j4 || exit 1 |