From 006d2ab4844e4fa96e5abd0a2bb4a6a8edc6b8a8 Mon Sep 17 00:00:00 2001 From: Mohamed Naufal Date: Wed, 31 Aug 2011 04:11:25 +0530 Subject: [PATCH 1/5] C++ Support ;) --- Changelog | 1 + Makefile | 8 ++++- configure | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 87 insertions(+), 9 deletions(-) diff --git a/Changelog b/Changelog index 510de33e1e..ec2fa30424 100644 --- a/Changelog +++ b/Changelog @@ -42,6 +42,7 @@ easier to use. The changes are: * -intra option was removed, it's equivalent to -g 0. - XMV demuxer - Windows Media Image decoder +- C++ Support version 0.7: diff --git a/Makefile b/Makefile index 28ca055aad..954d5b6ffc 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ include config.mak vpath %.c $(SRC_PATH) +vpath %.cpp $(SRC_PATH) vpath %.h $(SRC_PATH) vpath %.S $(SRC_PATH) vpath %.asm $(SRC_PATH) @@ -10,7 +11,7 @@ vpath %.texi $(SRC_PATH) ifndef V Q = @ ECHO = printf "$(1)\t%s\n" $(2) -BRIEF = CC AS YASM AR LD HOSTCC +BRIEF = CC CXX AS YASM AR LD HOSTCC SILENT = DEPCC YASMDEP RM RANLIB MSG = $@ M = @$(call ECHO,$(TAG),$@); @@ -26,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) @@ -36,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) diff --git a/configure b/configure index e26124e8d1..6f5c76359a 100755 --- a/configure +++ b/configure @@ -203,12 +203,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 [] @@ -578,6 +580,10 @@ add_cflags(){ append CFLAGS $($filter_cflags "$@") } +add_cxxflags(){ + append CXXFLAGS $($filter_cflags "$@") +} + add_asflags(){ append ASFLAGS $($filter_asflags "$@") } @@ -602,6 +608,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 @@ -637,12 +650,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 } @@ -662,9 +677,17 @@ int x; EOF } +check_cxxflags(){ + log check_cxxflags "$@" + set -- $($filter_cflags "$@") + check_cxx "$@" < float foo(float f) { return $func(f); } int main(void){ return 0; } @@ -721,7 +744,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(){ @@ -753,6 +795,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" @@ -768,7 +818,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(){ @@ -848,6 +898,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" @@ -1173,6 +1231,7 @@ CMDLINE_SET=" cc cpu cross_prefix + cxx dep_cc extra_version host_cc @@ -1196,6 +1255,7 @@ CMDLINE_SET=" CMDLINE_APPEND=" extra_cflags + extra_cxxflags " # code dependency declarations @@ -1610,6 +1670,7 @@ shlibdir_default="$libdir_default" # toolchain ar_default="ar" cc_default="gcc" +cxx_default="g++" cc_version=\"unknown\" host_cc_default="gcc" ln_s="ln -sf" @@ -1671,6 +1732,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' @@ -1823,13 +1885,14 @@ 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}" sysinclude_default="${sysroot}/usr/include" -set_default cc nm pkg_config sysinclude +set_default cc cxx nm pkg_config sysinclude enabled cross_compile || host_cc_default=$cc set_default host_cc @@ -1871,6 +1934,7 @@ tmpfile(){ trap 'rm -f -- $TMPFILES' EXIT tmpfile TMPC .c +tmpfile TMPCPP .cpp tmpfile TMPE $EXESUF tmpfile TMPH .h tmpfile TMPO .o @@ -2088,9 +2152,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 @@ -2325,6 +2391,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 < @@ -2615,7 +2682,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 < Date: Wed, 31 Aug 2011 04:12:56 +0530 Subject: [PATCH 2/5] Add build-script for Android --- build.sh | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100755 build.sh diff --git a/build.sh b/build.sh new file mode 100755 index 0000000000..0b5efc4de6 --- /dev/null +++ b/build.sh @@ -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" + +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 From 84f26f528836bf35eb51b25c8876d715aaadda53 Mon Sep 17 00:00:00 2001 From: Mohamed Naufal Date: Wed, 31 Aug 2011 04:14:47 +0530 Subject: [PATCH 3/5] Support (H/W accelerated) H.264 decoding on Android via Stagefright --- Changelog | 1 + configure | 7 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/libstagefright.cpp | 516 ++++++++++++++++++++++++++++++++++ libavcodec/version.h | 2 +- 6 files changed, 527 insertions(+), 1 deletion(-) create mode 100644 libavcodec/libstagefright.cpp diff --git a/Changelog b/Changelog index ec2fa30424..c3b37484c1 100644 --- a/Changelog +++ b/Changelog @@ -43,6 +43,7 @@ easier to use. The changes are: - XMV demuxer - Windows Media Image decoder - C++ Support +- H.264 Decoding on Android via Stagefright version 0.7: diff --git a/configure b/configure index 6f5c76359a..c6bf171f6b 100755 --- a/configure +++ b/configure @@ -178,6 +178,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 decoding via libspeex [no] + --enable-libstagefright 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] @@ -999,6 +1000,7 @@ CONFIG_LIST=" librtmp libschroedinger libspeex + libstagefright libtheora libvo_aacenc libvo_amrwbenc @@ -1463,6 +1465,7 @@ libopenjpeg_decoder_deps="libopenjpeg" libschroedinger_decoder_deps="libschroedinger" libschroedinger_encoder_deps="libschroedinger" libspeex_decoder_deps="libspeex" +libstagefright_decoder_deps="libstagefright" libtheora_encoder_deps="libtheora" libvo_aacenc_encoder_deps="libvo_aacenc" libvo_amrwbenc_encoder_deps="libvo_amrwbenc" @@ -2946,6 +2949,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 && require_cpp libstagefright "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 @@ -3226,6 +3232,7 @@ echo "libopenjpeg enabled ${libopenjpeg-no}" echo "librtmp enabled ${librtmp-no}" echo "libschroedinger enabled ${libschroedinger-no}" echo "libspeex enabled ${libspeex-no}" +echo "libstagefright enabled ${libstagefright-no}" echo "libtheora enabled ${libtheora-no}" echo "libvo-aacenc support ${libvo_aacenc-no}" echo "libvo-amrwbenc support ${libvo_amrwbenc-no}" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 2264e86b7d..30c084503f 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -573,6 +573,7 @@ OBJS-$(CONFIG_LIBSCHROEDINGER_ENCODER) += libschroedingerenc.o \ libschroedinger.o \ libdirac_libschro.o OBJS-$(CONFIG_LIBSPEEX_DECODER) += libspeexdec.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 b483f81aa2..4439ca3e48 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -369,6 +369,7 @@ void avcodec_register_all(void) REGISTER_DECODER (LIBOPENJPEG, libopenjpeg); REGISTER_ENCDEC (LIBSCHROEDINGER, libschroedinger); REGISTER_DECODER (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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 source; + List *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 decoder; + const char *decoder_component; +}; + +class CustomSource : public MediaSource { +public: + CustomSource(AVCodecContext *avctx, sp 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 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 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 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 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; + s->out_queue = new List; + 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 889e945082..557c656132 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 9 +#define LIBAVCODEC_VERSION_MINOR 10 #define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ From fd265746fec952412b9350495a51f619815dcea1 Mon Sep 17 00:00:00 2001 From: Mohamed Naufal Date: Thu, 8 Sep 2011 21:17:17 +0530 Subject: [PATCH 4/5] Fix regular build --- build.sh | 2 +- configure | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build.sh b/build.sh index 0b5efc4de6..0d474f4ac5 100755 --- a/build.sh +++ b/build.sh @@ -18,7 +18,7 @@ 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" +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" diff --git a/configure b/configure index c6bf171f6b..6f23af3969 100755 --- a/configure +++ b/configure @@ -178,7 +178,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 decoding via libspeex [no] - --enable-libstagefright enable H.264 decoding via libstagefright [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] @@ -1000,7 +1000,7 @@ CONFIG_LIST=" librtmp libschroedinger libspeex - libstagefright + libstagefright_h264 libtheora libvo_aacenc libvo_amrwbenc @@ -1465,7 +1465,7 @@ libopenjpeg_decoder_deps="libopenjpeg" libschroedinger_decoder_deps="libschroedinger" libschroedinger_encoder_deps="libschroedinger" libspeex_decoder_deps="libspeex" -libstagefright_decoder_deps="libstagefright" +libstagefright_h264_decoder_deps="libstagefright_h264" libtheora_encoder_deps="libtheora" libvo_aacenc_encoder_deps="libvo_aacenc" libvo_amrwbenc_encoder_deps="libvo_amrwbenc" @@ -2949,7 +2949,7 @@ 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 && require_cpp libstagefright "binder/ProcessState.h media/stagefright/MetaData.h +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 @@ -3232,7 +3232,7 @@ echo "libopenjpeg enabled ${libopenjpeg-no}" echo "librtmp enabled ${librtmp-no}" echo "libschroedinger enabled ${libschroedinger-no}" echo "libspeex enabled ${libspeex-no}" -echo "libstagefright enabled ${libstagefright-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}" From 9c29ab58517cae8d56c7ed7fd5070d8f8c8d429e Mon Sep 17 00:00:00 2001 From: Mohamed Naufal Date: Fri, 9 Sep 2011 23:14:36 +0530 Subject: [PATCH 5/5] Move & Rename buildscript, remove tabs --- build.sh => tools/build_libstagefright | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename build.sh => tools/build_libstagefright (94%) diff --git a/build.sh b/tools/build_libstagefright similarity index 94% rename from build.sh rename to tools/build_libstagefright index 0d474f4ac5..583c801a56 100755 --- a/build.sh +++ b/tools/build_libstagefright @@ -1,8 +1,8 @@ #!/bin/bash if [ "$NDK" = "" ]; then - echo NDK variable not set, assuming ${HOME}/android-ndk - export NDK=${HOME}/android-ndk + echo NDK variable not set, assuming ${HOME}/android-ndk + export NDK=${HOME}/android-ndk fi SYSROOT=$NDK/platforms/android-9/arch-arm