diff --git a/README.md b/README.md index a670aa4b17..cf01fe22d4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,28 @@ # ijkplayer + +基于ijkplayer的定制化修改: + +1、解决ijkplayer切换音轨失步、爆音问题 + +2、支持双画面同时渲染 + +3、支持切换左右声道都有声音输出 + +4、支持声道切换 + +5、支持FFmpeg硬件解码 + +6、支持配置FFmpeg-soft、ijk-MediaCodec、FFmpeg-MediaCodec配置修改 + +7、默认采用FFmpeg-MediaCodec方案,FFmpeg硬件失败重试FFmpeg-soft方案 + +8、修复FFmpeg解码时NV12渲染颜色错乱的BUG + +9、修复DNS解析相关的bug + +10、添加文件加密播放功能 + Platform | Build Status -------- | ------------ Android | [![Build Status](https://travis-ci.org/Bilibili/ci-ijk-ffmpeg-android.svg?branch=master)](https://travis-ci.org/Bilibili/ci-ijk-ffmpeg-android) diff --git a/android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/fragments/SampleMediaListFragment.java b/android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/fragments/SampleMediaListFragment.java index 3361d5012f..fa31b5d3e1 100644 --- a/android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/fragments/SampleMediaListFragment.java +++ b/android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/fragments/SampleMediaListFragment.java @@ -67,7 +67,8 @@ public void onItemClick(AdapterView parent, View view, final int position, fi VideoActivity.intentTo(activity, url, name); } }); - + mAdapter.addItem("http://192.168.1.11:8080/3.mp4","局域网多音轨测试mp4"); + mAdapter.addItem("http://crossnat.cn:8080/OK1.mp4","多音轨测试mp4"); mAdapter.addItem("http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8", "bipbop basic master playlist"); mAdapter.addItem("http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/prog_index.m3u8", "bipbop basic 400x300 @ 232 kbps"); mAdapter.addItem("http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear2/prog_index.m3u8", "bipbop basic 640x480 @ 650 kbps"); diff --git a/android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/IjkVideoView.java b/android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/IjkVideoView.java index cc3f002d82..6a1e105a58 100755 --- a/android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/IjkVideoView.java +++ b/android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/IjkVideoView.java @@ -1038,7 +1038,12 @@ public IMediaPlayer createPlayer(int playerType) { ijkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG); if (mSettings.getUsingMediaCodec()) { - ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1); + ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 2); + ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-avc", 2); + ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-hevc", 2); + ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-mpeg4", 2); + + if (mSettings.getUsingMediaCodecAutoRotate()) { ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1); } else { @@ -1067,10 +1072,13 @@ public IMediaPlayer createPlayer(int playerType) { } ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1); ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0); - + ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "min-frames", 2); ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "http-detect-range-support", 0); - ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48); + ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "threads", 4); + //todo(xzl) 设置文件解密密钥 + ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "mask_str", "osvyBFIL"); + ijkMediaPlayer.setPitch(1.0f); } mediaPlayer = ijkMediaPlayer; } diff --git a/android/ijkplayer/ijkplayer-example/src/main/res/values/strings.xml b/android/ijkplayer/ijkplayer-example/src/main/res/values/strings.xml index b4fdce5e02..a30f35837f 100755 --- a/android/ijkplayer/ijkplayer-example/src/main/res/values/strings.xml +++ b/android/ijkplayer/ijkplayer-example/src/main/res/values/strings.xml @@ -1,58 +1,58 @@ - ijkmediademo + 播放器测试 N/A - Close - Exit - Sample - Recent - Settings - Tracks - Player - Render - Scale - Info - vdec - fps - v-cache - a-cache + 关闭 + 退出 + 示例 + 最近 + 设置 + 媒体 + 播放器 + 渲染 + 缩放 + 详情 + 视频编码 + 帧率 + 视频缓存 + 音频缓存 load-cost seek_cost seek_load_cost - tcp_speed - bit_rate + 网速 + 比特率 - Media Information - Player - Media - Profile level - Pixel format - Resolution - Length - Stream #%d - Type - Language - Codec - Frame rate - Bit rate - Sample rate - Channels + 媒体信息 + 播放器 + 媒体 + 规格 + 采样格式 + 分辨率 + 长度 + 流 #%d + 类型 + 语言 + 编解码 + 帧率 + 比特率 + 采样率 + 通道数 * * * - Video - Audio - Subtitle + 视频 + 音频 + 字幕 Timed text - Meta data - Unknown + 元数据 + 未知 Invalid progressive playback Unknown - OK + 好的 Aspect / Fit parent Aspect / Fill parent @@ -66,7 +66,7 @@ Render: TextureView Player: None - Player: AndroidMediaPlayer + Player: 原生播放器 Player: IjkMediaPlayer Player: IjkExoMediaPlayer diff --git a/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IMediaPlayer.java b/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IMediaPlayer.java index da668efe3d..8790b81722 100644 --- a/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IMediaPlayer.java +++ b/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IMediaPlayer.java @@ -212,4 +212,5 @@ interface OnTimedTextListener { * AndroidMediaPlayer: M: */ void setDataSource(IMediaDataSource mediaDataSource); + } diff --git a/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java b/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java index beb73f76e8..aacdf3729a 100755 --- a/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java +++ b/android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java @@ -108,6 +108,7 @@ public final class IjkMediaPlayer extends AbstractMediaPlayer { public static final int PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND = 10001; public static final int PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND = 10002; public static final int FFP_PROP_FLOAT_PLAYBACK_RATE = 10003; + public static final int FFP_PROP_FLOAT_PITCH_RATE = 11000; public static final int FFP_PROP_FLOAT_DROP_FRAME_RATE = 10007; public static final int FFP_PROP_INT64_SELECTED_VIDEO_STREAM = 20001; @@ -140,6 +141,8 @@ public final class IjkMediaPlayer extends AbstractMediaPlayer { public static final int FFP_PROP_INT64_TCP_SPEED = 20200; public static final int FFP_PROP_INT64_LATEST_SEEK_LOAD_DURATION = 20300; public static final int FFP_PROP_INT64_IMMEDIATE_RECONNECT = 20211; + public static final int FFP_PROP_INT64_CHANNEL_CONFIG = 21000; + //---------------------------------------- @AccessedByNative @@ -156,7 +159,7 @@ public final class IjkMediaPlayer extends AbstractMediaPlayer { @AccessedByNative private int mListenerContext; - private SurfaceHolder mSurfaceHolder; + private SurfaceHolder mSurfaceHolder[] = new SurfaceHolder[2]; private EventHandler mEventHandler; private PowerManager.WakeLock mWakeLock = null; private boolean mScreenOnWhilePlaying; @@ -166,7 +169,7 @@ public final class IjkMediaPlayer extends AbstractMediaPlayer { private int mVideoHeight; private int mVideoSarNum; private int mVideoSarDen; - + private int mSurfaceIndex = 0; private String mDataSource; /** @@ -254,7 +257,12 @@ private native void _setFrameAtTime(String imgCachePath, long startTime, long en * Update the IjkMediaPlayer SurfaceTexture. Call after setting a new * display surface. */ - private native void _setVideoSurface(Surface surface); + private native void _setVideoSurface(Surface surface,int index); + + + public void setSurfaceIndex(int idx) { + mSurfaceIndex = idx; + } /** * Sets the {@link SurfaceHolder} to use for displaying the video portion of @@ -271,17 +279,18 @@ private native void _setFrameAtTime(String imgCachePath, long startTime, long en */ @Override public void setDisplay(SurfaceHolder sh) { - mSurfaceHolder = sh; + mSurfaceHolder[mSurfaceIndex] = sh; Surface surface; if (sh != null) { surface = sh.getSurface(); } else { surface = null; } - _setVideoSurface(surface); + _setVideoSurface(surface,mSurfaceIndex); updateSurfaceScreenOn(); } + /** * Sets the {@link Surface} to be used as the sink for the video portion of * the media. This is similar to {@link #setDisplay(SurfaceHolder)}, but @@ -307,8 +316,8 @@ public void setSurface(Surface surface) { DebugLog.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for Surface"); } - mSurfaceHolder = null; - _setVideoSurface(surface); + mSurfaceHolder[mSurfaceIndex] = null; + _setVideoSurface(surface,mSurfaceIndex); updateSurfaceScreenOn(); } @@ -488,6 +497,7 @@ public void setDataSource(IMediaDataSource mediaDataSource) _setDataSource(mediaDataSource); } + public void setAndroidIOCallback(IAndroidIO androidIO) throws IllegalArgumentException, SecurityException, IllegalStateException { _setAndroidIOCallback(androidIO); @@ -566,7 +576,7 @@ public void setWakeMode(Context context, int mode) { @Override public void setScreenOnWhilePlaying(boolean screenOn) { if (mScreenOnWhilePlaying != screenOn) { - if (screenOn && mSurfaceHolder == null) { + if (screenOn && mSurfaceHolder[0] == null && mSurfaceHolder[1] == null) { DebugLog.w(TAG, "setScreenOnWhilePlaying(true) is ineffective without a SurfaceHolder"); } @@ -589,8 +599,11 @@ private void stayAwake(boolean awake) { } private void updateSurfaceScreenOn() { - if (mSurfaceHolder != null) { - mSurfaceHolder.setKeepScreenOn(mScreenOnWhilePlaying && mStayAwake); + if (mSurfaceHolder[0] != null) { + mSurfaceHolder[0].setKeepScreenOn(mScreenOnWhilePlaying && mStayAwake); + } + if (mSurfaceHolder[1] != null) { + mSurfaceHolder[1].setKeepScreenOn(mScreenOnWhilePlaying && mStayAwake); } } @@ -754,6 +767,15 @@ public float getSpeed(float speed) { return _getPropertyFloat(FFP_PROP_FLOAT_PLAYBACK_RATE, .0f); } + public void setPitch(float pitch) { + _setPropertyFloat(FFP_PROP_FLOAT_PITCH_RATE, pitch); + } + + public float getPitch(float pitch) { + return _getPropertyFloat(FFP_PROP_FLOAT_PITCH_RATE, .0f); + } + + public int getVideoDecoder() { return (int)_getPropertyLong(FFP_PROP_INT64_VIDEO_DECODER, FFP_PROPV_DECODER_UNKNOWN); } @@ -766,6 +788,14 @@ public float getVideoDecodeFramesPerSecond() { return _getPropertyFloat(PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND, 0.0f); } + public void setChannelConfig(int config) { + _setPropertyLong(FFP_PROP_INT64_CHANNEL_CONFIG, config); + } + + public float getChannelConfig() { + return _getPropertyLong(FFP_PROP_INT64_CHANNEL_CONFIG, 0); + } + public long getVideoCachedDuration() { return _getPropertyLong(FFP_PROP_INT64_VIDEO_CACHED_DURATION, 0); } diff --git a/config/module-default.sh b/config/module-default.sh index 9f02c4e434..d461c81385 100755 --- a/config/module-default.sh +++ b/config/module-default.sh @@ -5,6 +5,15 @@ export COMMON_FF_CFG_FLAGS= # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --prefix=PREFIX" +export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-jni " +export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-mediacodec" +export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-hwaccel=h264_mediacodec" +export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-hwaccel=hevc_mediacodec" +export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-hwaccel=mpeg2_mediacodec" +export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-hwaccel=mpeg4_mediacodec" +export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-hwaccel=vp8_mediacodec" +export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-hwaccel=vp9_mediacodec" + # Licensing options: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-gpl" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-version3" @@ -64,7 +73,7 @@ export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vdpau" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-everything" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-encoders" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-decoders" -export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-hwaccels" +# export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-hwaccels" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-muxers" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-demuxers" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-parsers" @@ -78,6 +87,7 @@ export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-iconv" # ... export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=async" +export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-linux-perf" # Advanced options (experts only): # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --cross-prefix=${FF_CROSS_PREFIX}-" diff --git a/config/module.sh b/config/module.sh index 0f16f539b1..a25d6630fd 120000 --- a/config/module.sh +++ b/config/module.sh @@ -1 +1 @@ -module-lite.sh \ No newline at end of file +module-default.sh \ No newline at end of file diff --git a/ijkmedia/ijkplayer/android/ijkplayer_android.c b/ijkmedia/ijkplayer/android/ijkplayer_android.c index da4de8a37a..bf5a4a1a41 100644 --- a/ijkmedia/ijkplayer/android/ijkplayer_android.c +++ b/ijkmedia/ijkplayer/android/ijkplayer_android.c @@ -54,23 +54,23 @@ IjkMediaPlayer *ijkmp_android_create(int(*msg_loop)(void*)) return NULL; } -void ijkmp_android_set_surface_l(JNIEnv *env, IjkMediaPlayer *mp, jobject android_surface) +void ijkmp_android_set_surface_l(JNIEnv *env, IjkMediaPlayer *mp, jobject android_surface,jint index) { if (!mp || !mp->ffplayer || !mp->ffplayer->vout) return; - SDL_VoutAndroid_SetAndroidSurface(env, mp->ffplayer->vout, android_surface); + SDL_VoutAndroid_SetAndroidSurface(env, mp->ffplayer->vout, android_surface,index); ffpipeline_set_surface(env, mp->ffplayer->pipeline, android_surface); } -void ijkmp_android_set_surface(JNIEnv *env, IjkMediaPlayer *mp, jobject android_surface) +void ijkmp_android_set_surface(JNIEnv *env, IjkMediaPlayer *mp, jobject android_surface,jint index) { if (!mp) return; MPTRACE("ijkmp_set_android_surface(surface=%p)", (void*)android_surface); pthread_mutex_lock(&mp->mutex); - ijkmp_android_set_surface_l(env, mp, android_surface); + ijkmp_android_set_surface_l(env, mp, android_surface,index); pthread_mutex_unlock(&mp->mutex); MPTRACE("ijkmp_set_android_surface(surface=%p)=void", (void*)android_surface); } diff --git a/ijkmedia/ijkplayer/android/ijkplayer_android.h b/ijkmedia/ijkplayer/android/ijkplayer_android.h index f711b290fc..09c9d32769 100644 --- a/ijkmedia/ijkplayer/android/ijkplayer_android.h +++ b/ijkmedia/ijkplayer/android/ijkplayer_android.h @@ -37,7 +37,7 @@ typedef struct ijkmp_android_media_format_context { // ref_count is 1 after open IjkMediaPlayer *ijkmp_android_create(int(*msg_loop)(void*)); -void ijkmp_android_set_surface(JNIEnv *env, IjkMediaPlayer *mp, jobject android_surface); +void ijkmp_android_set_surface(JNIEnv *env, IjkMediaPlayer *mp, jobject android_surface,jint index); void ijkmp_android_set_volume(JNIEnv *env, IjkMediaPlayer *mp, float left, float right); int ijkmp_android_get_audio_session_id(JNIEnv *env, IjkMediaPlayer *mp); void ijkmp_android_set_mediacodec_select_callback(IjkMediaPlayer *mp, bool (*callback)(void *opaque, ijkmp_mediacodecinfo_context *mcc), void *opaque); diff --git a/ijkmedia/ijkplayer/android/ijkplayer_jni.c b/ijkmedia/ijkplayer/android/ijkplayer_jni.c index b5a50e7d6a..2725635816 100755 --- a/ijkmedia/ijkplayer/android/ijkplayer_jni.c +++ b/ijkmedia/ijkplayer/android/ijkplayer_jni.c @@ -241,13 +241,13 @@ IjkMediaPlayer_setAndroidIOCallback(JNIEnv *env, jobject thiz, jobject callback) } static void -IjkMediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface) +IjkMediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface,jint index) { MPTRACE("%s\n", __func__); IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, NULL, "mpjni: setVideoSurface: null mp", LABEL_RETURN); - ijkmp_android_set_surface(env, mp, jsurface); + ijkmp_android_set_surface(env, mp, jsurface,index); LABEL_RETURN: ijkmp_dec_ref_p(&mp); @@ -369,7 +369,9 @@ IjkMediaPlayer_release(JNIEnv *env, jobject thiz) if (!mp) return; - ijkmp_android_set_surface(env, mp, NULL); + ijkmp_android_set_surface(env, mp, NULL,0); + ijkmp_android_set_surface(env, mp, NULL,1); + // explicit shutdown mp, in case it is not the last mp-ref here ijkmp_shutdown(mp); //only delete weak_thiz at release @@ -1143,7 +1145,7 @@ static JNINativeMethod g_methods[] = { { "_setDataSource", "(Ltv/danmaku/ijk/media/player/misc/IMediaDataSource;)V", (void *)IjkMediaPlayer_setDataSourceCallback }, { "_setAndroidIOCallback", "(Ltv/danmaku/ijk/media/player/misc/IAndroidIO;)V", (void *)IjkMediaPlayer_setAndroidIOCallback }, - { "_setVideoSurface", "(Landroid/view/Surface;)V", (void *) IjkMediaPlayer_setVideoSurface }, + { "_setVideoSurface", "(Landroid/view/Surface;I)V", (void *) IjkMediaPlayer_setVideoSurface }, { "_prepareAsync", "()V", (void *) IjkMediaPlayer_prepareAsync }, { "_start", "()V", (void *) IjkMediaPlayer_start }, { "_stop", "()V", (void *) IjkMediaPlayer_stop }, @@ -1182,6 +1184,9 @@ static JNINativeMethod g_methods[] = { { "_setFrameAtTime", "(Ljava/lang/String;JJII)V", (void *) IjkMediaPlayer_setFrameAtTime }, }; + +#include + JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv* env = NULL; @@ -1200,7 +1205,7 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) ijkmp_global_init(); ijkmp_global_set_inject_callback(inject_callback); - + av_jni_set_java_vm(vm, NULL); FFmpegApi_global_init(env); return JNI_VERSION_1_4; diff --git a/ijkmedia/ijkplayer/android/pipeline/ffpipeline_android.c b/ijkmedia/ijkplayer/android/pipeline/ffpipeline_android.c index cbb1d7b448..8d9845018b 100644 --- a/ijkmedia/ijkplayer/android/pipeline/ffpipeline_android.c +++ b/ijkmedia/ijkplayer/android/pipeline/ffpipeline_android.c @@ -70,10 +70,16 @@ static IJKFF_Pipenode *func_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlaye IJKFF_Pipeline_Opaque *opaque = pipeline->opaque; IJKFF_Pipenode *node = NULL; - if (ffp->mediacodec_all_videos || ffp->mediacodec_avc || ffp->mediacodec_hevc || ffp->mediacodec_mpeg2) + if (ffp->mediacodec_all_videos == 1 || + ffp->mediacodec_avc == 1 || + ffp->mediacodec_hevc == 1 || + ffp->mediacodec_mpeg2 == 1 || + ffp->mediacodec_mpeg4 == 1) node = ffpipenode_create_video_decoder_from_android_mediacodec(ffp, pipeline, opaque->weak_vout); if (!node) { node = ffpipenode_create_video_decoder_from_ffplay(ffp); + }else{ + ALOGE("启用ijk硬件解码成功\n"); } return node; @@ -97,7 +103,11 @@ static IJKFF_Pipenode *func_init_video_decoder(IJKFF_Pipeline *pipeline, FFPlaye IJKFF_Pipeline_Opaque *opaque = pipeline->opaque; IJKFF_Pipenode *node = NULL; - if (ffp->mediacodec_all_videos || ffp->mediacodec_avc || ffp->mediacodec_hevc || ffp->mediacodec_mpeg2) + if (ffp->mediacodec_all_videos == 1 || + ffp->mediacodec_avc == 1 || + ffp->mediacodec_hevc == 1 || + ffp->mediacodec_mpeg2 == 1 || + ffp->mediacodec_mpeg4 == 1) node = ffpipenode_init_decoder_from_android_mediacodec(ffp, pipeline, opaque->weak_vout); return node; diff --git a/ijkmedia/ijkplayer/android/pipeline/ffpipenode_android_mediacodec_vdec.c b/ijkmedia/ijkplayer/android/pipeline/ffpipenode_android_mediacodec_vdec.c index 4c6a53510b..864eda4cf8 100755 --- a/ijkmedia/ijkplayer/android/pipeline/ffpipenode_android_mediacodec_vdec.c +++ b/ijkmedia/ijkplayer/android/pipeline/ffpipenode_android_mediacodec_vdec.c @@ -1708,7 +1708,7 @@ int ffpipenode_config_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pip switch (opaque->codecpar->codec_id) { case AV_CODEC_ID_H264: - if (!ffp->mediacodec_avc && !ffp->mediacodec_all_videos) { + if (ffp->mediacodec_avc != 1 && ffp->mediacodec_all_videos != 1) { ALOGE("%s: MediaCodec: AVC/H264 is disabled. codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } @@ -1761,7 +1761,7 @@ int ffpipenode_config_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pip opaque->mcc.level = opaque->codecpar->level; break; case AV_CODEC_ID_HEVC: - if (!ffp->mediacodec_hevc && !ffp->mediacodec_all_videos) { + if (ffp->mediacodec_hevc != 1 && ffp->mediacodec_all_videos != 1) { ALOGE("%s: MediaCodec/HEVC is disabled. codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } @@ -1770,7 +1770,7 @@ int ffpipenode_config_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pip opaque->mcc.level = opaque->codecpar->level; break; case AV_CODEC_ID_MPEG2VIDEO: - if (!ffp->mediacodec_mpeg2 && !ffp->mediacodec_all_videos) { + if (ffp->mediacodec_mpeg2 != 1 && ffp->mediacodec_all_videos != 1) { ALOGE("%s: MediaCodec/MPEG2VIDEO is disabled. codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } @@ -1779,7 +1779,7 @@ int ffpipenode_config_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pip opaque->mcc.level = opaque->codecpar->level; break; case AV_CODEC_ID_MPEG4: - if (!ffp->mediacodec_mpeg4 && !ffp->mediacodec_all_videos) { + if (ffp->mediacodec_mpeg4 != 1 && ffp->mediacodec_all_videos != 1) { ALOGE("%s: MediaCodec/MPEG4 is disabled. codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } @@ -1942,7 +1942,7 @@ IJKFF_Pipenode *ffpipenode_create_video_decoder_from_android_mediacodec(FFPlayer switch (opaque->codecpar->codec_id) { case AV_CODEC_ID_H264: - if (!ffp->mediacodec_avc && !ffp->mediacodec_all_videos) { + if (ffp->mediacodec_avc != 1 && ffp->mediacodec_all_videos != 1) { ALOGE("%s: MediaCodec: AVC/H264 is disabled. codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } @@ -1995,7 +1995,7 @@ IJKFF_Pipenode *ffpipenode_create_video_decoder_from_android_mediacodec(FFPlayer opaque->mcc.level = opaque->codecpar->level; break; case AV_CODEC_ID_HEVC: - if (!ffp->mediacodec_hevc && !ffp->mediacodec_all_videos) { + if (ffp->mediacodec_hevc != 1 && ffp->mediacodec_all_videos != 1) { ALOGE("%s: MediaCodec/HEVC is disabled. codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } @@ -2004,7 +2004,7 @@ IJKFF_Pipenode *ffpipenode_create_video_decoder_from_android_mediacodec(FFPlayer opaque->mcc.level = opaque->codecpar->level; break; case AV_CODEC_ID_MPEG2VIDEO: - if (!ffp->mediacodec_mpeg2 && !ffp->mediacodec_all_videos) { + if (ffp->mediacodec_mpeg2 != 1 && ffp->mediacodec_all_videos != 1) { ALOGE("%s: MediaCodec/MPEG2VIDEO is disabled. codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } @@ -2013,7 +2013,7 @@ IJKFF_Pipenode *ffpipenode_create_video_decoder_from_android_mediacodec(FFPlayer opaque->mcc.level = opaque->codecpar->level; break; case AV_CODEC_ID_MPEG4: - if (!ffp->mediacodec_mpeg4 && !ffp->mediacodec_all_videos) { + if (ffp->mediacodec_mpeg4 != 1 && ffp->mediacodec_all_videos != 1) { ALOGE("%s: MediaCodec/MPEG4 is disabled. codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } diff --git a/ijkmedia/ijkplayer/ff_ffmsg.h b/ijkmedia/ijkplayer/ff_ffmsg.h index c5c4cd89d4..5b8834d411 100755 --- a/ijkmedia/ijkplayer/ff_ffmsg.h +++ b/ijkmedia/ijkplayer/ff_ffmsg.h @@ -62,6 +62,8 @@ #define FFP_PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND 10001 #define FFP_PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND 10002 #define FFP_PROP_FLOAT_PLAYBACK_RATE 10003 +//FFP_PROP_FLOAT_PITCH_RATE -- add by xzl +#define FFP_PROP_FLOAT_PITCH_RATE 11000 #define FFP_PROP_FLOAT_PLAYBACK_VOLUME 10006 #define FFP_PROP_FLOAT_AVDELAY 10004 #define FFP_PROP_FLOAT_AVDIFF 10005 @@ -105,5 +107,6 @@ #define FFP_PROP_INT64_LOGICAL_FILE_SIZE 20209 #define FFP_PROP_INT64_SHARE_CACHE_DATA 20210 #define FFP_PROP_INT64_IMMEDIATE_RECONNECT 20211 - +//add by xzl +#define FFP_PROP_INT64_CHANNEL_CONFIG 21000 #endif diff --git a/ijkmedia/ijkplayer/ff_ffplay.c b/ijkmedia/ijkplayer/ff_ffplay.c index 52aba31f41..dce6f19507 100755 --- a/ijkmedia/ijkplayer/ff_ffplay.c +++ b/ijkmedia/ijkplayer/ff_ffplay.c @@ -48,6 +48,7 @@ #include "libavutil/avassert.h" #include "libavutil/time.h" #include "libavformat/avformat.h" +#include "libavcodec/mediacodec.h" #if CONFIG_AVDEVICE #include "libavdevice/avdevice.h" #endif @@ -68,6 +69,7 @@ #include "ff_cmdutils.h" #include "ff_fferror.h" #include "ff_ffpipeline.h" +#include "android/pipeline/ffpipeline_android.h" #include "ff_ffpipenode.h" #include "ff_ffplay_debug.h" #include "ijkmeta.h" @@ -138,6 +140,13 @@ int64_t get_valid_channel_layout(int64_t channel_layout, int channels) } #endif + +inline static uint64_t get_now_time() { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + static void free_picture(Frame *vp); static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt) @@ -2579,14 +2588,14 @@ static int audio_decode_frame(FFPlayer *ffp) int bytes_per_sample = av_get_bytes_per_sample(is->audio_tgt.fmt); resampled_data_size = len2 * is->audio_tgt.channels * bytes_per_sample; #if defined(__ANDROID__) - if (ffp->soundtouch_enable && ffp->pf_playback_rate != 1.0f && !is->abort_request) { + if (ffp->soundtouch_enable && (ffp->pf_playback_rate != 1.0f || ffp->pf_pitch_rate != 1.0f )&& !is->abort_request) { av_fast_malloc(&is->audio_new_buf, &is->audio_new_buf_size, out_size * translate_time); for (int i = 0; i < (resampled_data_size / 2); i++) { is->audio_new_buf[i] = (is->audio_buf1[i * 2] | (is->audio_buf1[i * 2 + 1] << 8)); } - int ret_len = ijk_soundtouch_translate(is->handle, is->audio_new_buf, (float)(ffp->pf_playback_rate), (float)(1.0f/ffp->pf_playback_rate), + int ret_len = ijk_soundtouch_translate(is->handle, is->audio_new_buf, (float)(ffp->pf_playback_rate), (float)(ffp->pf_pitch_rate/ ffp->pf_playback_rate), resampled_data_size / 2, bytes_per_sample, is->audio_tgt.channels, af->frame->sample_rate); if (ret_len > 0) { is->audio_buf = (uint8_t*)is->audio_new_buf; @@ -2632,12 +2641,15 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len) { FFPlayer *ffp = opaque; VideoState *is = ffp->is; - int audio_size, len1; - if (!ffp || !is) { + int audio_size, len1,origin_len = len; + Uint8 *origin_stream = stream; + + if (!ffp || !is || get_now_time() - ffp->last_audio_open_tm < 20) { memset(stream, 0, len); return; } + ffp->audio_callback_time = av_gettime_relative(); if (ffp->pf_playback_rate_changed) { @@ -2691,6 +2703,26 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len) stream += len1; is->audio_buf_index += len1; } + + + if(is->audio_tgt.channels == 2 && ffp->channel_config != 0){ + //双声道并且需要制定输出单一声道 + int sample_size = av_get_bytes_per_sample(is->audio_tgt.fmt); + Uint8 *sample_ptr0,*sample_ptr1; + //av_log(NULL, AV_LOG_ERROR, "##########%d %d %d %d %d\n",is->audio_tgt.channels,ffp->channel_config,sample_size,is->audio_tgt.fmt,origin_len); + + for(int i = 0; i < origin_len; ){ + sample_ptr0 = origin_stream + i; + sample_ptr1 = origin_stream + i + sample_size; + if(ffp->channel_config == 1){ + memcpy(sample_ptr0,sample_ptr1,sample_size); + }else{ + memcpy(sample_ptr1,sample_ptr0,sample_size); + } + i += (sample_size * 2); + } + } + is->audio_write_buf_size = is->audio_buf_size - is->audio_buf_index; /* Let's assume the audio driver that is used by SDL has two periods. */ if (!isnan(is->audio_clock)) { @@ -2829,29 +2861,68 @@ static int stream_component_open(FFPlayer *ffp, int stream_index) goto fail; av_codec_set_pkt_timebase(avctx, ic->streams[stream_index]->time_base); - codec = avcodec_find_decoder(avctx->codec_id); - switch (avctx->codec_type) { case AVMEDIA_TYPE_AUDIO : is->last_audio_stream = stream_index; forced_codec_name = ffp->audio_codec_name; break; case AVMEDIA_TYPE_SUBTITLE: is->last_subtitle_stream = stream_index; forced_codec_name = ffp->subtitle_codec_name; break; case AVMEDIA_TYPE_VIDEO : is->last_video_stream = stream_index; forced_codec_name = ffp->video_codec_name; break; default: break; } - if (forced_codec_name) + const char *meidiacodec_name = NULL; + switch(avctx->codec_id){ + case AV_CODEC_ID_H264 : meidiacodec_name = (ffp->mediacodec_avc == 2 || ffp->mediacodec_all_videos == 2) ? "h264_mediacodec" : NULL;break; + case AV_CODEC_ID_HEVC : meidiacodec_name = (ffp->mediacodec_hevc == 2 || ffp->mediacodec_all_videos == 2) ? "hevc_mediacodec" : NULL;break; + case AV_CODEC_ID_MPEG2VIDEO : meidiacodec_name = (ffp->mediacodec_mpeg2 == 2 || ffp->mediacodec_all_videos == 2) ? "mpeg2_mediacodec" : NULL;break; + case AV_CODEC_ID_MPEG4 : meidiacodec_name = (ffp->mediacodec_mpeg4 == 2 || ffp->mediacodec_all_videos == 2) ? "mpeg4_mediacodec" : NULL;break; + case AV_CODEC_ID_VP8 : meidiacodec_name = (ffp->mediacodec_vp8 == 2 || ffp->mediacodec_all_videos == 2) ? "vp8_mediacodec" : NULL;break; + case AV_CODEC_ID_VP9 : meidiacodec_name = (ffp->mediacodec_vp9 == 2 || ffp->mediacodec_all_videos == 2) ? "vp9_mediacodec" : NULL;break; + default : break; + } + + if(avctx->codec_type == AVMEDIA_TYPE_VIDEO){ + av_log(NULL, AV_LOG_ERROR,"解码器配置: mediacodec_all_videos = %d\n", ffp->mediacodec_all_videos); + av_log(NULL, AV_LOG_ERROR,"解码器配置: mediacodec_avc = %d\n", ffp->mediacodec_avc); + av_log(NULL, AV_LOG_ERROR,"解码器配置: mediacodec_hevc = %d\n", ffp->mediacodec_hevc); + av_log(NULL, AV_LOG_ERROR,"解码器配置: mediacodec_mpeg2 = %d\n", ffp->mediacodec_mpeg2); + av_log(NULL, AV_LOG_ERROR,"解码器配置: mediacodec_mpeg4 = %d\n", ffp->mediacodec_mpeg4); + av_log(NULL, AV_LOG_ERROR,"解码器配置: mediacodec_vp8 = %d\n", ffp->mediacodec_vp8); + av_log(NULL, AV_LOG_ERROR,"解码器配置: mediacodec_vp9 = %d\n", ffp->mediacodec_vp9); + } + + //是否尝试开启FFmpeg-MediaCodec + int ffmpeg_mediacodec_tryed = 0; + +retry: + + if(meidiacodec_name && ffmpeg_mediacodec_tryed == 0){ + codec = avcodec_find_decoder_by_name(meidiacodec_name); + av_log(NULL, AV_LOG_ERROR,"查找ffmpeg硬件解码: %s %s\n", meidiacodec_name,codec ? "成功" : "失败"); + ffmpeg_mediacodec_tryed = (codec != NULL); + } + if(!codec){ + codec = avcodec_find_decoder(avctx->codec_id); + if(avctx->codec_type == AVMEDIA_TYPE_VIDEO){ + av_log(NULL, AV_LOG_ERROR,"查找ffmpeg软件解码: %d %s\n", (int)avctx->codec_id ,codec ? "成功" : "失败"); + ffmpeg_mediacodec_tryed = 0; + } + } + + if (forced_codec_name){ codec = avcodec_find_decoder_by_name(forced_codec_name); + av_log(NULL, AV_LOG_ERROR,"查找forced_codec_name: %s %s\n", forced_codec_name,codec ? "成功" : "失败"); + } if (!codec) { - if (forced_codec_name) av_log(NULL, AV_LOG_WARNING, - "No codec could be found with name '%s'\n", forced_codec_name); - else av_log(NULL, AV_LOG_WARNING, - "No codec could be found with id %d\n", avctx->codec_id); + if (forced_codec_name){ + av_log(NULL, AV_LOG_WARNING, "No codec could be found with name '%s'\n", forced_codec_name); + }else{ + av_log(NULL, AV_LOG_WARNING,"No codec could be found with id %d\n", avctx->codec_id); + } ret = AVERROR(EINVAL); goto fail; } avctx->codec_id = codec->id; if(stream_lowres > av_codec_get_max_lowres(codec)){ - av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n", - av_codec_get_max_lowres(codec)); + av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n",av_codec_get_max_lowres(codec)); stream_lowres = av_codec_get_max_lowres(codec); } av_codec_set_lowres(avctx, stream_lowres); @@ -2874,6 +2945,11 @@ static int stream_component_open(FFPlayer *ffp, int stream_index) if (avctx->codec_type == AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO) av_dict_set(&opts, "refcounted_frames", "1", 0); if ((ret = avcodec_open2(avctx, codec, &opts)) < 0) { + av_log(NULL, AV_LOG_ERROR,"打开ffmpeg解码器失败: %d %s\n", avctx->codec_id , meidiacodec_name ? meidiacodec_name : "soft decoder"); + if(ffmpeg_mediacodec_tryed){ + codec = NULL; + goto retry; + } goto fail; } if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) { @@ -2940,6 +3016,9 @@ static int stream_component_open(FFPlayer *ffp, int stream_index) } if ((ret = decoder_start(&is->auddec, audio_thread, ffp, "ff_audio_dec")) < 0) goto out; + + ffp->last_audio_open_tm = get_now_time(); + SDL_AoutFlushAudio(ffp->aout); SDL_AoutPauseAudio(ffp->aout, 0); break; case AVMEDIA_TYPE_VIDEO: @@ -3139,7 +3218,7 @@ static int read_thread(void *arg) if (ffp->genpts) ic->flags |= AVFMT_FLAG_GENPTS; - av_format_inject_global_side_data(ic); + //av_format_inject_global_side_data(ic); // //AVDictionary **opts; //int orig_nb_streams; @@ -3383,7 +3462,7 @@ static int read_thread(void *arg) packet_queue_flush(&is->audioq); packet_queue_put(&is->audioq, &flush_pkt); // TODO: clear invaild audio data - // SDL_AoutFlushAudio(ffp->aout); + SDL_AoutFlushAudio(ffp->aout); } if (is->subtitle_stream >= 0) { packet_queue_flush(&is->subtitleq); @@ -3718,7 +3797,11 @@ static VideoState *stream_open(FFPlayer *ffp, const char *filename, AVInputForma if (ffp->async_init_decoder && !ffp->video_disable && ffp->video_mime_type && strlen(ffp->video_mime_type) > 0 && ffp->mediacodec_default_name && strlen(ffp->mediacodec_default_name) > 0) { - if (ffp->mediacodec_all_videos || ffp->mediacodec_avc || ffp->mediacodec_hevc || ffp->mediacodec_mpeg2) { + if (ffp->mediacodec_all_videos == 1 || + ffp->mediacodec_avc == 1 || + ffp->mediacodec_hevc == 1 || + ffp->mediacodec_mpeg2 == 1 || + ffp->mediacodec_mpeg4 == 1) { decoder_init(&is->viddec, NULL, &is->videoq, is->continue_read_thread); ffp->node_vdec = ffpipeline_init_video_decoder(ffp->pipeline, ffp); } @@ -4788,6 +4871,15 @@ void ffp_set_playback_rate(FFPlayer *ffp, float rate) ffp->pf_playback_rate_changed = 1; } +void ffp_set_pitch_rate(FFPlayer *ffp, float rate) +{ + if (!ffp) + return; + + av_log(ffp, AV_LOG_INFO, "Pitch_rate: %f\n", rate); + ffp->pf_pitch_rate = rate; +} + void ffp_set_playback_volume(FFPlayer *ffp, float volume) { if (!ffp) @@ -4857,6 +4949,7 @@ int ffp_set_stream_selected(FFPlayer *ffp, int stream, int selected) av_log(ffp, AV_LOG_ERROR, "select invalid stream %d of video type %d\n", stream, codecpar->codec_type); return -1; } + return stream_component_open(ffp, stream); } else { switch (codecpar->codec_type) { @@ -4889,6 +4982,8 @@ float ffp_get_property_float(FFPlayer *ffp, int id, float default_value) return ffp ? ffp->stat.vfps : default_value; case FFP_PROP_FLOAT_PLAYBACK_RATE: return ffp ? ffp->pf_playback_rate : default_value; + case FFP_PROP_FLOAT_PITCH_RATE: + return ffp ? ffp->pf_pitch_rate : default_value; case FFP_PROP_FLOAT_AVDELAY: return ffp ? ffp->stat.avdelay : default_value; case FFP_PROP_FLOAT_AVDIFF: @@ -4911,6 +5006,9 @@ void ffp_set_property_float(FFPlayer *ffp, int id, float value) case FFP_PROP_FLOAT_PLAYBACK_VOLUME: ffp_set_playback_volume(ffp, value); break; + case FFP_PROP_FLOAT_PITCH_RATE: + ffp_set_pitch_rate(ffp, value); + break; default: return; } @@ -5002,6 +5100,11 @@ int64_t ffp_get_property_int64(FFPlayer *ffp, int id, int64_t default_value) if (!ffp) return default_value; return ffp->stat.logical_file_size; + + case FFP_PROP_INT64_CHANNEL_CONFIG: + if (!ffp) + return default_value; + return ffp->channel_config; default: return default_value; } @@ -5025,6 +5128,10 @@ void ffp_set_property_int64(FFPlayer *ffp, int id, int64_t value) if (ffp) { ijkio_manager_immediate_reconnect(ffp->ijkio_manager_ctx); } + case FFP_PROP_INT64_CHANNEL_CONFIG: + if(ffp){ + ffp->channel_config = value; + } default: break; } diff --git a/ijkmedia/ijkplayer/ff_ffplay_def.h b/ijkmedia/ijkplayer/ff_ffplay_def.h index 00f19f3c4d..15a78fc841 100755 --- a/ijkmedia/ijkplayer/ff_ffplay_def.h +++ b/ijkmedia/ijkplayer/ff_ffplay_def.h @@ -87,9 +87,9 @@ #ifdef FFP_MERGE #define MIN_FRAMES 25 #endif -#define DEFAULT_MIN_FRAMES 50000 #define MIN_MIN_FRAMES 2 #define MAX_MIN_FRAMES 50000 +#define DEFAULT_MIN_FRAMES MIN_MIN_FRAMES #define MIN_FRAMES (ffp->dcc.min_frames) #define EXTERNAL_CLOCK_MIN_FRAMES 2 #define EXTERNAL_CLOCK_MAX_FRAMES 10 @@ -675,6 +675,8 @@ typedef struct FFPlayer { int mediacodec_hevc; int mediacodec_mpeg2; int mediacodec_mpeg4; + int mediacodec_vp8; + int mediacodec_vp9; int mediacodec_handle_resolution_change; int mediacodec_auto_rotate; @@ -697,6 +699,7 @@ typedef struct FFPlayer { int vf_changed; int af_changed; float pf_playback_rate; + float pf_pitch_rate; int pf_playback_rate_changed; float pf_playback_volume; int pf_playback_volume_changed; @@ -720,6 +723,9 @@ typedef struct FFPlayer { char *mediacodec_default_name; int ijkmeta_delay_init; int render_wait_start; + //add by xzl + int64_t last_audio_open_tm; + int channel_config; } FFPlayer; #define fftime_to_milliseconds(ts) (av_rescale(ts, 1000, AV_TIME_BASE)) @@ -812,10 +818,14 @@ inline static void ffp_reset_internal(FFPlayer *ffp) ffp->vtb_handle_resolution_change = 0; // option ffp->vtb_wait_async = 0; // option - ffp->mediacodec_all_videos = 0; // option - ffp->mediacodec_avc = 0; // option - ffp->mediacodec_hevc = 0; // option - ffp->mediacodec_mpeg2 = 0; // option + ffp->mediacodec_all_videos = 0; // 默认ffmpeg软解解码 + ffp->mediacodec_hevc = 2; // 默认ffmpeg硬件解码 + ffp->mediacodec_avc = 2; // 默认ffmpeg硬件解码 + ffp->mediacodec_mpeg2 = 2; // 默认ffmpeg硬件解码 + ffp->mediacodec_mpeg4 = 2; // 默认ffmpeg硬件解码 + ffp->mediacodec_vp8 = 2; // 默认ffmpeg硬件解码 + ffp->mediacodec_vp9 = 2; // 默认ffmpeg硬件解码 + ffp->mediacodec_handle_resolution_change = 0; // option ffp->mediacodec_auto_rotate = 0; // option @@ -840,6 +850,7 @@ inline static void ffp_reset_internal(FFPlayer *ffp) ffp->vf_changed = 0; ffp->af_changed = 0; ffp->pf_playback_rate = 1.0f; + ffp->pf_pitch_rate = 1.0f; ffp->pf_playback_rate_changed = 0; ffp->pf_playback_volume = 1.0f; ffp->pf_playback_volume_changed = 0; @@ -853,6 +864,9 @@ inline static void ffp_reset_internal(FFPlayer *ffp) ffp->ijkio_inject_opaque = NULL; ffp_reset_statistic(&ffp->stat); ffp_reset_demux_cache_control(&ffp->dcc); + //add by xzl + ffp->last_audio_open_tm = 0; + ffp->channel_config = 0; } inline static void ffp_notify_msg1(FFPlayer *ffp, int what) { diff --git a/ijkmedia/ijkplayer/ff_ffplay_options.h b/ijkmedia/ijkplayer/ff_ffplay_options.h index b23afac16c..4d3f82b538 100644 --- a/ijkmedia/ijkplayer/ff_ffplay_options.h +++ b/ijkmedia/ijkplayer/ff_ffplay_options.h @@ -178,26 +178,30 @@ static const AVOption ffp_context_options[] = { OPTION_OFFSET(vtb_handle_resolution_change), OPTION_INT(0, 0, 1) }, // Android only options - { "mediacodec", "MediaCodec: enable H264 (deprecated by 'mediacodec-avc')", - OPTION_OFFSET(mediacodec_avc), OPTION_INT(0, 0, 1) }, { "mediacodec-auto-rotate", "MediaCodec: auto rotate frame depending on meta", OPTION_OFFSET(mediacodec_auto_rotate), OPTION_INT(0, 0, 1) }, - { "mediacodec-all-videos", "MediaCodec: enable all videos", - OPTION_OFFSET(mediacodec_all_videos), OPTION_INT(0, 0, 1) }, - { "mediacodec-avc", "MediaCodec: enable H264", - OPTION_OFFSET(mediacodec_avc), OPTION_INT(0, 0, 1) }, - { "mediacodec-hevc", "MediaCodec: enable HEVC", - OPTION_OFFSET(mediacodec_hevc), OPTION_INT(0, 0, 1) }, - { "mediacodec-mpeg2", "MediaCodec: enable MPEG2VIDEO", - OPTION_OFFSET(mediacodec_mpeg2), OPTION_INT(0, 0, 1) }, - { "mediacodec-mpeg4", "MediaCodec: enable MPEG4", - OPTION_OFFSET(mediacodec_mpeg4), OPTION_INT(0, 0, 1) }, + + { "mediacodec-all-videos", "MediaCodec: enable all videos(0:ffmpeg_soft,1:ijk_mediacodec,2:ffmpeg_mediacodec)", + OPTION_OFFSET(mediacodec_all_videos), OPTION_INT(0, 0, 2) }, + { "mediacodec-avc", "MediaCodec: enable H264(0:ffmpeg_soft,1:ijk_mediacodec,2:ffmpeg_mediacodec)", + OPTION_OFFSET(mediacodec_avc), OPTION_INT(2, 0, 2) }, + { "mediacodec-hevc", "MediaCodec: enable HEVC(0:ffmpeg_soft,1:ijk_mediacodec,2:ffmpeg_mediacodec)", + OPTION_OFFSET(mediacodec_hevc), OPTION_INT(2, 0, 2) }, + { "mediacodec-mpeg2", "MediaCodec: enable MPEG2VIDEO(0:ffmpeg_soft,1:ijk_mediacodec,2:ffmpeg_mediacodec)", + OPTION_OFFSET(mediacodec_mpeg2), OPTION_INT(2, 0, 2) }, + { "mediacodec-mpeg4", "MediaCodec: enable MPEG4(0:ffmpeg_soft,1:ijk_mediacodec,2:ffmpeg_mediacodec)", + OPTION_OFFSET(mediacodec_mpeg4), OPTION_INT(2, 0, 2) }, + { "mediacodec-vp8", "MediaCodec: enable VP8(0:ffmpeg_soft,1:ijk_mediacodec,2:ffmpeg_mediacodec)", + OPTION_OFFSET(mediacodec_vp8), OPTION_INT(2, 0, 2) }, + { "mediacodec-vp9", "MediaCodec: enable VP9(0:ffmpeg_soft,1:ijk_mediacodec,2:ffmpeg_mediacodec)", + OPTION_OFFSET(mediacodec_vp9), OPTION_INT(2, 0, 2) }, + { "mediacodec-handle-resolution-change", "MediaCodec: handle resolution change automatically", OPTION_OFFSET(mediacodec_handle_resolution_change), OPTION_INT(0, 0, 1) }, { "opensles", "OpenSL ES: enable", OPTION_OFFSET(opensles), OPTION_INT(0, 0, 1) }, { "soundtouch", "SoundTouch: enable", - OPTION_OFFSET(soundtouch_enable), OPTION_INT(0, 0, 1) }, + OPTION_OFFSET(soundtouch_enable), OPTION_INT(1, 0, 1) }, { "mediacodec-sync", "mediacodec: use msg_queue for synchronise", OPTION_OFFSET(mediacodec_sync), OPTION_INT(0, 0, 1) }, { "mediacodec-default-name", "mediacodec default name", diff --git a/ijkmedia/ijksdl/android/ijksdl_vout_android_nativewindow.c b/ijkmedia/ijksdl/android/ijksdl_vout_android_nativewindow.c index e2a2e90317..75b335d7bf 100644 --- a/ijkmedia/ijksdl/android/ijksdl_vout_android_nativewindow.c +++ b/ijkmedia/ijksdl/android/ijksdl_vout_android_nativewindow.c @@ -82,7 +82,7 @@ static void SDL_AMediaCodecBufferProxy_invalidate(SDL_AMediaCodecBufferProxy *pr } typedef struct SDL_Vout_Opaque { - ANativeWindow *native_window; + ANativeWindow *native_window[2]; SDL_AMediaCodec *acodec; int null_native_window_warned; // reduce log for null window int next_buffer_id; @@ -90,7 +90,7 @@ typedef struct SDL_Vout_Opaque { ISDL_Array overlay_manager; ISDL_Array overlay_pool; - IJK_EGL *egl; + IJK_EGL *egl[2]; } SDL_Vout_Opaque; static SDL_VoutOverlay *func_create_overlay_l(int width, int height, int frame_format, SDL_Vout *vout) @@ -126,12 +126,18 @@ static void func_free_l(SDL_Vout *vout) ISDL_Array__clear(&opaque->overlay_pool); ISDL_Array__clear(&opaque->overlay_manager); - if (opaque->native_window) { - ANativeWindow_release(opaque->native_window); - opaque->native_window = NULL; + if (opaque->native_window[0]) { + ANativeWindow_release(opaque->native_window[0]); + opaque->native_window[0] = NULL; } + if (opaque->native_window[1]) { + ANativeWindow_release(opaque->native_window[1]); + opaque->native_window[1] = NULL; + } + + IJK_EGL_freep(&opaque->egl[0]); + IJK_EGL_freep(&opaque->egl[1]); - IJK_EGL_freep(&opaque->egl); SDL_AMediaCodec_decreaseReferenceP(&opaque->acodec); } @@ -139,10 +145,10 @@ static void func_free_l(SDL_Vout *vout) SDL_Vout_FreeInternal(vout); } -static int func_display_overlay_l(SDL_Vout *vout, SDL_VoutOverlay *overlay) +static int func_display_overlay_l(SDL_Vout *vout, SDL_VoutOverlay *overlay ,int index) { SDL_Vout_Opaque *opaque = vout->opaque; - ANativeWindow *native_window = opaque->native_window; + ANativeWindow *native_window = opaque->native_window[index]; if (!native_window) { if (!opaque->null_native_window_warned) { @@ -167,36 +173,37 @@ static int func_display_overlay_l(SDL_Vout *vout, SDL_VoutOverlay *overlay) switch(overlay->format) { case SDL_FCC__AMC: { // only ANativeWindow support - IJK_EGL_terminate(opaque->egl); + IJK_EGL_terminate(opaque->egl[index]); return SDL_VoutOverlayAMediaCodec_releaseFrame_l(overlay, NULL, true); } case SDL_FCC_RV24: case SDL_FCC_I420: case SDL_FCC_I444P10LE: { // only GLES support - if (opaque->egl) - return IJK_EGL_display(opaque->egl, native_window, overlay); + if (opaque->egl[index]) + return IJK_EGL_display(opaque->egl[index], native_window, overlay); break; } case SDL_FCC_YV12: case SDL_FCC_RV16: case SDL_FCC_RV32: { // both GLES & ANativeWindow support - if (vout->overlay_format == SDL_FCC__GLES2 && opaque->egl) - return IJK_EGL_display(opaque->egl, native_window, overlay); + if (vout->overlay_format == SDL_FCC__GLES2 && opaque->egl[index]) + return IJK_EGL_display(opaque->egl[index], native_window, overlay); break; } } // fallback to ANativeWindow - IJK_EGL_terminate(opaque->egl); + IJK_EGL_terminate(opaque->egl[index]); return SDL_Android_NativeWindow_display_l(native_window, overlay); } static int func_display_overlay(SDL_Vout *vout, SDL_VoutOverlay *overlay) { SDL_LockMutex(vout->mutex); - int retval = func_display_overlay_l(vout, overlay); + int retval = func_display_overlay_l(vout, overlay,0); + func_display_overlay_l(vout, overlay,1); SDL_UnlockMutex(vout->mutex); return retval; } @@ -212,14 +219,18 @@ SDL_Vout *SDL_VoutAndroid_CreateForANativeWindow() return NULL; SDL_Vout_Opaque *opaque = vout->opaque; - opaque->native_window = NULL; + opaque->native_window[0] = NULL; + opaque->native_window[1] = NULL; + if (ISDL_Array__init(&opaque->overlay_manager, 32)) goto fail; if (ISDL_Array__init(&opaque->overlay_pool, 32)) goto fail; - opaque->egl = IJK_EGL_create(); - if (!opaque->egl) + opaque->egl[0] = IJK_EGL_create(); + opaque->egl[1] = IJK_EGL_create(); + + if (!opaque->egl[0] || !opaque->egl[1]) goto fail; vout->opaque_class = &g_nativewindow_class; @@ -252,12 +263,12 @@ void SDL_VoutAndroid_invalidateAllBuffers(SDL_Vout *vout) SDL_UnlockMutex(vout->mutex); } -static void SDL_VoutAndroid_SetNativeWindow_l(SDL_Vout *vout, ANativeWindow *native_window) +static void SDL_VoutAndroid_SetNativeWindow_l(SDL_Vout *vout, ANativeWindow *native_window,int index) { AMCTRACE("%s(%p, %p)\n", __func__, vout, native_window); SDL_Vout_Opaque *opaque = vout->opaque; - if (opaque->native_window == native_window) { + if (opaque->native_window[index] == native_window) { if (native_window == NULL) { // always invalidate buffers, if native_window is changed SDL_VoutAndroid_invalidateAllBuffers_l(vout); @@ -265,23 +276,23 @@ static void SDL_VoutAndroid_SetNativeWindow_l(SDL_Vout *vout, ANativeWindow *nat return; } - IJK_EGL_terminate(opaque->egl); + IJK_EGL_terminate(opaque->egl[index]); SDL_VoutAndroid_invalidateAllBuffers_l(vout); - if (opaque->native_window) - ANativeWindow_release(opaque->native_window); + if (opaque->native_window[index]) + ANativeWindow_release(opaque->native_window[index]); if (native_window) ANativeWindow_acquire(native_window); - opaque->native_window = native_window; + opaque->native_window[index] = native_window; opaque->null_native_window_warned = 0; } -void SDL_VoutAndroid_SetNativeWindow(SDL_Vout *vout, ANativeWindow *native_window) +void SDL_VoutAndroid_SetNativeWindow(SDL_Vout *vout, ANativeWindow *native_window,int index) { SDL_LockMutex(vout->mutex); - SDL_VoutAndroid_SetNativeWindow_l(vout, native_window); + SDL_VoutAndroid_SetNativeWindow_l(vout, native_window,index); SDL_UnlockMutex(vout->mutex); } diff --git a/ijkmedia/ijksdl/android/ijksdl_vout_android_nativewindow.h b/ijkmedia/ijksdl/android/ijksdl_vout_android_nativewindow.h index dc0bc74f84..6365deb0cc 100644 --- a/ijkmedia/ijksdl/android/ijksdl_vout_android_nativewindow.h +++ b/ijkmedia/ijksdl/android/ijksdl_vout_android_nativewindow.h @@ -32,7 +32,7 @@ typedef struct ANativeWindow ANativeWindow; typedef struct SDL_AMediaCodec SDL_AMediaCodec; SDL_Vout *SDL_VoutAndroid_CreateForANativeWindow(); -void SDL_VoutAndroid_SetNativeWindow(SDL_Vout *vout, ANativeWindow *native_window); +void SDL_VoutAndroid_SetNativeWindow(SDL_Vout *vout, ANativeWindow *native_window,int index); void SDL_VoutAndroid_setAMediaCodec(SDL_Vout *vout, SDL_AMediaCodec *acodec); SDL_AMediaCodec *SDL_VoutAndroid_peekAMediaCodec(SDL_Vout *vout); void SDL_VoutAndroid_invalidateAllBuffers(SDL_Vout *vout); diff --git a/ijkmedia/ijksdl/android/ijksdl_vout_android_surface.c b/ijkmedia/ijksdl/android/ijksdl_vout_android_surface.c index 3f80d01773..26638f5732 100644 --- a/ijkmedia/ijksdl/android/ijksdl_vout_android_surface.c +++ b/ijkmedia/ijksdl/android/ijksdl_vout_android_surface.c @@ -34,7 +34,7 @@ SDL_Vout *SDL_VoutAndroid_CreateForAndroidSurface() return SDL_VoutAndroid_CreateForANativeWindow(); } -void SDL_VoutAndroid_SetAndroidSurface(JNIEnv *env, SDL_Vout *vout, jobject android_surface) +void SDL_VoutAndroid_SetAndroidSurface(JNIEnv *env, SDL_Vout *vout, jobject android_surface,jint index) { ANativeWindow *native_window = NULL; if (android_surface) { @@ -45,7 +45,7 @@ void SDL_VoutAndroid_SetAndroidSurface(JNIEnv *env, SDL_Vout *vout, jobject andr } } - SDL_VoutAndroid_SetNativeWindow(vout, native_window); + SDL_VoutAndroid_SetNativeWindow(vout, native_window,index); if (native_window) ANativeWindow_release(native_window); } diff --git a/ijkmedia/ijksdl/android/ijksdl_vout_android_surface.h b/ijkmedia/ijksdl/android/ijksdl_vout_android_surface.h index 24da65fd66..128a8349a5 100644 --- a/ijkmedia/ijksdl/android/ijksdl_vout_android_surface.h +++ b/ijkmedia/ijksdl/android/ijksdl_vout_android_surface.h @@ -30,6 +30,6 @@ #include "../ijksdl_vout.h" SDL_Vout *SDL_VoutAndroid_CreateForAndroidSurface(); -void SDL_VoutAndroid_SetAndroidSurface(JNIEnv*env, SDL_Vout *vout, jobject android_surface); +void SDL_VoutAndroid_SetAndroidSurface(JNIEnv*env, SDL_Vout *vout, jobject android_surface,jint index); #endif diff --git a/ijkmedia/ijksdl/ffmpeg/abi_all/image_convert.c b/ijkmedia/ijksdl/ffmpeg/abi_all/image_convert.c index d48a92761a..c5de22054d 100644 --- a/ijkmedia/ijksdl/ffmpeg/abi_all/image_convert.c +++ b/ijkmedia/ijksdl/ffmpeg/abi_all/image_convert.c @@ -30,25 +30,60 @@ int ijk_image_convert(int width, int height, enum AVPixelFormat dst_format, uint8_t **dst_data, int *dst_linesize, enum AVPixelFormat src_format, const uint8_t **src_data, const int *src_linesize) { + int ret = -2; #if defined(__ANDROID__) switch (src_format) { + case AV_PIX_FMT_NV12:{ + switch (dst_format) { + case AV_PIX_FMT_RGB565: + ret = NV12ToRGB565( + src_data[0], src_linesize[0], + src_data[1], src_linesize[1], + dst_data[0], dst_linesize[0], + width, height); + break; + case AV_PIX_FMT_0BGR32: + ret = NV12ToARGB( + src_data[0], src_linesize[0], + src_data[1], src_linesize[1], + dst_data[0], dst_linesize[0], + width, height); + if(ret == 0){ + ret = ARGBToABGR(dst_data[0], dst_linesize[0],dst_data[0], dst_linesize[0],width, height); + } + break; + default: + break; + } + break; + } case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUVJ420P: // FIXME: 9 not equal to AV_PIX_FMT_YUV420P, but a workaround switch (dst_format) { case AV_PIX_FMT_RGB565: - return I420ToRGB565( + ret = I420ToRGB565( src_data[0], src_linesize[0], src_data[1], src_linesize[1], src_data[2], src_linesize[2], dst_data[0], dst_linesize[0], width, height); + break; case AV_PIX_FMT_0BGR32: - return I420ToABGR( + ret = I420ToABGR( src_data[0], src_linesize[0], src_data[1], src_linesize[1], src_data[2], src_linesize[2], dst_data[0], dst_linesize[0], width, height); + break; + case AV_PIX_FMT_RGB24 : + ret = I420ToRGB24( + src_data[0], src_linesize[0], + src_data[1], src_linesize[1], + src_data[2], src_linesize[2], + dst_data[0], dst_linesize[0], + width, height); + break; default: break; } @@ -57,6 +92,24 @@ int ijk_image_convert(int width, int height, break; } #endif + + if(ret == 0){ + return 0; + } + + if(ret == -2){ + ALOGE("ijk_image_convert can not convert %s(%d) -> %s(%d)", + av_get_pix_fmt_name(src_format), + (int)src_format, + av_get_pix_fmt_name(dst_format), + (int)dst_format); + }else if(ret == -1){ + ALOGE("ijk_image_convert convert failed %s(%d) -> %s(%d)", + av_get_pix_fmt_name(src_format), + (int)src_format, + av_get_pix_fmt_name(dst_format), + (int)dst_format); + } return -1; } diff --git a/ijkmedia/ijksdl/ffmpeg/ijksdl_vout_overlay_ffmpeg.c b/ijkmedia/ijksdl/ffmpeg/ijksdl_vout_overlay_ffmpeg.c index 452f9a1c3e..32af234e28 100644 --- a/ijkmedia/ijksdl/ffmpeg/ijksdl_vout_overlay_ffmpeg.c +++ b/ijkmedia/ijksdl/ffmpeg/ijksdl_vout_overlay_ffmpeg.c @@ -268,7 +268,10 @@ static int func_fill_frame(SDL_VoutOverlay *overlay, const AVFrame *frame) if (!opaque->no_neon_warned) { opaque->no_neon_warned = 1; - ALOGE("non-neon image convert %s -> %s", av_get_pix_fmt_name(frame->format), av_get_pix_fmt_name(dst_format)); + ALOGE("non-neon image convert %s(%d) -> %s(%d)", av_get_pix_fmt_name(frame->format), + (int)frame->format, + av_get_pix_fmt_name(dst_format), + (int)dst_format); } } diff --git a/init-android.sh b/init-android.sh index a654e17f6b..14a6586fea 100755 --- a/init-android.sh +++ b/init-android.sh @@ -17,9 +17,9 @@ # # IJK_FFMPEG_UPSTREAM=git://git.videolan.org/ffmpeg.git -IJK_FFMPEG_UPSTREAM=https://github.com/Bilibili/FFmpeg.git -IJK_FFMPEG_FORK=https://github.com/Bilibili/FFmpeg.git -IJK_FFMPEG_COMMIT=ff3.4--ijk0.8.7--20180103--001 +IJK_FFMPEG_UPSTREAM=https://github.com/xiongziliang/FFmpeg.git +IJK_FFMPEG_FORK=https://github.com/xiongziliang/FFmpeg.git +IJK_FFMPEG_COMMIT=b031cdf7c41a041c958c1627af7891f9cedbecd6 IJK_FFMPEG_LOCAL_REPO=extra/ffmpeg set -e