Repository: bilibili/ijkplayer Branch: master Commit: 30eb9441945d Files: 640 Total size: 2.8 MB Directory structure: gitextract_n9wctwe6/ ├── .gitignore ├── .travis.yml ├── COPYING.GPLv2 ├── COPYING.GPLv3 ├── COPYING.LGPLv2.1 ├── COPYING.LGPLv3 ├── MODULE_LICENSE_APACHE2 ├── NEWS.md ├── NOTICE ├── README.md ├── android/ │ ├── .gitignore │ ├── build-on-travis.sh │ ├── compile-ijk.sh │ ├── contrib/ │ │ ├── .gitignore │ │ ├── compile-ffmpeg.sh │ │ ├── compile-libsoxr.sh │ │ ├── compile-openssl.sh │ │ ├── setup-as-commiter.sh │ │ ├── sync-mirrors.sh │ │ └── tools/ │ │ ├── do-compile-ffmpeg.sh │ │ ├── do-compile-libsoxr.sh │ │ ├── do-compile-openssl.sh │ │ └── do-detect-env.sh │ ├── ijk-addr2line.sh │ ├── ijk-ndk-stack.sh │ ├── ijkplayer/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── gradle/ │ │ │ └── wrapper/ │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ ├── gradle.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ ├── ijkplayer-arm64/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── gradle.properties │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ ├── androidTest/ │ │ │ │ └── java/ │ │ │ │ └── tv/ │ │ │ │ └── danmaku/ │ │ │ │ └── ijk/ │ │ │ │ └── media/ │ │ │ │ └── player_arm64/ │ │ │ │ └── ApplicationTest.java │ │ │ └── main/ │ │ │ ├── .classpath │ │ │ ├── .project │ │ │ ├── .settings/ │ │ │ │ └── org.eclipse.jdt.core.prefs │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── tv/ │ │ │ │ └── danmaku/ │ │ │ │ └── ijk/ │ │ │ │ └── media/ │ │ │ │ └── player_arm64/ │ │ │ │ └── Pragma.java │ │ │ ├── jni/ │ │ │ │ └── Application.mk │ │ │ ├── project.properties │ │ │ └── res/ │ │ │ └── values/ │ │ │ └── strings.xml │ │ ├── ijkplayer-armv5/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── gradle.properties │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ ├── androidTest/ │ │ │ │ └── java/ │ │ │ │ └── tv/ │ │ │ │ └── danmaku/ │ │ │ │ └── ijk/ │ │ │ │ └── media/ │ │ │ │ └── player_armv5/ │ │ │ │ └── ApplicationTest.java │ │ │ └── main/ │ │ │ ├── .classpath │ │ │ ├── .project │ │ │ ├── .settings/ │ │ │ │ └── org.eclipse.jdt.core.prefs │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── tv/ │ │ │ │ └── danmaku/ │ │ │ │ └── ijk/ │ │ │ │ └── media/ │ │ │ │ └── player_armv5/ │ │ │ │ └── Pragma.java │ │ │ ├── jni/ │ │ │ │ └── Application.mk │ │ │ ├── project.properties │ │ │ └── res/ │ │ │ └── values/ │ │ │ └── strings.xml │ │ ├── ijkplayer-armv7a/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── gradle.properties │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ ├── androidTest/ │ │ │ │ └── java/ │ │ │ │ └── tv/ │ │ │ │ └── danmaku/ │ │ │ │ └── ijk/ │ │ │ │ └── media/ │ │ │ │ └── player_armv7a/ │ │ │ │ └── ApplicationTest.java │ │ │ └── main/ │ │ │ ├── .classpath │ │ │ ├── .project │ │ │ ├── .settings/ │ │ │ │ └── org.eclipse.jdt.core.prefs │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── tv/ │ │ │ │ └── danmaku/ │ │ │ │ └── ijk/ │ │ │ │ └── media/ │ │ │ │ └── player_armv7a/ │ │ │ │ └── Pragma.java │ │ │ ├── jni/ │ │ │ │ ├── Android.mk │ │ │ │ ├── Application.mk │ │ │ │ └── ffmpeg/ │ │ │ │ └── Android.mk │ │ │ ├── project.properties │ │ │ └── res/ │ │ │ └── values/ │ │ │ └── strings.xml │ │ ├── ijkplayer-example/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ ├── androidTest/ │ │ │ │ └── java/ │ │ │ │ └── tv/ │ │ │ │ └── danmaku/ │ │ │ │ └── ijk/ │ │ │ │ └── media/ │ │ │ │ └── example/ │ │ │ │ └── ApplicationTest.java │ │ │ └── main/ │ │ │ ├── .classpath │ │ │ ├── .project │ │ │ ├── .settings/ │ │ │ │ └── org.eclipse.jdt.core.prefs │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── tv/ │ │ │ │ └── danmaku/ │ │ │ │ └── ijk/ │ │ │ │ └── media/ │ │ │ │ └── example/ │ │ │ │ ├── activities/ │ │ │ │ │ ├── FileExplorerActivity.java │ │ │ │ │ ├── RecentMediaActivity.java │ │ │ │ │ ├── SampleMediaActivity.java │ │ │ │ │ ├── SettingsActivity.java │ │ │ │ │ └── VideoActivity.java │ │ │ │ ├── application/ │ │ │ │ │ ├── AppActivity.java │ │ │ │ │ └── Settings.java │ │ │ │ ├── content/ │ │ │ │ │ ├── PathCursor.java │ │ │ │ │ ├── PathCursorLoader.java │ │ │ │ │ └── RecentMediaStorage.java │ │ │ │ ├── eventbus/ │ │ │ │ │ └── FileExplorerEvents.java │ │ │ │ ├── fragments/ │ │ │ │ │ ├── FileListFragment.java │ │ │ │ │ ├── RecentMediaListFragment.java │ │ │ │ │ ├── SampleMediaListFragment.java │ │ │ │ │ ├── SettingsFragment.java │ │ │ │ │ └── TracksFragment.java │ │ │ │ ├── services/ │ │ │ │ │ └── MediaPlayerService.java │ │ │ │ └── widget/ │ │ │ │ ├── media/ │ │ │ │ │ ├── AndroidMediaController.java │ │ │ │ │ ├── FileMediaDataSource.java │ │ │ │ │ ├── IMediaController.java │ │ │ │ │ ├── IRenderView.java │ │ │ │ │ ├── IjkVideoView.java │ │ │ │ │ ├── InfoHudViewHolder.java │ │ │ │ │ ├── MeasureHelper.java │ │ │ │ │ ├── MediaPlayerCompat.java │ │ │ │ │ ├── SurfaceRenderView.java │ │ │ │ │ ├── TableLayoutBinder.java │ │ │ │ │ └── TextureRenderView.java │ │ │ │ └── preference/ │ │ │ │ └── IjkListPreference.java │ │ │ ├── project.properties │ │ │ └── res/ │ │ │ ├── layout/ │ │ │ │ ├── activity_app.xml │ │ │ │ ├── activity_player.xml │ │ │ │ ├── fragment_file_list.xml │ │ │ │ ├── fragment_file_list_item.xml │ │ │ │ ├── fragment_track_list.xml │ │ │ │ ├── table_media_info.xml │ │ │ │ ├── table_media_info_row1.xml │ │ │ │ ├── table_media_info_row2.xml │ │ │ │ ├── table_media_info_section.xml │ │ │ │ └── widget_toolbar.xml │ │ │ ├── menu/ │ │ │ │ ├── menu_app.xml │ │ │ │ └── menu_player.xml │ │ │ ├── values/ │ │ │ │ ├── attrs.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ ├── strings_pref.xml │ │ │ │ ├── styles.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v11/ │ │ │ │ └── styles.xml │ │ │ ├── values-v14/ │ │ │ │ └── styles.xml │ │ │ ├── values-w820dp/ │ │ │ │ └── dimens.xml │ │ │ └── xml/ │ │ │ └── settings.xml │ │ ├── ijkplayer-exo/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── gradle.properties │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ ├── androidTest/ │ │ │ │ └── java/ │ │ │ │ └── tv/ │ │ │ │ └── danmaku/ │ │ │ │ └── ijk/ │ │ │ │ └── media/ │ │ │ │ └── exo/ │ │ │ │ └── ApplicationTest.java │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── tv/ │ │ │ │ └── danmaku/ │ │ │ │ └── ijk/ │ │ │ │ └── media/ │ │ │ │ └── exo/ │ │ │ │ ├── IjkExoMediaPlayer.java │ │ │ │ └── demo/ │ │ │ │ ├── EventLogger.java │ │ │ │ ├── SmoothStreamingTestMediaDrmCallback.java │ │ │ │ └── player/ │ │ │ │ ├── DashRendererBuilder.java │ │ │ │ ├── DemoPlayer.java │ │ │ │ ├── ExtractorRendererBuilder.java │ │ │ │ ├── HlsRendererBuilder.java │ │ │ │ └── SmoothStreamingRendererBuilder.java │ │ │ └── res/ │ │ │ └── values/ │ │ │ └── strings.xml │ │ ├── ijkplayer-java/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── gradle.properties │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ ├── androidTest/ │ │ │ │ └── java/ │ │ │ │ └── tv/ │ │ │ │ └── danmaku/ │ │ │ │ └── ijk/ │ │ │ │ └── media/ │ │ │ │ └── player/ │ │ │ │ └── ApplicationTest.java │ │ │ └── main/ │ │ │ ├── .classpath │ │ │ ├── .project │ │ │ ├── .settings/ │ │ │ │ └── org.eclipse.jdt.core.prefs │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── tv/ │ │ │ │ └── danmaku/ │ │ │ │ └── ijk/ │ │ │ │ └── media/ │ │ │ │ └── player/ │ │ │ │ ├── AbstractMediaPlayer.java │ │ │ │ ├── AndroidMediaPlayer.java │ │ │ │ ├── IMediaPlayer.java │ │ │ │ ├── ISurfaceTextureHolder.java │ │ │ │ ├── ISurfaceTextureHost.java │ │ │ │ ├── IjkLibLoader.java │ │ │ │ ├── IjkMediaCodecInfo.java │ │ │ │ ├── IjkMediaMeta.java │ │ │ │ ├── IjkMediaPlayer.java │ │ │ │ ├── IjkTimedText.java │ │ │ │ ├── MediaInfo.java │ │ │ │ ├── MediaPlayerProxy.java │ │ │ │ ├── TextureMediaPlayer.java │ │ │ │ ├── annotations/ │ │ │ │ │ ├── AccessedByNative.java │ │ │ │ │ └── CalledByNative.java │ │ │ │ ├── exceptions/ │ │ │ │ │ └── IjkMediaException.java │ │ │ │ ├── ffmpeg/ │ │ │ │ │ └── FFmpegApi.java │ │ │ │ ├── misc/ │ │ │ │ │ ├── AndroidMediaFormat.java │ │ │ │ │ ├── AndroidTrackInfo.java │ │ │ │ │ ├── IAndroidIO.java │ │ │ │ │ ├── IMediaDataSource.java │ │ │ │ │ ├── IMediaFormat.java │ │ │ │ │ ├── ITrackInfo.java │ │ │ │ │ ├── IjkMediaFormat.java │ │ │ │ │ └── IjkTrackInfo.java │ │ │ │ └── pragma/ │ │ │ │ ├── DebugLog.java │ │ │ │ └── Pragma.java │ │ │ ├── project.properties │ │ │ └── res/ │ │ │ └── values/ │ │ │ └── strings.xml │ │ ├── ijkplayer-x86/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── gradle.properties │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ ├── androidTest/ │ │ │ │ └── java/ │ │ │ │ └── tv/ │ │ │ │ └── danmaku/ │ │ │ │ └── ijk/ │ │ │ │ └── media/ │ │ │ │ └── ijkplayer/ │ │ │ │ └── ApplicationTest.java │ │ │ └── main/ │ │ │ ├── .classpath │ │ │ ├── .project │ │ │ ├── .settings/ │ │ │ │ └── org.eclipse.jdt.core.prefs │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── tv/ │ │ │ │ └── danmaku/ │ │ │ │ └── ijk/ │ │ │ │ └── media/ │ │ │ │ └── player_x86/ │ │ │ │ └── Pragma.java │ │ │ ├── jni/ │ │ │ │ ├── Application.mk │ │ │ │ └── ffmpeg/ │ │ │ │ └── Android.mk │ │ │ ├── project.properties │ │ │ └── res/ │ │ │ └── values/ │ │ │ └── strings.xml │ │ ├── ijkplayer-x86_64/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── gradle.properties │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ ├── androidTest/ │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── example/ │ │ │ │ └── ijkplayer_x86_64/ │ │ │ │ └── ApplicationTest.java │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── jni/ │ │ │ │ ├── Application.mk │ │ │ │ └── ffmpeg/ │ │ │ │ └── Android.mk │ │ │ └── res/ │ │ │ └── values/ │ │ │ └── strings.xml │ │ ├── settings.gradle │ │ └── tools/ │ │ ├── gradle-bintray-upload.gradle │ │ ├── gradle-mvn-push.gradle │ │ └── gradle-on-demand.gradle │ ├── patch-debugging-with-lldb.sh │ └── patches/ │ ├── 0001-gitignore-ignore-.externalNativeBuild.patch │ ├── 0002-gradle-upgrade-build-tool-to-2.2.0-beta2.patch │ ├── 0003-arm64-enable-debugging-with-LLDB.patch │ ├── 0003-armv5-enable-debugging-with-LLDB.patch │ ├── 0003-armv7a-enable-debugging-with-LLDB.patch │ ├── 0003-x86-enable-debugging-with-LLDB.patch │ ├── 0003-x86_64-enable-debugging-with-LLDB.patch │ ├── 0004-armv7a-link-prebuilt-staic-libraries-of-ffmepg.patch │ ├── 0004-x86-link-prebuilt-staic-libraries-of-ffmepg.patch │ └── 0004-x86_64-link-prebuilt-staic-libraries-of-ffmepg.patch ├── compile-android-j4a.sh ├── config/ │ ├── module-default.sh │ ├── module-lite-hevc.sh │ └── module-lite.sh ├── doc/ │ └── preflight_checklist.md ├── ijkmedia/ │ ├── Android.mk │ ├── ijkj4a/ │ │ ├── .gitignore │ │ ├── Android.mk │ │ ├── Makefile │ │ ├── j4a/ │ │ │ ├── class/ │ │ │ │ ├── android/ │ │ │ │ │ ├── media/ │ │ │ │ │ │ ├── AudioTrack.c │ │ │ │ │ │ ├── AudioTrack.h │ │ │ │ │ │ ├── AudioTrack.include.j4a │ │ │ │ │ │ ├── AudioTrack.loader.j4a │ │ │ │ │ │ ├── MediaCodec.c │ │ │ │ │ │ ├── MediaCodec.h │ │ │ │ │ │ ├── MediaCodec.include.j4a │ │ │ │ │ │ ├── MediaCodec.loader.j4a │ │ │ │ │ │ ├── MediaFormat.c │ │ │ │ │ │ ├── MediaFormat.h │ │ │ │ │ │ ├── MediaFormat.include.j4a │ │ │ │ │ │ ├── MediaFormat.loader.j4a │ │ │ │ │ │ ├── PlaybackParams.c │ │ │ │ │ │ ├── PlaybackParams.h │ │ │ │ │ │ ├── PlaybackParams.include.j4a │ │ │ │ │ │ └── PlaybackParams.loader.j4a │ │ │ │ │ └── os/ │ │ │ │ │ ├── Build.c │ │ │ │ │ ├── Build.h │ │ │ │ │ ├── Build.include.j4a │ │ │ │ │ ├── Build.loader.j4a │ │ │ │ │ ├── Bundle.c │ │ │ │ │ ├── Bundle.h │ │ │ │ │ ├── Bundle.include.j4a │ │ │ │ │ └── Bundle.loader.j4a │ │ │ │ ├── java/ │ │ │ │ │ ├── nio/ │ │ │ │ │ │ ├── Buffer.c │ │ │ │ │ │ ├── Buffer.h │ │ │ │ │ │ ├── Buffer.include.j4a │ │ │ │ │ │ ├── Buffer.loader.j4a │ │ │ │ │ │ ├── ByteBuffer.c │ │ │ │ │ │ ├── ByteBuffer.h │ │ │ │ │ │ ├── ByteBuffer.include.j4a │ │ │ │ │ │ └── ByteBuffer.loader.j4a │ │ │ │ │ └── util/ │ │ │ │ │ ├── ArrayList.c │ │ │ │ │ ├── ArrayList.h │ │ │ │ │ ├── ArrayList.include.j4a │ │ │ │ │ └── ArrayList.loader.j4a │ │ │ │ └── tv/ │ │ │ │ └── danmaku/ │ │ │ │ └── ijk/ │ │ │ │ └── media/ │ │ │ │ └── player/ │ │ │ │ ├── IjkMediaPlayer.c │ │ │ │ ├── IjkMediaPlayer.h │ │ │ │ ├── IjkMediaPlayer.include.j4a │ │ │ │ ├── IjkMediaPlayer.loader.j4a │ │ │ │ └── misc/ │ │ │ │ ├── IAndroidIO.c │ │ │ │ ├── IAndroidIO.h │ │ │ │ ├── IAndroidIO.include.j4a │ │ │ │ ├── IAndroidIO.loader.j4a │ │ │ │ ├── IMediaDataSource.c │ │ │ │ ├── IMediaDataSource.h │ │ │ │ ├── IMediaDataSource.include.j4a │ │ │ │ └── IMediaDataSource.loader.j4a │ │ │ ├── j4a_allclasses.c │ │ │ ├── j4a_allclasses.h │ │ │ ├── j4a_allclasses.include.h │ │ │ ├── j4a_allclasses.loader.h │ │ │ ├── j4a_base.c │ │ │ └── j4a_base.h │ │ ├── j4au/ │ │ │ └── class/ │ │ │ ├── android/ │ │ │ │ └── media/ │ │ │ │ ├── AudioTrack.util.c │ │ │ │ └── AudioTrack.util.h │ │ │ └── java/ │ │ │ └── nio/ │ │ │ ├── ByteBuffer.util.c │ │ │ └── ByteBuffer.util.h │ │ └── java/ │ │ ├── android/ │ │ │ ├── media/ │ │ │ │ ├── AudioTrack.java │ │ │ │ ├── MediaCodec.java │ │ │ │ ├── MediaCrypto.java │ │ │ │ ├── MediaFormat.java │ │ │ │ └── PlaybackParams.java │ │ │ └── os/ │ │ │ ├── Build.java │ │ │ └── Bundle.java │ │ ├── java/ │ │ │ ├── nio/ │ │ │ │ ├── Buffer.java │ │ │ │ └── ByteBuffer.java │ │ │ └── util/ │ │ │ └── ArrayList.java │ │ └── tv/ │ │ └── danmaku/ │ │ └── ijk/ │ │ └── media/ │ │ └── player/ │ │ ├── IjkMediaPlayer.java │ │ └── misc/ │ │ ├── IAndroidIO.java │ │ └── IMediaDataSource.java │ ├── ijkplayer/ │ │ ├── .gitignore │ │ ├── Android.mk │ │ ├── android/ │ │ │ ├── ffmpeg_api_jni.c │ │ │ ├── ffmpeg_api_jni.h │ │ │ ├── ijkplayer_android.c │ │ │ ├── ijkplayer_android.h │ │ │ ├── ijkplayer_android_def.h │ │ │ ├── ijkplayer_jni.c │ │ │ └── pipeline/ │ │ │ ├── ffpipeline_android.c │ │ │ ├── ffpipeline_android.h │ │ │ ├── ffpipenode_android_mediacodec_vdec.c │ │ │ ├── ffpipenode_android_mediacodec_vdec.h │ │ │ ├── h264_nal.h │ │ │ ├── hevc_nal.h │ │ │ └── mpeg4_esds.h │ │ ├── config.h │ │ ├── ff_cmdutils.c │ │ ├── ff_cmdutils.h │ │ ├── ff_fferror.h │ │ ├── ff_ffinc.h │ │ ├── ff_ffmsg.h │ │ ├── ff_ffmsg_queue.h │ │ ├── ff_ffpipeline.c │ │ ├── ff_ffpipeline.h │ │ ├── ff_ffpipenode.c │ │ ├── ff_ffpipenode.h │ │ ├── ff_ffplay.c │ │ ├── ff_ffplay.h │ │ ├── ff_ffplay_debug.h │ │ ├── ff_ffplay_def.h │ │ ├── ff_ffplay_options.h │ │ ├── ijkavformat/ │ │ │ ├── allformats.c │ │ │ ├── cJSON.c │ │ │ ├── cJSON.h │ │ │ ├── ijkasync.c │ │ │ ├── ijkavformat.h │ │ │ ├── ijkio.c │ │ │ ├── ijkioandroidio.c │ │ │ ├── ijkioapplication.c │ │ │ ├── ijkioapplication.h │ │ │ ├── ijkiocache.c │ │ │ ├── ijkioffio.c │ │ │ ├── ijkiomanager.c │ │ │ ├── ijkiomanager.h │ │ │ ├── ijkioprotocol.c │ │ │ ├── ijkioprotocol.h │ │ │ ├── ijkiourl.h │ │ │ ├── ijkiourlhook.c │ │ │ ├── ijklas.c │ │ │ ├── ijklas.h │ │ │ ├── ijklivehook.c │ │ │ ├── ijklongurl.c │ │ │ ├── ijkmediadatasource.c │ │ │ ├── ijksegment.c │ │ │ └── ijkurlhook.c │ │ ├── ijkavutil/ │ │ │ ├── ijkdict.c │ │ │ ├── ijkdict.h │ │ │ ├── ijkfifo.c │ │ │ ├── ijkfifo.h │ │ │ ├── ijkstl.cpp │ │ │ ├── ijkstl.h │ │ │ ├── ijkthreadpool.c │ │ │ ├── ijkthreadpool.h │ │ │ ├── ijktree.c │ │ │ ├── ijktree.h │ │ │ ├── ijkutils.c │ │ │ ├── ijkutils.h │ │ │ └── opt.h │ │ ├── ijkmeta.c │ │ ├── ijkmeta.h │ │ ├── ijkplayer.c │ │ ├── ijkplayer.h │ │ ├── ijkplayer_internal.h │ │ ├── pipeline/ │ │ │ ├── ffpipeline_ffplay.c │ │ │ ├── ffpipeline_ffplay.h │ │ │ ├── ffpipenode_ffplay_vdec.c │ │ │ └── ffpipenode_ffplay_vdec.h │ │ └── version.sh │ └── ijksdl/ │ ├── Android.mk │ ├── android/ │ │ ├── android_audiotrack.c │ │ ├── android_audiotrack.h │ │ ├── android_nativewindow.c │ │ ├── android_nativewindow.h │ │ ├── ijksdl_android.h │ │ ├── ijksdl_android_jni.c │ │ ├── ijksdl_android_jni.h │ │ ├── ijksdl_aout_android_audiotrack.c │ │ ├── ijksdl_aout_android_audiotrack.h │ │ ├── ijksdl_aout_android_opensles.c │ │ ├── ijksdl_aout_android_opensles.h │ │ ├── ijksdl_codec_android_mediacodec.c │ │ ├── ijksdl_codec_android_mediacodec.h │ │ ├── ijksdl_codec_android_mediacodec_dummy.c │ │ ├── ijksdl_codec_android_mediacodec_dummy.h │ │ ├── ijksdl_codec_android_mediacodec_internal.c │ │ ├── ijksdl_codec_android_mediacodec_internal.h │ │ ├── ijksdl_codec_android_mediacodec_java.c │ │ ├── ijksdl_codec_android_mediacodec_java.h │ │ ├── ijksdl_codec_android_mediadef.c │ │ ├── ijksdl_codec_android_mediadef.h │ │ ├── ijksdl_codec_android_mediaformat.c │ │ ├── ijksdl_codec_android_mediaformat.h │ │ ├── ijksdl_codec_android_mediaformat_internal.h │ │ ├── ijksdl_codec_android_mediaformat_java.c │ │ ├── ijksdl_codec_android_mediaformat_java.h │ │ ├── ijksdl_inc_internal_android.h │ │ ├── ijksdl_vout_android_nativewindow.c │ │ ├── ijksdl_vout_android_nativewindow.h │ │ ├── ijksdl_vout_android_surface.c │ │ ├── ijksdl_vout_android_surface.h │ │ ├── ijksdl_vout_overlay_android_mediacodec.c │ │ └── ijksdl_vout_overlay_android_mediacodec.h │ ├── dummy/ │ │ ├── ijksdl_dummy.h │ │ ├── ijksdl_vout_dummy.c │ │ └── ijksdl_vout_dummy.h │ ├── ffmpeg/ │ │ ├── abi_all/ │ │ │ └── image_convert.c │ │ ├── ijksdl_image_convert.h │ │ ├── ijksdl_inc_ffmpeg.h │ │ ├── ijksdl_vout_overlay_ffmpeg.c │ │ └── ijksdl_vout_overlay_ffmpeg.h │ ├── gles2/ │ │ ├── color.c │ │ ├── common.c │ │ ├── fsh/ │ │ │ ├── rgb.fsh.c │ │ │ ├── yuv420p.fsh.c │ │ │ ├── yuv420sp.fsh.c │ │ │ └── yuv444p10le.fsh.c │ │ ├── internal.h │ │ ├── renderer.c │ │ ├── renderer_rgb.c │ │ ├── renderer_yuv420p.c │ │ ├── renderer_yuv420sp.c │ │ ├── renderer_yuv420sp_vtb.m │ │ ├── renderer_yuv444p10le.c │ │ ├── shader.c │ │ └── vsh/ │ │ └── mvp.vsh.c │ ├── ijksdl.h │ ├── ijksdl_aout.c │ ├── ijksdl_aout.h │ ├── ijksdl_aout_internal.h │ ├── ijksdl_audio.c │ ├── ijksdl_audio.h │ ├── ijksdl_class.h │ ├── ijksdl_container.h │ ├── ijksdl_egl.c │ ├── ijksdl_egl.h │ ├── ijksdl_endian.h │ ├── ijksdl_error.c │ ├── ijksdl_error.h │ ├── ijksdl_extra_log.c │ ├── ijksdl_extra_log.h │ ├── ijksdl_fourcc.h │ ├── ijksdl_gles2.h │ ├── ijksdl_inc_internal.h │ ├── ijksdl_log.h │ ├── ijksdl_misc.h │ ├── ijksdl_mutex.c │ ├── ijksdl_mutex.h │ ├── ijksdl_stdinc.c │ ├── ijksdl_stdinc.h │ ├── ijksdl_thread.c │ ├── ijksdl_thread.h │ ├── ijksdl_timer.c │ ├── ijksdl_timer.h │ ├── ijksdl_video.h │ ├── ijksdl_vout.c │ ├── ijksdl_vout.h │ └── ijksdl_vout_internal.h ├── ijkprof/ │ └── android-ndk-profiler-dummy/ │ └── jni/ │ ├── Android-include.mk │ ├── Android.mk │ ├── prof.c │ └── prof.h ├── init-android-exo.sh ├── init-android-j4a.sh ├── init-android-libsoxr.sh ├── init-android-libyuv.sh ├── init-android-openssl.sh ├── init-android-prof.sh ├── init-android-soundtouch.sh ├── init-android.sh ├── init-config.sh ├── init-ios-openssl.sh ├── init-ios.sh ├── ios/ │ ├── .gitignore │ ├── IJKMediaDemo/ │ │ ├── IJKMediaDemo/ │ │ │ ├── AppIcons.xcassets/ │ │ │ │ └── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ ├── Barcode.h │ │ │ ├── Barcode.m │ │ │ ├── IJKAppDelegate.h │ │ │ ├── IJKAppDelegate.m │ │ │ ├── IJKCommon.h │ │ │ ├── IJKDemoHistory.h │ │ │ ├── IJKDemoHistory.m │ │ │ ├── IJKDemoInputURLViewController.h │ │ │ ├── IJKDemoInputURLViewController.m │ │ │ ├── IJKDemoInputURLViewController.xib │ │ │ ├── IJKDemoLocalFolderViewController.h │ │ │ ├── IJKDemoLocalFolderViewController.m │ │ │ ├── IJKDemoMainViewController.h │ │ │ ├── IJKDemoMainViewController.m │ │ │ ├── IJKDemoMainViewController.xib │ │ │ ├── IJKDemoSampleViewController.h │ │ │ ├── IJKDemoSampleViewController.m │ │ │ ├── IJKDemoSampleViewController.xib │ │ │ ├── IJKMediaControl.h │ │ │ ├── IJKMediaControl.m │ │ │ ├── IJKMediaDemo-Info.plist │ │ │ ├── IJKMediaDemo-Prefix.pch │ │ │ ├── IJKMoviePlayerViewController.h │ │ │ ├── IJKMoviePlayerViewController.m │ │ │ ├── IJKMoviePlayerViewController.xib │ │ │ ├── IJKQRCodeScanViewController.h │ │ │ ├── IJKQRCodeScanViewController.m │ │ │ ├── IJKQRCodeScanViewController.xib │ │ │ ├── Images.xcassets/ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ └── Contents.json │ │ │ │ └── LaunchImage.launchimage/ │ │ │ │ └── Contents.json │ │ │ ├── LaunchScreen.xib │ │ │ ├── en.lproj/ │ │ │ │ └── InfoPlist.strings │ │ │ └── main.m │ │ ├── IJKMediaDemo.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ └── project.xcworkspace/ │ │ │ └── contents.xcworkspacedata │ │ └── XCAssets/ │ │ ├── AppIcons.xcassets/ │ │ │ └── AppIcon.appiconset/ │ │ │ └── Contents.json │ │ ├── LaunchImages.xcassets/ │ │ │ └── LaunchImage.launchimage/ │ │ │ └── Contents.json │ │ └── MoviePlayerImages.xcassets/ │ │ └── MoviePlayer/ │ │ ├── btn_player_back_highlighted.imageset/ │ │ │ └── Contents.json │ │ ├── btn_player_pause.imageset/ │ │ │ └── Contents.json │ │ ├── btn_player_play.imageset/ │ │ │ └── Contents.json │ │ ├── player_bottom_control_bg.imageset/ │ │ │ └── Contents.json │ │ └── player_top_control_bg.imageset/ │ │ └── Contents.json │ ├── IJKMediaPlayer/ │ │ ├── IJKMediaFramework/ │ │ │ ├── IJKMediaFramework.h │ │ │ └── Info.plist │ │ ├── IJKMediaFrameworkTests/ │ │ │ ├── IJKMediaFrameworkTests.m │ │ │ └── Info.plist │ │ ├── IJKMediaFrameworkWithSSL/ │ │ │ └── IJKMediaFrameworkWithSSL.h │ │ ├── IJKMediaFrameworkWithSSL.plist │ │ ├── IJKMediaPlayer/ │ │ │ ├── IJKAVMoviePlayerController.h │ │ │ ├── IJKAVMoviePlayerController.m │ │ │ ├── IJKAVPlayerLayerView.h │ │ │ ├── IJKAVPlayerLayerView.m │ │ │ ├── IJKAudioKit.h │ │ │ ├── IJKAudioKit.m │ │ │ ├── IJKDeviceModel.h │ │ │ ├── IJKDeviceModel.m │ │ │ ├── IJKFFMonitor.h │ │ │ ├── IJKFFMonitor.m │ │ │ ├── IJKFFMoviePlayerController.h │ │ │ ├── IJKFFMoviePlayerController.m │ │ │ ├── IJKFFMoviePlayerDef.h │ │ │ ├── IJKFFMoviePlayerDef.m │ │ │ ├── IJKFFOptions.h │ │ │ ├── IJKFFOptions.m │ │ │ ├── IJKKVOController.h │ │ │ ├── IJKKVOController.m │ │ │ ├── IJKMPMoviePlayerController.h │ │ │ ├── IJKMPMoviePlayerController.m │ │ │ ├── IJKMediaModule.h │ │ │ ├── IJKMediaModule.m │ │ │ ├── IJKMediaPlayback.h │ │ │ ├── IJKMediaPlayback.m │ │ │ ├── IJKMediaPlayer-Prefix.pch │ │ │ ├── IJKMediaPlayer.h │ │ │ ├── IJKMediaUtils.h │ │ │ ├── IJKMediaUtils.m │ │ │ ├── IJKNotificationManager.h │ │ │ ├── IJKNotificationManager.m │ │ │ ├── IJKSDLGLViewProtocol.h │ │ │ ├── NSString+IJKMedia.h │ │ │ ├── NSString+IJKMedia.m │ │ │ └── ijkmedia/ │ │ │ ├── ijkplayer/ │ │ │ │ └── ios/ │ │ │ │ ├── ijkplayer_ios.h │ │ │ │ ├── ijkplayer_ios.m │ │ │ │ └── pipeline/ │ │ │ │ ├── IJKVideoToolBox.h │ │ │ │ ├── IJKVideoToolBox.m │ │ │ │ ├── IJKVideoToolBoxAsync.h │ │ │ │ ├── IJKVideoToolBoxAsync.m │ │ │ │ ├── IJKVideoToolBoxSync.h │ │ │ │ ├── IJKVideoToolBoxSync.m │ │ │ │ ├── ffpipeline_ios.c │ │ │ │ ├── ffpipeline_ios.h │ │ │ │ ├── ffpipenode_ios_videotoolbox_vdec.h │ │ │ │ ├── ffpipenode_ios_videotoolbox_vdec.m │ │ │ │ └── h264_sps_parser.h │ │ │ └── ijksdl/ │ │ │ └── ios/ │ │ │ ├── IJKSDLAudioKit.h │ │ │ ├── IJKSDLAudioKit.m │ │ │ ├── IJKSDLAudioQueueController.h │ │ │ ├── IJKSDLAudioQueueController.m │ │ │ ├── IJKSDLAudioUnitController.h │ │ │ ├── IJKSDLAudioUnitController.m │ │ │ ├── IJKSDLGLView.h │ │ │ ├── IJKSDLGLView.m │ │ │ ├── IJKSDLHudViewCell.h │ │ │ ├── IJKSDLHudViewCell.m │ │ │ ├── IJKSDLHudViewController.h │ │ │ ├── IJKSDLHudViewController.m │ │ │ ├── ijksdl_aout_ios_audiounit.h │ │ │ ├── ijksdl_aout_ios_audiounit.m │ │ │ ├── ijksdl_ios.h │ │ │ ├── ijksdl_thread_ios.h │ │ │ ├── ijksdl_thread_ios.m │ │ │ ├── ijksdl_vout_ios_gles2.h │ │ │ ├── ijksdl_vout_ios_gles2.m │ │ │ ├── ijksdl_vout_overlay_videotoolbox.h │ │ │ └── ijksdl_vout_overlay_videotoolbox.m │ │ └── IJKMediaPlayer.xcodeproj/ │ │ ├── project.pbxproj │ │ └── project.xcworkspace/ │ │ └── contents.xcworkspacedata │ ├── IJKMediaPodDemo/ │ │ ├── .gitignore │ │ ├── IJKMediaPodDemo/ │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── Base.lproj/ │ │ │ │ ├── LaunchScreen.xib │ │ │ │ └── Main.storyboard │ │ │ ├── Images.xcassets/ │ │ │ │ └── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ ├── Info.plist │ │ │ ├── ViewController.h │ │ │ ├── ViewController.m │ │ │ └── main.m │ │ ├── IJKMediaPodDemo.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ └── project.xcworkspace/ │ │ │ └── contents.xcworkspacedata │ │ ├── IJKMediaPodDemoTests/ │ │ │ ├── IJKMediaPodDemoTests.m │ │ │ └── Info.plist │ │ └── Podfile │ ├── compile-ffmpeg.sh │ ├── compile-openssl.sh │ └── tools/ │ ├── avconfig.h │ ├── config.h │ ├── do-compile-ffmpeg.sh │ ├── do-compile-openssl.sh │ └── ffversion.h ├── tools/ │ ├── .gitignore │ ├── copyrighter/ │ │ ├── CRContext.py │ │ ├── CRCopyright.py │ │ ├── CRFile.py │ │ ├── __init__.py │ │ └── __main__.py │ ├── pull-repo-base.sh │ ├── pull-repo-ref.sh │ ├── setup-as-commiter.sh │ └── sync-mirrors.sh └── version.sh ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # ----- build/ ffmpeg-temp/ android/ffmpeg-* android/openssl-* ios/ffmpeg-* ios/openssl-* extra .DS_Store ijkmedia/ijkyuv/ ijkmedia/ijksoundtouch ijkprof/android-ndk-profiler/ # built application files *.apk *.ap_ # files for the dex VM *.dex # Java class files *.class # generated files bin/ gen/ libs/ obj/ ijkmedia/ijkplayer/ijkversion.h # Local configuration file (sdk path, etc) local.properties # Android Studio .idea .gradle build/ # Xcode xcuserdata xcshareddata *.xccheckout ================================================ FILE: .travis.yml ================================================ language: android android: components: - platform-tools - tools - build-tools-23.0.3 - android-23 - extra-android-support - extra-android-m2repository script: - cd android/ijkplayer - ./gradlew assemble ================================================ FILE: COPYING.GPLv2 ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ================================================ FILE: COPYING.GPLv3 ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: COPYING.LGPLv2.1 ================================================ GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library 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. This library 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 this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ================================================ FILE: COPYING.LGPLv3 ================================================ GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. ================================================ FILE: MODULE_LICENSE_APACHE2 ================================================ ================================================ FILE: NEWS.md ================================================ tag next -------------------------------- - ffmpeg: upgrade to 4.0 tag k0.8.8 -------------------------------- - ffmpeg: upgrade to 3.4 - ffmpeg: fix hls some issue - android: fix seek bug when no audio - openssl: upgrade to 1.0.2n - ios: vtb support h265 tag k0.8.7 -------------------------------- tag k0.8.6 -------------------------------- - ijkplayer: fix opengl config error - ffmpeg: fix a concat issue tag k0.8.5 -------------------------------- - ijkplayer: fix opengl config error - ijkplayer: fix some bug about audio tag k0.8.4 -------------------------------- - ffmpeg: enable hevc by default - ijkio: support cache share - ijkplayer: fix some bug tag k0.8.3 -------------------------------- - ffmpeg: dns cache refactor - ijkio: cache support synchronize read avoid frequent lseek - ijkplayer: fix some bug tag k0.8.2 -------------------------------- - ffmpeg: fix some bug - ijkio: update and modify features - ijkplayer: support don't calculate real frame rate, the first frame will speed up tag k0.8.1 -------------------------------- - ffmpeg: support dns cache - ijkio: support inject extra node tag k0.8.0 -------------------------------- - ffmpeg: upgrade to 3.3 - ffmpeg: enable flac - android: support sync mediacodec - android: support framedrop when use mediacodec - openssl: upgrade to 1.0.2k - jni4android: upgrade to v0.0.2 tag k0.7.9 -------------------------------- - ffmpeg: add tcp timeout control - android: support soundtouch tag k0.7.8 -------------------------------- - ffplay: support accurate seek - ijkio: fix some issue - ios: add ijkplayer dynamic target with ssl tag k0.7.7 -------------------------------- - ffmpeg: enable ijkio protocol - ffmpeg: avoid some unreasonable pts - ios: fix a crash caused by videotoolbox sync initialization fail tag k0.7.6 -------------------------------- - ffmpeg: ass subtitle support - msg_queue: add resource for msg_queue - ios: separate vtb sync mode from mixed vtb - android: fix some thread competition - android: support setSpeed for pre-M(api<23) versions tag k0.7.5 -------------------------------- - ffmpeg: disable-asm on architecture x86 - ffmpeg: revert some cutted demuxer and decoder - ios: add playback volume interface tag k0.7.4 -------------------------------- - ffplay: fix sample buffer leak introduced in k0.7.1 - doc: add takeoff checklist tag k0.7.3 -------------------------------- - ios: turn videotoolbox into singleton - ffmpeg: merge ipv6 issue in tcp.c tag k0.7.2 ------------------------------- - ios: fix a compile error tag k0.7.1 ------------------------------- - ffmpeg: upgrade to n3.2 tag k0.6.3 -------------------------------- - ffmpeg: disable clock_gettime added in xcode8 - android: make NDKr13 happy tag k0.6.2 -------------------------------- - ffmpeg: fix wild pointer when decoder was not found - player: fix bug introduced in k0.6.0 tag k0.6.1 -------------------------------- - concat: fix crash introduced in k0.6.0 - flvdec: fix seek problem introduced in k0.6.0 - hls: fix regression with ranged media segments tag k0.6.0 -------------------------------- - openssl: upgrade to 1.0.2h - ffmpeg: upgrade to n3.1 - MediaCodec: add options to enable resolution change. - VideoToolbox: add options to enable resolution change. tag k0.5.1 -------------------------------- - ffmpeg: fix crash introduced in k0.5.0 tag k0.5.0 -------------------------------- - ffmpeg: upgrade to n3.0 - android: support NDKr11 tag k0.4.5 -------------------------------- - ios: support playbackRate change. (iOS 7.0 or later) - android: support speed change. (Android 6.0 or later) - player: do not link avfilter by default. - android: add x86_64 support - android: move jjk out to jni4android project - android: support OpenGL ES2 render tag k0.4.4 -------------------------------- - ios: replace MPMoviePlayerXXX with IJKMPMoviePlayerXXX - ios: remove target 'IjkMediaPlayer'. 'IjkMediaFramework' should be used instead. - android: switch ExoPlayer to r1.5.2 tag k0.4.3 -------------------------------- - android: fix several crash when reconfiguring MediaCodec - android: add jjk to generate API native wrapper - android: support IMediaDataSource for user to supply media data tag k0.4.2 -------------------------------- - ios: support Xcode 7 - ios: drop support of iOS 5.x - ffmpeg: enable libavfilter - player: limited support of libavfilter - android: add ExoPlayer as an alternative backend player tag k0.4.1 -------------------------------- - android: support downloading from jcenter tag k0.4.0 -------------------------------- - ffmpeg: switch to ffmpeg n2.8 tag k0.3.3 -------------------------------- - player: custom protocol as io hook - android/sample: support rotation meta (TextureView only) tag k0.3.2 -------------------------------- - android: drop support of Eclipse - android: update to SDK 23 - android/sample: better UI - ios: support SAR - android/sample: support background play tag k0.3.1 -------------------------------- - player: key-value options API - player: remove ijkutil - build: support cygwin - ios: optimize performance of VideoToolbox. tag k0.3.0 -------------------------------- - android: support build with Android Studio / Gradle - build: improve library fetch - openssl: switch to openssl 1.0.1o tag k0.2.4 -------------------------------- - ios: remove armv7s build from default - player: introduce key-value options - ios: demo improvement - ios: support init/play in background. - ffmpeg: switch to ffmpeg n2.7 tag k0.2.3 -------------------------------- - android: support OpenSL ES - ios: support NV12 Render - ios: support VideoToolBox - ffmpeg: switch to ffmpeg n2.6 tag n0.2.2: -------------------------------- - ffmpeg: switch to ffmpeg n2.5 - android: fix leak in jni - player: retrieve media informations tag n0.2.1: -------------------------------- - android: support MediaCodec (API 16+) tag n0.2.0 -------------------------------- - player: fix crash on invalid audio - android: support build with ndk-r10 - ios: add IJKAVMoviePlayerController based on AVPlayer API - ios: remove some unused interface - ios8: fix latency of aout_pause_audio() - ios8: upgrade project - ffmpeg: switch to ffmpeg n2.4 tag n0.1.3 -------------------------------- - ffmpeg: switch to ffmpeg n2.2 - player: fix complete/error state handle - ffmpeg: build with x86_64, armv5 - android: replace vlc-chroma-asm with libyuv tag n0.1.2: -------------------------------- - ffmpeg: build with openssl - player: fix aout leak - player: reduce memory footprint for I420/YV12 overlay - ios: snapshot last displayed image tag n0.1.1: -------------------------------- - player: remove ugly frame drop trick - ios: simplify application state handle - ios: fix 5.1 channel support - player: handle ffmpeg error - player: fix leak - player: improve buffer indicator - player: drop frame for high fps video tag n0.1.0: -------------------------------- - android: replace AbstractMediaPlayer with IMediaPlayer and other misc interfaces - android: remove list player classes due to lack of regression test - ios: support build with SDK7 - ffmpeg: switch to n2.1 base - ios: fix possible block on ijkmp_pause - ios: set CAEAGLLayer.contentsScale to avoid bad image on retina devices - ios: fix handle of AudioSession interruption - ios: add AudioQueue api as replacement of AudioUnit api - ijksdl: fix non-I420 pixel-format support - player: improve late packet/frame dropping - player: prefer h264 stream if multiple video stream exists tag n0.0.6: -------------------------------- - android: fix NativeWindow leak - ios: fix a deadlock related to AudioUnit - ios: support ffmpeg concat playback - ios: add ffmpeg options methods - android: limait audio sample-rate to 4kHz~48kHz - ios: fix gles texture alignment tag n0.0.5: -------------------------------- - build: disable -fmodulo-sched -fmodulo-sched-allow-regmoves, may crash on gcc4.7~4.8 - player: support ios - ijksdl: support ios gles2 video output - ijksdl: support ios AudioUnit audio output - build: add android/ios sub directory - player: fix some dead lock - build: use shell scripts instead of git-submodule - android: use RV32 as default chroma tag n0.0.4: -------------------------------- - ffmpeg: enable ac3 - android: target API-18 - build: switch to NDKr9 gcc4.8 toolchain tag n0.0.3: -------------------------------- - ffmpeg: switch to tag n2.0 - ffmpeg: remove rarely used decoders, parsers, demuxers - avformat/hls: fix many bugs - avformat/http: support reading compressed data - avformat/mov: optimize short seek - player: fix AudioTrack latency - player: refactor play/pause/step/buffering logic - player: fix A/V sync - yuv2rgb: treat YUVJ420P as YUV420P - yuv2rgb: support zero copy of YUV420P frame output to YV12 surface - ijksdl: fix SDL_GetTickHR() returns wrong time ================================================ FILE: NOTICE ================================================ Copyright (c) 2005-2008, The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS ================================================ FILE: README.md ================================================ # ijkplayer 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) iOS | [![Build Status](https://travis-ci.org/Bilibili/ci-ijk-ffmpeg-ios.svg?branch=master)](https://travis-ci.org/Bilibili/ci-ijk-ffmpeg-ios) Video player based on [ffplay](http://ffmpeg.org) ### Download - Android: - Gradle ``` # required allprojects { repositories { jcenter() } } dependencies { # required, enough for most devices. compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8' compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8' # Other ABIs: optional compile 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8' compile 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8' compile 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8' compile 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8' # ExoPlayer as IMediaPlayer: optional, experimental compile 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.8' } ``` - iOS - in coming... ### My Build Environment - Common - Mac OS X 10.11.5 - Android - [NDK r10e](http://developer.android.com/tools/sdk/ndk/index.html) - Android Studio 2.1.3 - Gradle 2.14.1 - iOS - Xcode 7.3 (7D175) - [HomeBrew](http://brew.sh) - ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" - brew install git ### Latest Changes - [NEWS.md](NEWS.md) ### Features - Common - remove rarely used ffmpeg components to reduce binary size [config/module-lite.sh](config/module-lite.sh) - workaround for some buggy online video. - Android - platform: API 9~23 - cpu: ARMv7a, ARM64v8a, x86 (ARMv5 is not tested on real devices) - api: [MediaPlayer-like](android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IMediaPlayer.java) - video-output: NativeWindow, OpenGL ES 2.0 - audio-output: AudioTrack, OpenSL ES - hw-decoder: MediaCodec (API 16+, Android 4.1+) - alternative-backend: android.media.MediaPlayer, ExoPlayer - iOS - platform: iOS 7.0~10.2.x - cpu: armv7, arm64, i386, x86_64, (armv7s is obselete) - api: [MediaPlayer.framework-like](ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.h) - video-output: OpenGL ES 2.0 - audio-output: AudioQueue, AudioUnit - hw-decoder: VideoToolbox (iOS 8+) - alternative-backend: AVFoundation.Framework.AVPlayer, MediaPlayer.Framework.MPMoviePlayerControlelr (obselete since iOS 8) ### NOT-ON-PLAN - obsolete platforms (Android: API-8 and below; iOS: pre-6.0) - obsolete cpu: ARMv5, ARMv6, MIPS (I don't even have these types of devices…) - native subtitle render - avfilter support ### Before Build ``` # install homebrew, git, yasm ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" brew install git brew install yasm # add these lines to your ~/.bash_profile or ~/.profile # export ANDROID_SDK= # export ANDROID_NDK= # on Cygwin (unmaintained) # install git, make, yasm ``` - If you prefer more codec/format ``` cd config rm module.sh ln -s module-default.sh module.sh cd android/contrib # cd ios sh compile-ffmpeg.sh clean ``` - If you prefer less codec/format for smaller binary size (include hevc function) ``` cd config rm module.sh ln -s module-lite-hevc.sh module.sh cd android/contrib # cd ios sh compile-ffmpeg.sh clean ``` - If you prefer less codec/format for smaller binary size (by default) ``` cd config rm module.sh ln -s module-lite.sh module.sh cd android/contrib # cd ios sh compile-ffmpeg.sh clean ``` - For Ubuntu/Debian users. ``` # choose [No] to use bash sudo dpkg-reconfigure dash ``` - If you'd like to share your config, pull request is welcome. ### Build Android ``` git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-android cd ijkplayer-android git checkout -B latest k0.8.8 ./init-android.sh cd android/contrib ./compile-ffmpeg.sh clean ./compile-ffmpeg.sh all cd .. ./compile-ijk.sh all # Android Studio: # Open an existing Android Studio project # Select android/ijkplayer/ and import # # define ext block in your root build.gradle # ext { # compileSdkVersion = 23 // depending on your sdk version # buildToolsVersion = "23.0.0" // depending on your build tools version # # targetSdkVersion = 23 // depending on your sdk version # } # # If you want to enable debugging ijkplayer(native modules) on Android Studio 2.2+: (experimental) # sh android/patch-debugging-with-lldb.sh armv7a # Install Android Studio 2.2(+) # Preference -> Android SDK -> SDK Tools # Select (LLDB, NDK, Android SDK Build-tools,Cmake) and install # Open an existing Android Studio project # Select android/ijkplayer # Sync Project with Gradle Files # Run -> Edit Configurations -> Debugger -> Symbol Directories # Add "ijkplayer-armv7a/.externalNativeBuild/ndkBuild/release/obj/local/armeabi-v7a" to Symbol Directories # Run -> Debug 'ijkplayer-example' # if you want to reverse patches: # sh patch-debugging-with-lldb.sh reverse armv7a # # Eclipse: (obselete) # File -> New -> Project -> Android Project from Existing Code # Select android/ and import all project # Import appcompat-v7 # Import preference-v7 # # Gradle # cd ijkplayer # gradle ``` ### Build iOS ``` git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-ios cd ijkplayer-ios git checkout -B latest k0.8.8 ./init-ios.sh cd ios ./compile-ffmpeg.sh clean ./compile-ffmpeg.sh all # Demo # open ios/IJKMediaDemo/IJKMediaDemo.xcodeproj with Xcode # # Import into Your own Application # Select your project in Xcode. # File -> Add Files to ... -> Select ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj # Select your Application's target. # Build Phases -> Target Dependencies -> Select IJKMediaFramework # Build Phases -> Link Binary with Libraries -> Add: # IJKMediaFramework.framework # # AudioToolbox.framework # AVFoundation.framework # CoreGraphics.framework # CoreMedia.framework # CoreVideo.framework # libbz2.tbd # libz.tbd # MediaPlayer.framework # MobileCoreServices.framework # OpenGLES.framework # QuartzCore.framework # UIKit.framework # VideoToolbox.framework # # ... (Maybe something else, if you get any link error) # ``` ### Support (支持) ### - Please do not send e-mail to me. Public technical discussion on github is preferred. - 请尽量在 github 上公开讨论[技术问题](https://github.com/bilibili/ijkplayer/issues),不要以邮件方式私下询问,恕不一一回复。 ### License ``` Copyright (c) 2017 Bilibili Licensed under LGPLv2.1 or later ``` ijkplayer required features are based on or derives from projects below: - LGPL - [FFmpeg](http://git.videolan.org/?p=ffmpeg.git) - [libVLC](http://git.videolan.org/?p=vlc.git) - [kxmovie](https://github.com/kolyvan/kxmovie) - [soundtouch](http://www.surina.net/soundtouch/sourcecode.html) - zlib license - [SDL](http://www.libsdl.org) - BSD-style license - [libyuv](https://code.google.com/p/libyuv/) - ISC license - [libyuv/source/x86inc.asm](https://code.google.com/p/libyuv/source/browse/trunk/source/x86inc.asm) android/ijkplayer-exo is based on or derives from projects below: - Apache License 2.0 - [ExoPlayer](https://github.com/google/ExoPlayer) android/example is based on or derives from projects below: - GPL - [android-ndk-profiler](https://github.com/richq/android-ndk-profiler) (not included by default) ios/IJKMediaDemo is based on or derives from projects below: - Unknown license - [iOS7-BarcodeScanner](https://github.com/jpwiddy/iOS7-BarcodeScanner) ijkplayer's build scripts are based on or derives from projects below: - [gas-preprocessor](http://git.libav.org/?p=gas-preprocessor.git) - [VideoLAN](http://git.videolan.org) - [yixia/FFmpeg-Android](https://github.com/yixia/FFmpeg-Android) - [kewlbear/FFmpeg-iOS-build-script](https://github.com/kewlbear/FFmpeg-iOS-build-script) ### Commercial Use ijkplayer is licensed under LGPLv2.1 or later, so itself is free for commercial use under LGPLv2.1 or later But ijkplayer is also based on other different projects under various licenses, which I have no idea whether they are compatible to each other or to your product. [IANAL](https://en.wikipedia.org/wiki/IANAL), you should always ask your lawyer for these stuffs before use it in your product. ================================================ FILE: android/.gitignore ================================================ #-------------------- # Android.gitignore # https://github.com/github/gitignore/blob/master/Android.gitignore #-------------------- # Built application files *.apk *.ap_ # Files for the Dalvik VM *.dex # Java class files *.class # Generated files bin/ gen/ # Gradle files .gradle/ build/ # Local configuration file (sdk path, etc) local.properties # Proguard folder generated by Eclipse proguard/ # Log Files *.log #-------------------- # Gradle.gitignore # https://github.com/github/gitignore/blob/master/Gradle.gitignore #-------------------- .gradle build/ # Ignore Gradle GUI config gradle-app.setting # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) !gradle-wrapper.jar #-------------------- # Android Studio .gitignore # https://gist.github.com/iainconnor/8605514 #-------------------- # Built application files /*/build/ # Crashlytics configuations com_crashlytics_export_strings.xml # Local configuration file (sdk path, etc) local.properties # Gradle generated files .gradle/ # Signing files .signing/ # User-specific configurations .idea/libraries/ .idea/workspace.xml .idea/tasks.xml .idea/.name .idea/compiler.xml .idea/copyright/profiles_settings.xml .idea/encodings.xml .idea/misc.xml .idea/modules.xml .idea/scopes/scope_settings.xml .idea/vcs.xml *.iml # OS-specific files .DS_Store .DS_Store? ._* .Spotlight-V100 .Trashes ehthumbs.db Thumbs.db ================================================ FILE: android/build-on-travis.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2014 Bilibili # Copyright (C) 2013-2014 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # set -e if [ -z "$ANDROID_NDK" -o -z "$ANDROID_NDK" ]; then echo "You must define ANDROID_NDK, ANDROID_SDK before starting." echo "They must point to your NDK and SDK directories.\n" exit 1 fi REQUEST_TARGET=$1 ACT_ABI_32="armv5 armv7a x86" ACT_ABI_64="armv5 armv7a arm64 x86 x86_64" ACT_ABI_ALL=$ACT_ABI_64 IJK_VERSION=`../version.sh show` wget_uploaded_version() { PARAM_TARGET=$1 VERSION_URL="https://jcenter.bintray.com/tv/danmaku/ijk/media/ijkplayer-$PARAM_TARGET/$IJK_VERSION" echo "VERSION_URL="$VERSION_URL wget $VERSION_URL -O /dev/null } do_build_native() { PARAM_TARGET=$1 wget_uploaded_version $PARAM_TARGET && echo "ijkplayer-$PARAM_TARGET $IJK_VERSION already uploaded, skip..." && return 0 cd contrib ./compile-ffmpeg.sh $PARAM_TARGET cd .. ./compile-ijk.sh $PARAM_TARGET cd ijkplayer ./gradlew :ijkplayer-$PARAM_TARGET:bintrayUpload cd .. } do_build_java() { wget_uploaded_version java && echo "ijkplayer-$PARAM_TARGET $IJK_VERSION already uploaded, skip..." && return 0 cd ijkplayer ./gradlew :ijkplayer-java:bintrayUpload cd .. } do_build_exo() { wget_uploaded_version exo && echo "ijkplayer-$PARAM_TARGET $IJK_VERSION already uploaded, skip..." && return 0 cd ijkplayer ./gradlew :ijkplayer-exo:bintrayUpload cd .. } case "$REQUEST_TARGET" in armv5|armv7a|arm64|x86|x86_64) do_build_native $REQUEST_TARGET ;; java) do_build_java ;; exo) do_build_exo ;; all32) do_build_java for ABI in $ACT_ABI_32 do do_build_native "$ABI"; done do_build_exo ;; all|all64) do_build_java for ABI in $ACT_ABI_64 do do_build_native "$ABI"; done do_build_exo ;; *) echo "Usage:" echo " build-on-travis.sh armv5|armv7a|arm64|x86|x86_64" echo " build-on-travis.sh java" echo " build-on-travis.sh exo" echo " build-on-travis.sh all|all32" echo " build-on-travis.sh all64" ;; esac ================================================ FILE: android/compile-ijk.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2014 Bilibili # Copyright (C) 2013-2014 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # if [ -z "$ANDROID_NDK" -o -z "$ANDROID_NDK" ]; then echo "You must define ANDROID_NDK, ANDROID_SDK before starting." echo "They must point to your NDK and SDK directories.\n" exit 1 fi REQUEST_TARGET=$1 REQUEST_SUB_CMD=$2 ACT_ABI_32="armv5 armv7a x86" ACT_ABI_64="armv5 armv7a arm64 x86 x86_64" ACT_ABI_ALL=$ACT_ABI_64 UNAME_S=$(uname -s) FF_MAKEFLAGS= if which nproc >/dev/null then FF_MAKEFLAGS=-j`nproc` elif [ "$UNAME_S" = "Darwin" ] && which sysctl >/dev/null then FF_MAKEFLAGS=-j`sysctl -n machdep.cpu.thread_count` fi do_sub_cmd () { SUB_CMD=$1 if [ -L "./android-ndk-prof" ]; then rm android-ndk-prof fi if [ "$PARAM_SUB_CMD" = 'prof' ]; then echo 'profiler build: YES'; ln -s ../../../../../../ijkprof/android-ndk-profiler/jni android-ndk-prof else echo 'profiler build: NO'; ln -s ../../../../../../ijkprof/android-ndk-profiler-dummy/jni android-ndk-prof fi case $SUB_CMD in prof) $ANDROID_NDK/ndk-build $FF_MAKEFLAGS ;; clean) $ANDROID_NDK/ndk-build clean ;; rebuild) $ANDROID_NDK/ndk-build clean $ANDROID_NDK/ndk-build $FF_MAKEFLAGS ;; *) $ANDROID_NDK/ndk-build $FF_MAKEFLAGS ;; esac } do_ndk_build () { PARAM_TARGET=$1 PARAM_SUB_CMD=$2 case "$PARAM_TARGET" in armv5|armv7a) cd "ijkplayer/ijkplayer-$PARAM_TARGET/src/main/jni" do_sub_cmd $PARAM_SUB_CMD cd - ;; arm64|x86|x86_64) cd "ijkplayer/ijkplayer-$PARAM_TARGET/src/main/jni" if [ "$PARAM_SUB_CMD" = 'prof' ]; then PARAM_SUB_CMD=''; fi do_sub_cmd $PARAM_SUB_CMD cd - ;; esac } case "$REQUEST_TARGET" in "") do_ndk_build armv7a; ;; armv5|armv7a|arm64|x86|x86_64) do_ndk_build $REQUEST_TARGET $REQUEST_SUB_CMD; ;; all32) for ABI in $ACT_ABI_32 do do_ndk_build "$ABI" $REQUEST_SUB_CMD; done ;; all|all64) for ABI in $ACT_ABI_64 do do_ndk_build "$ABI" $REQUEST_SUB_CMD; done ;; clean) for ABI in $ACT_ABI_ALL do do_ndk_build "$ABI" clean; done ;; *) echo "Usage:" echo " compile-ijk.sh armv5|armv7a|arm64|x86|x86_64" echo " compile-ijk.sh all|all32" echo " compile-ijk.sh all64" echo " compile-ijk.sh clean" ;; esac ================================================ FILE: android/contrib/.gitignore ================================================ build ffmpeg-* libsoxr-* openssl-* ================================================ FILE: android/contrib/compile-ffmpeg.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2014 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # This script is based on projects below # https://github.com/yixia/FFmpeg-Android # http://git.videolan.org/?p=vlc-ports/android.git;a=summary #---------- UNI_BUILD_ROOT=`pwd` FF_TARGET=$1 FF_TARGET_EXTRA=$2 set -e set +x FF_ACT_ARCHS_32="armv5 armv7a x86" FF_ACT_ARCHS_64="armv5 armv7a arm64 x86 x86_64" FF_ACT_ARCHS_ALL=$FF_ACT_ARCHS_64 echo_archs() { echo "====================" echo "[*] check archs" echo "====================" echo "FF_ALL_ARCHS = $FF_ACT_ARCHS_ALL" echo "FF_ACT_ARCHS = $*" echo "" } echo_usage() { echo "Usage:" echo " compile-ffmpeg.sh armv5|armv7a|arm64|x86|x86_64" echo " compile-ffmpeg.sh all|all32" echo " compile-ffmpeg.sh all64" echo " compile-ffmpeg.sh clean" echo " compile-ffmpeg.sh check" exit 1 } echo_nextstep_help() { echo "" echo "--------------------" echo "[*] Finished" echo "--------------------" echo "# to continue to build ijkplayer, run script below," echo "sh compile-ijk.sh " } #---------- case "$FF_TARGET" in "") echo_archs armv7a sh tools/do-compile-ffmpeg.sh armv7a ;; armv5|armv7a|arm64|x86|x86_64) echo_archs $FF_TARGET $FF_TARGET_EXTRA sh tools/do-compile-ffmpeg.sh $FF_TARGET $FF_TARGET_EXTRA echo_nextstep_help ;; all32) echo_archs $FF_ACT_ARCHS_32 for ARCH in $FF_ACT_ARCHS_32 do sh tools/do-compile-ffmpeg.sh $ARCH $FF_TARGET_EXTRA done echo_nextstep_help ;; all|all64) echo_archs $FF_ACT_ARCHS_64 for ARCH in $FF_ACT_ARCHS_64 do sh tools/do-compile-ffmpeg.sh $ARCH $FF_TARGET_EXTRA done echo_nextstep_help ;; clean) echo_archs FF_ACT_ARCHS_64 for ARCH in $FF_ACT_ARCHS_ALL do if [ -d ffmpeg-$ARCH ]; then cd ffmpeg-$ARCH && git clean -xdf && cd - fi done rm -rf ./build/ffmpeg-* ;; check) echo_archs FF_ACT_ARCHS_ALL ;; *) echo_usage exit 1 ;; esac ================================================ FILE: android/contrib/compile-libsoxr.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2014 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # #---------- UNI_BUILD_ROOT=`pwd` FF_TARGET=$1 set -e set +x FF_ACT_ARCHS_32="armv5 armv7a x86" FF_ACT_ARCHS_64="armv5 armv7a arm64 x86 x86_64" FF_ACT_ARCHS_ALL=$FF_ACT_ARCHS_64 echo_archs() { echo "====================" echo "[*] check archs" echo "====================" echo "FF_ALL_ARCHS = $FF_ACT_ARCHS_ALL" echo "FF_ACT_ARCHS = $*" echo "" } echo_usage() { echo "Usage:" echo " compile-libsoxr.sh armv5|armv7a|arm64|x86|x86_64" echo " compile-libsoxr.sh all|all32" echo " compile-libsoxr.sh all64" echo " compile-libsoxr.sh clean" echo " compile-libsoxr.sh check" exit 1 } echo_nextstep_help() { #---------- echo "" echo "--------------------" echo "[*] Finished" echo "--------------------" echo "# to continue to build ffmpeg, run script below," echo "sh compile-ffmpeg.sh " echo "# to continue to build ijkplayer, run script below," echo "sh compile-ijk.sh " } #---------- case "$FF_TARGET" in "") echo_archs armv7a sh tools/do-compile-libsoxr.sh armv7a ;; armv5|armv7a|arm64|x86|x86_64) echo_archs $FF_TARGET sh tools/do-compile-libsoxr.sh $FF_TARGET echo_nextstep_help ;; all32) echo_archs $FF_ACT_ARCHS_32 for ARCH in $FF_ACT_ARCHS_32 do sh tools/do-compile-libsoxr.sh $ARCH done echo_nextstep_help ;; all|all64) echo_archs $FF_ACT_ARCHS_64 for ARCH in $FF_ACT_ARCHS_64 do sh tools/do-compile-libsoxr.sh $ARCH done echo_nextstep_help ;; clean) echo_archs FF_ACT_ARCHS_64 for ARCH in $FF_ACT_ARCHS_ALL do if [ -d libsoxr-$ARCH ]; then cd libsoxr-$ARCH && git clean -xdf && cd - fi done rm -rf ./build/libsoxr-* ;; check) echo_archs FF_ACT_ARCHS_ALL ;; *) echo_usage exit 1 ;; esac ================================================ FILE: android/contrib/compile-openssl.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2014 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # #---------- UNI_BUILD_ROOT=`pwd` FF_TARGET=$1 set -e set +x FF_ACT_ARCHS_32="armv5 armv7a x86" FF_ACT_ARCHS_64="armv5 armv7a arm64 x86 x86_64" FF_ACT_ARCHS_ALL=$FF_ACT_ARCHS_64 echo_archs() { echo "====================" echo "[*] check archs" echo "====================" echo "FF_ALL_ARCHS = $FF_ACT_ARCHS_ALL" echo "FF_ACT_ARCHS = $*" echo "" } echo_usage() { echo "Usage:" echo " compile-openssl.sh armv5|armv7a|arm64|x86|x86_64" echo " compile-openssl.sh all|all32" echo " compile-openssl.sh all64" echo " compile-openssl.sh clean" echo " compile-openssl.sh check" exit 1 } echo_nextstep_help() { #---------- echo "" echo "--------------------" echo "[*] Finished" echo "--------------------" echo "# to continue to build ffmpeg, run script below," echo "sh compile-ffmpeg.sh " echo "# to continue to build ijkplayer, run script below," echo "sh compile-ijk.sh " } #---------- case "$FF_TARGET" in "") echo_archs armv7a sh tools/do-compile-openssl.sh armv7a ;; armv5|armv7a|arm64|x86|x86_64) echo_archs $FF_TARGET sh tools/do-compile-openssl.sh $FF_TARGET echo_nextstep_help ;; all32) echo_archs $FF_ACT_ARCHS_32 for ARCH in $FF_ACT_ARCHS_32 do sh tools/do-compile-openssl.sh $ARCH done echo_nextstep_help ;; all|all64) echo_archs $FF_ACT_ARCHS_64 for ARCH in $FF_ACT_ARCHS_64 do sh tools/do-compile-openssl.sh $ARCH done echo_nextstep_help ;; clean) echo_archs FF_ACT_ARCHS_64 for ARCH in $FF_ACT_ARCHS_ALL do if [ -d openssl-$ARCH ]; then cd openssl-$ARCH && git clean -xdf && cd - fi done rm -rf ./build/openssl-* ;; check) echo_archs FF_ACT_ARCHS_ALL ;; *) echo_usage exit 1 ;; esac ================================================ FILE: android/contrib/setup-as-commiter.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2014 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # cd ffmpeg-armv7a git remote set-url --push origin git@github.com:bbcallen/FFmpeg.git git remote add ffmpeg git://source.ffmpeg.org/ffmpeg.git git remote add libav git://git.libav.org/libav.git git remote add chromium https://chromium.googlesource.com/chromium/third_party/ffmpeg git remote add gitcafe git@gitcafe.com:bbcallen/FFmpeg.git git remote add oschina git@git.oschina.net:bbcallen/ffmpeg.git git remote add csdn git@code.csdn.net:bbcallen/FFmpeg.git git fetch --all git branch --track ffmpeg ffmpeg/master git branch --track libav libav/master git branch --track chromium chromium/master ================================================ FILE: android/contrib/sync-mirrors.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2014 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # cd ffmpeg-armv7a git checkout ffmpeg git pull git checkout - git checkout libav git pull git checkout - git checkout master git pull git merge ffmpeg git checkout - git push origin --all --follow-tags git push gitcafe --all --follow-tags git push oschina --all --follow-tags git push csdn --all --follow-tags cd - ================================================ FILE: android/contrib/tools/do-compile-ffmpeg.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2014 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # This script is based on projects below # https://github.com/yixia/FFmpeg-Android # http://git.videolan.org/?p=vlc-ports/android.git;a=summary #-------------------- echo "====================" echo "[*] check env $1" echo "====================" set -e #-------------------- # common defines FF_ARCH=$1 FF_BUILD_OPT=$2 echo "FF_ARCH=$FF_ARCH" echo "FF_BUILD_OPT=$FF_BUILD_OPT" if [ -z "$FF_ARCH" ]; then echo "You must specific an architecture 'arm, armv7a, x86, ...'." echo "" exit 1 fi FF_BUILD_ROOT=`pwd` FF_ANDROID_PLATFORM=android-9 FF_BUILD_NAME= FF_SOURCE= FF_CROSS_PREFIX= FF_DEP_OPENSSL_INC= FF_DEP_OPENSSL_LIB= FF_DEP_LIBSOXR_INC= FF_DEP_LIBSOXR_LIB= FF_CFG_FLAGS= FF_EXTRA_CFLAGS= FF_EXTRA_LDFLAGS= FF_DEP_LIBS= FF_MODULE_DIRS="compat libavcodec libavfilter libavformat libavutil libswresample libswscale" FF_ASSEMBLER_SUB_DIRS= #-------------------- echo "" echo "--------------------" echo "[*] make NDK standalone toolchain" echo "--------------------" . ./tools/do-detect-env.sh FF_MAKE_TOOLCHAIN_FLAGS=$IJK_MAKE_TOOLCHAIN_FLAGS FF_MAKE_FLAGS=$IJK_MAKE_FLAG FF_GCC_VER=$IJK_GCC_VER FF_GCC_64_VER=$IJK_GCC_64_VER #----- armv7a begin ----- if [ "$FF_ARCH" = "armv7a" ]; then FF_BUILD_NAME=ffmpeg-armv7a FF_BUILD_NAME_OPENSSL=openssl-armv7a FF_BUILD_NAME_LIBSOXR=libsoxr-armv7a FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME FF_CROSS_PREFIX=arm-linux-androideabi FF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_VER} FF_CFG_FLAGS="$FF_CFG_FLAGS --arch=arm --cpu=cortex-a8" FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-neon" FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-thumb" FF_EXTRA_CFLAGS="$FF_EXTRA_CFLAGS -march=armv7-a -mcpu=cortex-a8 -mfpu=vfpv3-d16 -mfloat-abi=softfp -mthumb" FF_EXTRA_LDFLAGS="$FF_EXTRA_LDFLAGS -Wl,--fix-cortex-a8" FF_ASSEMBLER_SUB_DIRS="arm" elif [ "$FF_ARCH" = "armv5" ]; then FF_BUILD_NAME=ffmpeg-armv5 FF_BUILD_NAME_OPENSSL=openssl-armv5 FF_BUILD_NAME_LIBSOXR=libsoxr-armv5 FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME FF_CROSS_PREFIX=arm-linux-androideabi FF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_VER} FF_CFG_FLAGS="$FF_CFG_FLAGS --arch=arm" FF_EXTRA_CFLAGS="$FF_EXTRA_CFLAGS -march=armv5te -mtune=arm9tdmi -msoft-float" FF_EXTRA_LDFLAGS="$FF_EXTRA_LDFLAGS" FF_ASSEMBLER_SUB_DIRS="arm" elif [ "$FF_ARCH" = "x86" ]; then FF_BUILD_NAME=ffmpeg-x86 FF_BUILD_NAME_OPENSSL=openssl-x86 FF_BUILD_NAME_LIBSOXR=libsoxr-x86 FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME FF_CROSS_PREFIX=i686-linux-android FF_TOOLCHAIN_NAME=x86-${FF_GCC_VER} FF_CFG_FLAGS="$FF_CFG_FLAGS --arch=x86 --cpu=i686 --enable-yasm" FF_EXTRA_CFLAGS="$FF_EXTRA_CFLAGS -march=atom -msse3 -ffast-math -mfpmath=sse" FF_EXTRA_LDFLAGS="$FF_EXTRA_LDFLAGS" FF_ASSEMBLER_SUB_DIRS="x86" elif [ "$FF_ARCH" = "x86_64" ]; then FF_ANDROID_PLATFORM=android-21 FF_BUILD_NAME=ffmpeg-x86_64 FF_BUILD_NAME_OPENSSL=openssl-x86_64 FF_BUILD_NAME_LIBSOXR=libsoxr-x86_64 FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME FF_CROSS_PREFIX=x86_64-linux-android FF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_64_VER} FF_CFG_FLAGS="$FF_CFG_FLAGS --arch=x86_64 --enable-yasm" FF_EXTRA_CFLAGS="$FF_EXTRA_CFLAGS" FF_EXTRA_LDFLAGS="$FF_EXTRA_LDFLAGS" FF_ASSEMBLER_SUB_DIRS="x86" elif [ "$FF_ARCH" = "arm64" ]; then FF_ANDROID_PLATFORM=android-21 FF_BUILD_NAME=ffmpeg-arm64 FF_BUILD_NAME_OPENSSL=openssl-arm64 FF_BUILD_NAME_LIBSOXR=libsoxr-arm64 FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME FF_CROSS_PREFIX=aarch64-linux-android FF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_64_VER} FF_CFG_FLAGS="$FF_CFG_FLAGS --arch=aarch64 --enable-yasm" FF_EXTRA_CFLAGS="$FF_EXTRA_CFLAGS" FF_EXTRA_LDFLAGS="$FF_EXTRA_LDFLAGS" FF_ASSEMBLER_SUB_DIRS="aarch64 neon" else echo "unknown architecture $FF_ARCH"; exit 1 fi if [ ! -d $FF_SOURCE ]; then echo "" echo "!! ERROR" echo "!! Can not find FFmpeg directory for $FF_BUILD_NAME" echo "!! Run 'sh init-android.sh' first" echo "" exit 1 fi FF_TOOLCHAIN_PATH=$FF_BUILD_ROOT/build/$FF_BUILD_NAME/toolchain FF_MAKE_TOOLCHAIN_FLAGS="$FF_MAKE_TOOLCHAIN_FLAGS --install-dir=$FF_TOOLCHAIN_PATH" FF_SYSROOT=$FF_TOOLCHAIN_PATH/sysroot FF_PREFIX=$FF_BUILD_ROOT/build/$FF_BUILD_NAME/output FF_DEP_OPENSSL_INC=$FF_BUILD_ROOT/build/$FF_BUILD_NAME_OPENSSL/output/include FF_DEP_OPENSSL_LIB=$FF_BUILD_ROOT/build/$FF_BUILD_NAME_OPENSSL/output/lib FF_DEP_LIBSOXR_INC=$FF_BUILD_ROOT/build/$FF_BUILD_NAME_LIBSOXR/output/include FF_DEP_LIBSOXR_LIB=$FF_BUILD_ROOT/build/$FF_BUILD_NAME_LIBSOXR/output/lib case "$UNAME_S" in CYGWIN_NT-*) FF_SYSROOT="$(cygpath -am $FF_SYSROOT)" FF_PREFIX="$(cygpath -am $FF_PREFIX)" ;; esac mkdir -p $FF_PREFIX # mkdir -p $FF_SYSROOT FF_TOOLCHAIN_TOUCH="$FF_TOOLCHAIN_PATH/touch" if [ ! -f "$FF_TOOLCHAIN_TOUCH" ]; then $ANDROID_NDK/build/tools/make-standalone-toolchain.sh \ $FF_MAKE_TOOLCHAIN_FLAGS \ --platform=$FF_ANDROID_PLATFORM \ --toolchain=$FF_TOOLCHAIN_NAME touch $FF_TOOLCHAIN_TOUCH; fi #-------------------- echo "" echo "--------------------" echo "[*] check ffmpeg env" echo "--------------------" export PATH=$FF_TOOLCHAIN_PATH/bin/:$PATH #export CC="ccache ${FF_CROSS_PREFIX}-gcc" export CC="${FF_CROSS_PREFIX}-gcc" export LD=${FF_CROSS_PREFIX}-ld export AR=${FF_CROSS_PREFIX}-ar export STRIP=${FF_CROSS_PREFIX}-strip FF_CFLAGS="-O3 -Wall -pipe \ -std=c99 \ -ffast-math \ -fstrict-aliasing -Werror=strict-aliasing \ -Wno-psabi -Wa,--noexecstack \ -DANDROID -DNDEBUG" # cause av_strlcpy crash with gcc4.7, gcc4.8 # -fmodulo-sched -fmodulo-sched-allow-regmoves # --enable-thumb is OK #FF_CFLAGS="$FF_CFLAGS -mthumb" # not necessary #FF_CFLAGS="$FF_CFLAGS -finline-limit=300" export COMMON_FF_CFG_FLAGS= . $FF_BUILD_ROOT/../../config/module.sh #-------------------- # with openssl if [ -f "${FF_DEP_OPENSSL_LIB}/libssl.a" ]; then echo "OpenSSL detected" # FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-nonfree" FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-openssl" FF_CFLAGS="$FF_CFLAGS -I${FF_DEP_OPENSSL_INC}" FF_DEP_LIBS="$FF_DEP_LIBS -L${FF_DEP_OPENSSL_LIB} -lssl -lcrypto" fi if [ -f "${FF_DEP_LIBSOXR_LIB}/libsoxr.a" ]; then echo "libsoxr detected" FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-libsoxr" FF_CFLAGS="$FF_CFLAGS -I${FF_DEP_LIBSOXR_INC}" FF_DEP_LIBS="$FF_DEP_LIBS -L${FF_DEP_LIBSOXR_LIB} -lsoxr" fi FF_CFG_FLAGS="$FF_CFG_FLAGS $COMMON_FF_CFG_FLAGS" #-------------------- # Standard options: FF_CFG_FLAGS="$FF_CFG_FLAGS --prefix=$FF_PREFIX" # Advanced options (experts only): FF_CFG_FLAGS="$FF_CFG_FLAGS --cross-prefix=${FF_CROSS_PREFIX}-" FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-cross-compile" FF_CFG_FLAGS="$FF_CFG_FLAGS --target-os=linux" FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-pic" # FF_CFG_FLAGS="$FF_CFG_FLAGS --disable-symver" if [ "$FF_ARCH" = "x86" ]; then FF_CFG_FLAGS="$FF_CFG_FLAGS --disable-asm" else # Optimization options (experts only): FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-asm" FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-inline-asm" fi case "$FF_BUILD_OPT" in debug) FF_CFG_FLAGS="$FF_CFG_FLAGS --disable-optimizations" FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-debug" FF_CFG_FLAGS="$FF_CFG_FLAGS --disable-small" ;; *) FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-optimizations" FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-debug" FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-small" ;; esac #-------------------- echo "" echo "--------------------" echo "[*] configurate ffmpeg" echo "--------------------" cd $FF_SOURCE if [ -f "./config.h" ]; then echo 'reuse configure' else which $CC ./configure $FF_CFG_FLAGS \ --extra-cflags="$FF_CFLAGS $FF_EXTRA_CFLAGS" \ --extra-ldflags="$FF_DEP_LIBS $FF_EXTRA_LDFLAGS" make clean fi #-------------------- echo "" echo "--------------------" echo "[*] compile ffmpeg" echo "--------------------" cp config.* $FF_PREFIX make $FF_MAKE_FLAGS > /dev/null make install mkdir -p $FF_PREFIX/include/libffmpeg cp -f config.h $FF_PREFIX/include/libffmpeg/config.h #-------------------- echo "" echo "--------------------" echo "[*] link ffmpeg" echo "--------------------" echo $FF_EXTRA_LDFLAGS FF_C_OBJ_FILES= FF_ASM_OBJ_FILES= for MODULE_DIR in $FF_MODULE_DIRS do C_OBJ_FILES="$MODULE_DIR/*.o" if ls $C_OBJ_FILES 1> /dev/null 2>&1; then echo "link $MODULE_DIR/*.o" FF_C_OBJ_FILES="$FF_C_OBJ_FILES $C_OBJ_FILES" fi for ASM_SUB_DIR in $FF_ASSEMBLER_SUB_DIRS do ASM_OBJ_FILES="$MODULE_DIR/$ASM_SUB_DIR/*.o" if ls $ASM_OBJ_FILES 1> /dev/null 2>&1; then echo "link $MODULE_DIR/$ASM_SUB_DIR/*.o" FF_ASM_OBJ_FILES="$FF_ASM_OBJ_FILES $ASM_OBJ_FILES" fi done done $CC -lm -lz -shared --sysroot=$FF_SYSROOT -Wl,--no-undefined -Wl,-z,noexecstack $FF_EXTRA_LDFLAGS \ -Wl,-soname,libijkffmpeg.so \ $FF_C_OBJ_FILES \ $FF_ASM_OBJ_FILES \ $FF_DEP_LIBS \ -o $FF_PREFIX/libijkffmpeg.so mysedi() { f=$1 exp=$2 n=`basename $f` cp $f /tmp/$n sed $exp /tmp/$n > $f rm /tmp/$n } echo "" echo "--------------------" echo "[*] create files for shared ffmpeg" echo "--------------------" rm -rf $FF_PREFIX/shared mkdir -p $FF_PREFIX/shared/lib/pkgconfig ln -s $FF_PREFIX/include $FF_PREFIX/shared/include ln -s $FF_PREFIX/libijkffmpeg.so $FF_PREFIX/shared/lib/libijkffmpeg.so cp $FF_PREFIX/lib/pkgconfig/*.pc $FF_PREFIX/shared/lib/pkgconfig for f in $FF_PREFIX/lib/pkgconfig/*.pc; do # in case empty dir if [ ! -f $f ]; then continue fi cp $f $FF_PREFIX/shared/lib/pkgconfig f=$FF_PREFIX/shared/lib/pkgconfig/`basename $f` # OSX sed doesn't have in-place(-i) mysedi $f 's/\/output/\/output\/shared/g' mysedi $f 's/-lavcodec/-lijkffmpeg/g' mysedi $f 's/-lavfilter/-lijkffmpeg/g' mysedi $f 's/-lavformat/-lijkffmpeg/g' mysedi $f 's/-lavutil/-lijkffmpeg/g' mysedi $f 's/-lswresample/-lijkffmpeg/g' mysedi $f 's/-lswscale/-lijkffmpeg/g' done ================================================ FILE: android/contrib/tools/do-compile-libsoxr.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2014 Miguel Botón # Copyright (C) 2014 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # #-------------------- set -e if [ -z "$ANDROID_NDK" ]; then echo "You must define ANDROID_NDK before starting." echo "They must point to your NDK directories.\n" exit 1 fi #-------------------- # common defines FF_ARCH=$1 if [ -z "$FF_ARCH" ]; then echo "You must specific an architecture 'arm, armv7a, x86, ...'.\n" exit 1 fi FF_BUILD_ROOT=`pwd` FF_BUILD_NAME= FF_SOURCE= FF_CROSS_PREFIX= FF_CFG_FLAGS= FF_PLATFORM_CFG_FLAGS= FF_EXTRA_CFLAGS= FF_EXTRA_LDFLAGS= FF_CMAKE_ABI= FF_CMAKE_EXTRA_FLAGS= #----- armv7a begin ----- if [ "$FF_ARCH" = "armv7a" ]; then FF_BUILD_NAME=libsoxr-armv7a FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME FF_CMAKE_ABI="armeabi-v7a with NEON" FF_CMAKE_EXTRA_FLAGS="-DHAVE_WORDS_BIGENDIAN_EXITCODE=1 -DWITH_SIMD=0" elif [ "$FF_ARCH" = "armv5" ]; then FF_BUILD_NAME=libsoxr-armv5 FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME FF_CMAKE_ABI="armeabi" FF_CMAKE_EXTRA_FLAGS="-DHAVE_WORDS_BIGENDIAN_EXITCODE=1 -DWITH_SIMD=0" elif [ "$FF_ARCH" = "x86" ]; then FF_BUILD_NAME=libsoxr-x86 FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME FF_CMAKE_ABI="x86" FF_CMAKE_EXTRA_FLAGS="-DHAVE_WORDS_BIGENDIAN_EXITCODE=1" elif [ "$FF_ARCH" = "x86_64" ]; then FF_ANDROID_PLATFORM=android-21 FF_BUILD_NAME=libsoxr-x86_64 FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME FF_CMAKE_ABI="x86_64" elif [ "$FF_ARCH" = "arm64" ]; then FF_ANDROID_PLATFORM=android-21 FF_BUILD_NAME=libsoxr-arm64 FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME FF_CMAKE_ABI="arm64-v8a" else echo "unknown architecture $FF_ARCH"; exit 1 fi FF_PREFIX=$FF_BUILD_ROOT/build/$FF_BUILD_NAME/output FF_CMAKE_BUILD_DIR=$FF_BUILD_ROOT/build/$FF_BUILD_NAME/build mkdir -p $FF_PREFIX mkdir -p $FF_CMAKE_BUILD_DIR #-------------------- echo "" echo "--------------------" echo "[*] configurate libsoxr" echo "--------------------" cd $FF_CMAKE_BUILD_DIR FF_CMAKE_CFG_FLAGS="-DCMAKE_TOOLCHAIN_FILE=${FF_SOURCE}/android.toolchain.cmake -DANDROID_NDK=$ANDROID_NDK -DBUILD_EXAMPLES=0 -DBUILD_LSR_TESTS=0 -DBUILD_SHARED_LIBS=0 -DBUILD_TESTS=0 -DCMAKE_BUILD_TYPE=Release -DWITH_LSR_BINDINGS=0 -DWITH_OPENMP=0 -DWITH_PFFFT=0" echo "cmake $FF_CMAKE_CFG_FLAGS -DANDROID_ABI=$FF_CMAKE_ABI -DCMAKE_INSTALL_PREFIX=$FF_PREFIX" cmake $FF_CMAKE_CFG_FLAGS $FF_CMAKE_EXTRA_FLAGS -DANDROID_ABI=$FF_CMAKE_ABI -DCMAKE_INSTALL_PREFIX=$FF_PREFIX $FF_SOURCE #-------------------- echo "" echo "--------------------" echo "[*] compile libsoxr" echo "--------------------" make -j4 make install ================================================ FILE: android/contrib/tools/do-compile-openssl.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2014 Miguel Botón # Copyright (C) 2014 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # #-------------------- set -e if [ -z "$ANDROID_NDK" ]; then echo "You must define ANDROID_NDK before starting." echo "They must point to your NDK directories.\n" exit 1 fi #-------------------- # common defines FF_ARCH=$1 if [ -z "$FF_ARCH" ]; then echo "You must specific an architecture 'arm, armv7a, x86, ...'.\n" exit 1 fi FF_BUILD_ROOT=`pwd` FF_ANDROID_PLATFORM=android-9 FF_BUILD_NAME= FF_SOURCE= FF_CROSS_PREFIX= FF_CFG_FLAGS= FF_PLATFORM_CFG_FLAGS= FF_EXTRA_CFLAGS= FF_EXTRA_LDFLAGS= #-------------------- echo "" echo "--------------------" echo "[*] make NDK standalone toolchain" echo "--------------------" . ./tools/do-detect-env.sh FF_MAKE_TOOLCHAIN_FLAGS=$IJK_MAKE_TOOLCHAIN_FLAGS FF_MAKE_FLAGS=$IJK_MAKE_FLAG FF_GCC_VER=$IJK_GCC_VER FF_GCC_64_VER=$IJK_GCC_64_VER #----- armv7a begin ----- if [ "$FF_ARCH" = "armv7a" ]; then FF_BUILD_NAME=openssl-armv7a FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME FF_CROSS_PREFIX=arm-linux-androideabi FF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_VER} FF_PLATFORM_CFG_FLAGS="android-armv7" elif [ "$FF_ARCH" = "armv5" ]; then FF_BUILD_NAME=openssl-armv5 FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME FF_CROSS_PREFIX=arm-linux-androideabi FF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_VER} FF_PLATFORM_CFG_FLAGS="android" elif [ "$FF_ARCH" = "x86" ]; then FF_BUILD_NAME=openssl-x86 FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME FF_CROSS_PREFIX=i686-linux-android FF_TOOLCHAIN_NAME=x86-${FF_GCC_VER} FF_PLATFORM_CFG_FLAGS="android-x86" FF_CFG_FLAGS="$FF_CFG_FLAGS no-asm" elif [ "$FF_ARCH" = "x86_64" ]; then FF_ANDROID_PLATFORM=android-21 FF_BUILD_NAME=openssl-x86_64 FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME FF_CROSS_PREFIX=x86_64-linux-android FF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_64_VER} FF_PLATFORM_CFG_FLAGS="linux-x86_64" elif [ "$FF_ARCH" = "arm64" ]; then FF_ANDROID_PLATFORM=android-21 FF_BUILD_NAME=openssl-arm64 FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME FF_CROSS_PREFIX=aarch64-linux-android FF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_64_VER} FF_PLATFORM_CFG_FLAGS="linux-aarch64" else echo "unknown architecture $FF_ARCH"; exit 1 fi FF_TOOLCHAIN_PATH=$FF_BUILD_ROOT/build/$FF_BUILD_NAME/toolchain FF_SYSROOT=$FF_TOOLCHAIN_PATH/sysroot FF_PREFIX=$FF_BUILD_ROOT/build/$FF_BUILD_NAME/output mkdir -p $FF_PREFIX # mkdir -p $FF_SYSROOT #-------------------- echo "" echo "--------------------" echo "[*] make NDK standalone toolchain" echo "--------------------" . ./tools/do-detect-env.sh FF_MAKE_TOOLCHAIN_FLAGS=$IJK_MAKE_TOOLCHAIN_FLAGS FF_MAKE_FLAGS=$IJK_MAKE_FLAG FF_MAKE_TOOLCHAIN_FLAGS="$FF_MAKE_TOOLCHAIN_FLAGS --install-dir=$FF_TOOLCHAIN_PATH" FF_TOOLCHAIN_TOUCH="$FF_TOOLCHAIN_PATH/touch" if [ ! -f "$FF_TOOLCHAIN_TOUCH" ]; then $ANDROID_NDK/build/tools/make-standalone-toolchain.sh \ $FF_MAKE_TOOLCHAIN_FLAGS \ --platform=$FF_ANDROID_PLATFORM \ --toolchain=$FF_TOOLCHAIN_NAME touch $FF_TOOLCHAIN_TOUCH; fi #-------------------- echo "" echo "--------------------" echo "[*] check openssl env" echo "--------------------" export PATH=$FF_TOOLCHAIN_PATH/bin:$PATH export COMMON_FF_CFG_FLAGS= FF_CFG_FLAGS="$FF_CFG_FLAGS $COMMON_FF_CFG_FLAGS" #-------------------- # Standard options: FF_CFG_FLAGS="$FF_CFG_FLAGS zlib-dynamic" FF_CFG_FLAGS="$FF_CFG_FLAGS no-shared" FF_CFG_FLAGS="$FF_CFG_FLAGS --openssldir=$FF_PREFIX" FF_CFG_FLAGS="$FF_CFG_FLAGS --cross-compile-prefix=${FF_CROSS_PREFIX}-" FF_CFG_FLAGS="$FF_CFG_FLAGS $FF_PLATFORM_CFG_FLAGS" #-------------------- echo "" echo "--------------------" echo "[*] configurate openssl" echo "--------------------" cd $FF_SOURCE #if [ -f "./Makefile" ]; then # echo 'reuse configure' #else echo "./Configure $FF_CFG_FLAGS" ./Configure $FF_CFG_FLAGS # --extra-cflags="$FF_CFLAGS $FF_EXTRA_CFLAGS" \ # --extra-ldflags="$FF_EXTRA_LDFLAGS" #fi #-------------------- echo "" echo "--------------------" echo "[*] compile openssl" echo "--------------------" make depend make $FF_MAKE_FLAGS make install_sw #-------------------- echo "" echo "--------------------" echo "[*] link openssl" echo "--------------------" ================================================ FILE: android/contrib/tools/do-detect-env.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2014 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # This script is based on projects below # https://github.com/yixia/FFmpeg-Android # http://git.videolan.org/?p=vlc-ports/android.git;a=summary #-------------------- set -e UNAME_S=$(uname -s) UNAME_SM=$(uname -sm) echo "build on $UNAME_SM" echo "ANDROID_NDK=$ANDROID_NDK" if [ -z "$ANDROID_NDK" ]; then echo "You must define ANDROID_NDK before starting." echo "They must point to your NDK directories." echo "" exit 1 fi # try to detect NDK version export IJK_GCC_VER=4.9 export IJK_GCC_64_VER=4.9 export IJK_MAKE_TOOLCHAIN_FLAGS= export IJK_MAKE_FLAG= export IJK_NDK_REL=$(grep -o '^r[0-9]*.*' $ANDROID_NDK/RELEASE.TXT 2>/dev/null | sed 's/[[:space:]]*//g' | cut -b2-) case "$IJK_NDK_REL" in 10e*) # we don't use 4.4.3 because it doesn't handle threads correctly. if test -d ${ANDROID_NDK}/toolchains/arm-linux-androideabi-4.8 # if gcc 4.8 is present, it's there for all the archs (x86, mips, arm) then echo "NDKr$IJK_NDK_REL detected" case "$UNAME_S" in Darwin) export IJK_MAKE_TOOLCHAIN_FLAGS="$IJK_MAKE_TOOLCHAIN_FLAGS --system=darwin-x86_64" ;; CYGWIN_NT-*) export IJK_MAKE_TOOLCHAIN_FLAGS="$IJK_MAKE_TOOLCHAIN_FLAGS --system=windows-x86_64" ;; esac else echo "You need the NDKr10e or later" exit 1 fi ;; *) IJK_NDK_REL=$(grep -o '^Pkg\.Revision.*=[0-9]*.*' $ANDROID_NDK/source.properties 2>/dev/null | sed 's/[[:space:]]*//g' | cut -d "=" -f 2) echo "IJK_NDK_REL=$IJK_NDK_REL" case "$IJK_NDK_REL" in 11*|12*|13*|14*) if test -d ${ANDROID_NDK}/toolchains/arm-linux-androideabi-4.9 then echo "NDKr$IJK_NDK_REL detected" else echo "You need the NDKr10e or later" exit 1 fi ;; *) echo "You need the NDKr10e or later" exit 1 ;; esac ;; esac case "$UNAME_S" in Darwin) export IJK_MAKE_FLAG=-j`sysctl -n machdep.cpu.thread_count` ;; CYGWIN_NT-*) IJK_WIN_TEMP="$(cygpath -am /tmp)" export TEMPDIR=$IJK_WIN_TEMP/ echo "Cygwin temp prefix=$IJK_WIN_TEMP/" ;; esac ================================================ FILE: android/ijk-addr2line.sh ================================================ #! /bin/sh addr2line -e ijkplayer/ijkplayer-armv7a/src/main/obj/local/armeabi-v7a/lib$1.so ================================================ FILE: android/ijk-ndk-stack.sh ================================================ #!/bin/sh adb logcat | ndk-stack -sym ijkplayer/ijkplayer-armv7a/src/main/obj/local/armeabi-v7a ================================================ FILE: android/ijkplayer/.gitignore ================================================ .gradle /local.properties /.idea/workspace.xml /.idea/libraries .DS_Store /build /captures android-ndk-prof ================================================ FILE: android/ijkplayer/build.gradle ================================================ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.1.3' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { jcenter() } } ext { compileSdkVersion = 25 buildToolsVersion = "25.0.3" targetSdkVersion = 25 versionCode = 800800 versionName = "0.8.8" } wrapper { gradleVersion = '2.14.1' } ================================================ FILE: android/ijkplayer/gradle/wrapper/gradle-wrapper.properties ================================================ #Wed Aug 24 16:26:25 CST 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip ================================================ FILE: android/ijkplayer/gradle.properties ================================================ # Project-wide Gradle settings. # IDE (e.g. Android Studio) users: # Gradle settings configured through the IDE *will override* # any settings specified in this file. # For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. # Default value: -Xmx10248m -XX:MaxPermSize=256m # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true VERSION_NAME=0.8.8 VERSION_CODE=800800 GROUP=tv.danmaku.ijk.media # http://central.sonatype.org/pages/requirements.html POM_USER_ORG=bilibili POM_DESCRIPTION=Video player based on FFmpeg n3.1 POM_URL=https://github.com/Bilibili/ijkplayer POM_SCM_URL=https://github.com/Bilibili/ijkplayer POM_SCM_CONNECTION=scm:git:git@github.com:Bilibili/ijkplayer.git POM_SCM_DEV_CONNECTION=scm:git:git@github.com:Bilibili/ijkplayer.git POM_LICENSE_NAME=LGPL-2.1 POM_LICENSE_URL=https://www.gnu.org/licenses/lgpl-2.1.html POM_LICENSE_DIST=repo POM_DEVELOPER_ID=bbcallen POM_DEVELOPER_NAME=Zhang Rui POM_DEVELOPER_EMAIL=bbcallen@gmail.com ================================================ FILE: android/ijkplayer/gradlew ================================================ #!/usr/bin/env bash ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS="" APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn ( ) { echo "$*" } die ( ) { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; esac # For Cygwin, ensure paths are in UNIX format before anything is touched. if $cygwin ; then [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` fi # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >&- APP_HOME="`pwd -P`" cd "$SAVED" >&- CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin, switch paths to Windows format before running java if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=$((i+1)) done case $i in (0) set -- ;; (1) set -- "$args0" ;; (2) set -- "$args0" "$args1" ;; (3) set -- "$args0" "$args1" "$args2" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules function splitJvmOpts() { JVM_OPTS=("$@") } eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" ================================================ FILE: android/ijkplayer/gradlew.bat ================================================ @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS= set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windowz variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* goto execute :4NT_args @rem Get arguments from the 4NT Shell from JP Software set CMD_LINE_ARGS=%$ :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: android/ijkplayer/ijkplayer-arm64/.gitignore ================================================ /build ================================================ FILE: android/ijkplayer/ijkplayer-arm64/build.gradle ================================================ apply plugin: 'com.android.library' android { // http://tools.android.com/tech-docs/new-build-system/tips //noinspection GroovyAssignabilityCheck compileSdkVersion rootProject.ext.compileSdkVersion //noinspection GroovyAssignabilityCheck buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { minSdkVersion 21 targetSdkVersion rootProject.ext.targetSdkVersion } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets.main { jniLibs.srcDirs 'src/main/libs' jni.srcDirs = [] // This prevents the auto generation of Android.mk } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) } apply from: new File(rootProject.projectDir, "tools/gradle-on-demand.gradle"); ================================================ FILE: android/ijkplayer/ijkplayer-arm64/gradle.properties ================================================ POM_NAME=ijkplayer-arm64 POM_ARTIFACT_ID=ijkplayer-arm64 POM_PACKAGING=aar ================================================ FILE: android/ijkplayer/ijkplayer-arm64/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /opt/android/ADK/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: android/ijkplayer/ijkplayer-arm64/src/androidTest/java/tv/danmaku/ijk/media/player_arm64/ApplicationTest.java ================================================ package tv.danmaku.ijk.media.player_arm64; import android.app.Application; import android.test.ApplicationTestCase; /** * Testing Fundamentals */ public class ApplicationTest extends ApplicationTestCase { public ApplicationTest() { super(Application.class); } } ================================================ FILE: android/ijkplayer/ijkplayer-arm64/src/main/.classpath ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-arm64/src/main/.project ================================================ ijkplayer-arm64 com.android.ide.eclipse.adt.ResourceManagerBuilder com.android.ide.eclipse.adt.PreCompilerBuilder org.eclipse.jdt.core.javabuilder com.android.ide.eclipse.adt.ApkBuilder com.android.ide.eclipse.adt.AndroidNature org.eclipse.jdt.core.javanature ================================================ FILE: android/ijkplayer/ijkplayer-arm64/src/main/.settings/org.eclipse.jdt.core.prefs ================================================ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.compliance=1.6 org.eclipse.jdt.core.compiler.source=1.6 ================================================ FILE: android/ijkplayer/ijkplayer-arm64/src/main/AndroidManifest.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-arm64/src/main/java/tv/danmaku/ijk/media/player_arm64/Pragma.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player_arm64; public class Pragma { } ================================================ FILE: android/ijkplayer/ijkplayer-arm64/src/main/jni/Application.mk ================================================ # Copyright (c) 2013-2014 Bilibili # copyright (c) 2013-2014 Zhang Rui # # This file is part of ijkPlayer. # # ijkPlayer 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. # # ijkPlayer 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 ijkPlayer; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA APP_OPTIM := release APP_PLATFORM := android-21 APP_ABI := arm64-v8a NDK_TOOLCHAIN_VERSION=4.9 APP_PIE := false APP_STL := stlport_static APP_CFLAGS := -O3 -Wall -pipe \ -ffast-math \ -fstrict-aliasing -Werror=strict-aliasing \ -Wno-psabi -Wa,--noexecstack \ -DANDROID -DNDEBUG ================================================ FILE: android/ijkplayer/ijkplayer-arm64/src/main/project.properties ================================================ # This file is automatically generated by Android Tools. # Do not modify this file -- YOUR CHANGES WILL BE ERASED! # # This file must be checked in Version Control Systems. # # To customize properties used by the Ant build system edit # "ant.properties", and override values to adapt the script to your # project structure. # # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. target=android-22 android.library=true ================================================ FILE: android/ijkplayer/ijkplayer-arm64/src/main/res/values/strings.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-armv5/.gitignore ================================================ /build ================================================ FILE: android/ijkplayer/ijkplayer-armv5/build.gradle ================================================ apply plugin: 'com.android.library' android { // http://tools.android.com/tech-docs/new-build-system/tips //noinspection GroovyAssignabilityCheck compileSdkVersion rootProject.ext.compileSdkVersion //noinspection GroovyAssignabilityCheck buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { minSdkVersion 9 targetSdkVersion rootProject.ext.targetSdkVersion } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets.main { jniLibs.srcDirs 'src/main/libs' jni.srcDirs = [] // This prevents the auto generation of Android.mk } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) } apply from: new File(rootProject.projectDir, "tools/gradle-on-demand.gradle"); ================================================ FILE: android/ijkplayer/ijkplayer-armv5/gradle.properties ================================================ POM_NAME=ijkplayer-armv5 POM_ARTIFACT_ID=ijkplayer-armv5 POM_PACKAGING=aar ================================================ FILE: android/ijkplayer/ijkplayer-armv5/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /opt/android/ADK/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: android/ijkplayer/ijkplayer-armv5/src/androidTest/java/tv/danmaku/ijk/media/player_armv5/ApplicationTest.java ================================================ package tv.danmaku.ijk.media.player_armv5; import android.app.Application; import android.test.ApplicationTestCase; /** * Testing Fundamentals */ public class ApplicationTest extends ApplicationTestCase { public ApplicationTest() { super(Application.class); } } ================================================ FILE: android/ijkplayer/ijkplayer-armv5/src/main/.classpath ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-armv5/src/main/.project ================================================ ijkplayer-armv5 com.android.ide.eclipse.adt.ResourceManagerBuilder com.android.ide.eclipse.adt.PreCompilerBuilder org.eclipse.jdt.core.javabuilder com.android.ide.eclipse.adt.ApkBuilder com.android.ide.eclipse.adt.AndroidNature org.eclipse.jdt.core.javanature ================================================ FILE: android/ijkplayer/ijkplayer-armv5/src/main/.settings/org.eclipse.jdt.core.prefs ================================================ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.compliance=1.6 org.eclipse.jdt.core.compiler.source=1.6 ================================================ FILE: android/ijkplayer/ijkplayer-armv5/src/main/AndroidManifest.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-armv5/src/main/java/tv/danmaku/ijk/media/player_armv5/Pragma.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player_armv5; public class Pragma { } ================================================ FILE: android/ijkplayer/ijkplayer-armv5/src/main/jni/Application.mk ================================================ # Copyright (c) 2013-2014 Bilibili # copyright (c) 2013-2014 Zhang Rui # # This file is part of ijkPlayer. # # ijkPlayer 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. # # ijkPlayer 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 ijkPlayer; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA APP_OPTIM := release APP_PLATFORM := android-9 APP_ABI := armeabi NDK_TOOLCHAIN_VERSION=4.9 APP_PIE := false APP_STL := stlport_static APP_CFLAGS := -O3 -Wall -pipe \ -ffast-math \ -fstrict-aliasing -Werror=strict-aliasing \ -Wno-psabi -Wa,--noexecstack \ -DANDROID -DNDEBUG ================================================ FILE: android/ijkplayer/ijkplayer-armv5/src/main/project.properties ================================================ # This file is automatically generated by Android Tools. # Do not modify this file -- YOUR CHANGES WILL BE ERASED! # # This file must be checked in Version Control Systems. # # To customize properties used by the Ant build system edit # "ant.properties", and override values to adapt the script to your # project structure. # # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. target=android-22 android.library=true ================================================ FILE: android/ijkplayer/ijkplayer-armv5/src/main/res/values/strings.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-armv7a/.gitignore ================================================ /build ================================================ FILE: android/ijkplayer/ijkplayer-armv7a/build.gradle ================================================ apply plugin: 'com.android.library' android { // http://tools.android.com/tech-docs/new-build-system/tips //noinspection GroovyAssignabilityCheck compileSdkVersion rootProject.ext.compileSdkVersion //noinspection GroovyAssignabilityCheck buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { minSdkVersion 9 targetSdkVersion rootProject.ext.targetSdkVersion } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets.main { jniLibs.srcDirs 'src/main/libs' jni.srcDirs = [] // This prevents the auto generation of Android.mk } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) } apply from: new File(rootProject.projectDir, "tools/gradle-on-demand.gradle"); ================================================ FILE: android/ijkplayer/ijkplayer-armv7a/gradle.properties ================================================ POM_NAME=ijkplayer-armv7a POM_ARTIFACT_ID=ijkplayer-armv7a POM_PACKAGING=aar ================================================ FILE: android/ijkplayer/ijkplayer-armv7a/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /opt/android/ADK/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: android/ijkplayer/ijkplayer-armv7a/src/androidTest/java/tv/danmaku/ijk/media/player_armv7a/ApplicationTest.java ================================================ package tv.danmaku.ijk.media.player_armv7a; import android.app.Application; import android.test.ApplicationTestCase; /** * Testing Fundamentals */ public class ApplicationTest extends ApplicationTestCase { public ApplicationTest() { super(Application.class); } } ================================================ FILE: android/ijkplayer/ijkplayer-armv7a/src/main/.classpath ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-armv7a/src/main/.project ================================================ ijkplayer-armv7a com.android.ide.eclipse.adt.ResourceManagerBuilder com.android.ide.eclipse.adt.PreCompilerBuilder org.eclipse.jdt.core.javabuilder com.android.ide.eclipse.adt.ApkBuilder com.android.ide.eclipse.adt.AndroidNature org.eclipse.jdt.core.javanature ================================================ FILE: android/ijkplayer/ijkplayer-armv7a/src/main/.settings/org.eclipse.jdt.core.prefs ================================================ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.compliance=1.6 org.eclipse.jdt.core.compiler.source=1.6 ================================================ FILE: android/ijkplayer/ijkplayer-armv7a/src/main/AndroidManifest.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-armv7a/src/main/java/tv/danmaku/ijk/media/player_armv7a/Pragma.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player_armv7a; public class Pragma { } ================================================ FILE: android/ijkplayer/ijkplayer-armv7a/src/main/jni/Android.mk ================================================ # Copyright (c) 2013 Bilibili # copyright (c) 2013 Zhang Rui # # This file is part of ijkPlayer. # # ijkPlayer 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. # # ijkPlayer 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 ijkPlayer; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA LOCAL_PATH := $(call my-dir) MY_APP_JNI_ROOT := $(realpath $(LOCAL_PATH)) MY_APP_PRJ_ROOT := $(realpath $(MY_APP_JNI_ROOT)/..) MY_APP_ANDROID_ROOT := $(realpath $(MY_APP_PRJ_ROOT)/../../../..) ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-armv7a/output) MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include) endif ifeq ($(TARGET_ARCH_ABI),armeabi) MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-armv5/output) MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include) endif ifeq ($(TARGET_ARCH_ABI),arm64-v8a) MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-arm64/output) MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include) endif ifeq ($(TARGET_ARCH_ABI),x86) MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-x86/output) MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include) endif ifeq ($(TARGET_ARCH_ABI),x86_64) MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-x86_64/output) MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include) endif include $(call all-subdir-makefiles) ================================================ FILE: android/ijkplayer/ijkplayer-armv7a/src/main/jni/Application.mk ================================================ # Copyright (c) 2013 Bilibili # copyright (c) 2013 Zhang Rui # # This file is part of ijkPlayer. # # ijkPlayer 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. # # ijkPlayer 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 ijkPlayer; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA APP_OPTIM := release APP_PLATFORM := android-9 APP_ABI := armeabi-v7a NDK_TOOLCHAIN_VERSION=4.9 APP_PIE := false APP_STL := stlport_static APP_CFLAGS := -O3 -Wall -pipe \ -ffast-math \ -fstrict-aliasing -Werror=strict-aliasing \ -Wno-psabi -Wa,--noexecstack \ -DANDROID -DNDEBUG ================================================ FILE: android/ijkplayer/ijkplayer-armv7a/src/main/jni/ffmpeg/Android.mk ================================================ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := ijkffmpeg LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/libijkffmpeg.so include $(PREBUILT_SHARED_LIBRARY) ================================================ FILE: android/ijkplayer/ijkplayer-armv7a/src/main/project.properties ================================================ # This file is automatically generated by Android Tools. # Do not modify this file -- YOUR CHANGES WILL BE ERASED! # # This file must be checked in Version Control Systems. # # To customize properties used by the Ant build system edit # "ant.properties", and override values to adapt the script to your # project structure. # # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. target=android-22 android.library=true ================================================ FILE: android/ijkplayer/ijkplayer-armv7a/src/main/res/values/strings.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/.gitignore ================================================ /build ================================================ FILE: android/ijkplayer/ijkplayer-example/build.gradle ================================================ apply plugin: 'com.android.application' android { // http://tools.android.com/tech-docs/new-build-system/tips //noinspection GroovyAssignabilityCheck compileSdkVersion rootProject.ext.compileSdkVersion //noinspection GroovyAssignabilityCheck buildToolsVersion rootProject.ext.buildToolsVersion lintOptions { abortOnError false } defaultConfig { applicationId "tv.danmaku.ijk.media.example" minSdkVersion 9 targetSdkVersion rootProject.ext.targetSdkVersion versionCode rootProject.ext.versionCode versionName rootProject.ext.versionName } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } productFlavors { all32 { minSdkVersion 9 } all64 { minSdkVersion 21 } // armv5 {} // armv7a {} // arm64 { minSdkVersion 21 } // x86 {} } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile 'com.android.support:appcompat-v7:23.0.1' compile 'com.android.support:preference-v7:23.0.1' compile 'com.android.support:support-annotations:23.0.1' compile 'com.squareup:otto:1.3.8' compile project(':ijkplayer-java') compile project(':ijkplayer-exo') all32Compile project(':ijkplayer-armv5') all32Compile project(':ijkplayer-armv7a') all32Compile project(':ijkplayer-x86') all64Compile project(':ijkplayer-armv5') all64Compile project(':ijkplayer-armv7a') all64Compile project(':ijkplayer-arm64') all64Compile project(':ijkplayer-x86') all64Compile project(':ijkplayer-x86_64') // compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8' // compile 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.8' // all32Compile 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8' // all32Compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8' // all32Compile 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8' // all64Compile 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8' // all64Compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8' // all64Compile 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8' // all64Compile 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8' // all64Compile 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8' // armv5Compile project(':player-armv5') // armv7aCompile project(':player-armv7a') // arm64Compile project(':player-arm64') // x86Compile project(':player-x86') // x86_64Compile project(':player-x86_64') } ================================================ FILE: android/ijkplayer/ijkplayer-example/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /opt/android/ADK/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: android/ijkplayer/ijkplayer-example/src/androidTest/java/tv/danmaku/ijk/media/example/ApplicationTest.java ================================================ package tv.danmaku.ijk.media.example; import android.app.Application; import android.test.ApplicationTestCase; /** * Testing Fundamentals */ public class ApplicationTest extends ApplicationTestCase { public ApplicationTest() { super(Application.class); } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/.classpath ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/.project ================================================ ijkplayer-sample com.android.ide.eclipse.adt.ResourceManagerBuilder com.android.ide.eclipse.adt.PreCompilerBuilder org.eclipse.jdt.core.javabuilder com.android.ide.eclipse.adt.ApkBuilder com.android.ide.eclipse.adt.AndroidNature org.eclipse.jdt.core.javanature ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/.settings/org.eclipse.jdt.core.prefs ================================================ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.compliance=1.6 org.eclipse.jdt.core.compiler.source=1.6 ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/AndroidManifest.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/activities/FileExplorerActivity.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.activities; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.text.TextUtils; import com.squareup.otto.Subscribe; import java.io.File; import java.io.IOException; import tv.danmaku.ijk.media.example.R; import tv.danmaku.ijk.media.example.application.AppActivity; import tv.danmaku.ijk.media.example.application.Settings; import tv.danmaku.ijk.media.example.eventbus.FileExplorerEvents; import tv.danmaku.ijk.media.example.fragments.FileListFragment; public class FileExplorerActivity extends AppActivity { private Settings mSettings; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (mSettings == null) { mSettings = new Settings(this); } String lastDirectory = mSettings.getLastDirectory(); if (!TextUtils.isEmpty(lastDirectory) && new File(lastDirectory).isDirectory()) doOpenDirectory(lastDirectory, false); else doOpenDirectory("/", false); } @Override protected void onResume() { super.onResume(); FileExplorerEvents.getBus().register(this); } @Override protected void onPause() { super.onPause(); FileExplorerEvents.getBus().unregister(this); } private void doOpenDirectory(String path, boolean addToBackStack) { Fragment newFragment = FileListFragment.newInstance(path); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.body, newFragment); if (addToBackStack) transaction.addToBackStack(null); transaction.commit(); } @Subscribe public void onClickFile(FileExplorerEvents.OnClickFile event) { File f = event.mFile; try { f = f.getAbsoluteFile(); f = f.getCanonicalFile(); if (TextUtils.isEmpty(f.toString())) f = new File("/"); } catch (IOException e) { e.printStackTrace(); } if (f.isDirectory()) { String path = f.toString(); mSettings.setLastDirectory(path); doOpenDirectory(path, true); } else if (f.exists()) { VideoActivity.intentTo(this, f.getPath(), f.getName()); } } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/activities/RecentMediaActivity.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.activities; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.view.Menu; import android.view.MenuItem; import tv.danmaku.ijk.media.example.R; import tv.danmaku.ijk.media.example.application.AppActivity; import tv.danmaku.ijk.media.example.fragments.RecentMediaListFragment; public class RecentMediaActivity extends AppActivity { public static Intent newIntent(Context context) { Intent intent = new Intent(context, RecentMediaActivity.class); return intent; } public static void intentTo(Context context) { context.startActivity(newIntent(context)); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Fragment newFragment = RecentMediaListFragment.newInstance(); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.body, newFragment); transaction.commit(); } @Override public boolean onPrepareOptionsMenu(Menu menu) { boolean show = super.onPrepareOptionsMenu(menu); if (!show) return show; MenuItem item = menu.findItem(R.id.action_recent); if (item != null) item.setVisible(false); return true; } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/activities/SampleMediaActivity.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.activities; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.view.Menu; import android.view.MenuItem; import tv.danmaku.ijk.media.example.R; import tv.danmaku.ijk.media.example.application.AppActivity; import tv.danmaku.ijk.media.example.fragments.SampleMediaListFragment; public class SampleMediaActivity extends AppActivity { public static Intent newIntent(Context context) { Intent intent = new Intent(context, SampleMediaActivity.class); return intent; } public static void intentTo(Context context) { context.startActivity(newIntent(context)); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Fragment newFragment = SampleMediaListFragment.newInstance(); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.body, newFragment); transaction.commit(); } @Override public boolean onPrepareOptionsMenu(Menu menu) { boolean show = super.onPrepareOptionsMenu(menu); if (!show) return show; MenuItem item = menu.findItem(R.id.action_recent); if (item != null) item.setVisible(false); return true; } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/activities/SettingsActivity.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.activities; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import tv.danmaku.ijk.media.example.R; import tv.danmaku.ijk.media.example.fragments.SettingsFragment; public class SettingsActivity extends AppCompatActivity { public static Intent newIntent(Context context) { Intent intent = new Intent(context, SettingsActivity.class); return intent; } public static void intentTo(Context context) { context.startActivity(newIntent(context)); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_app); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); Fragment newFragment = SettingsFragment.newInstance(); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.body, newFragment); transaction.commit(); } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/activities/VideoActivity.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.activities; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.graphics.Color; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.text.TextUtils; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.ViewGroup; import android.widget.TableLayout; import android.widget.TextView; import tv.danmaku.ijk.media.player.IjkMediaPlayer; import tv.danmaku.ijk.media.player.misc.ITrackInfo; import tv.danmaku.ijk.media.example.R; import tv.danmaku.ijk.media.example.application.Settings; import tv.danmaku.ijk.media.example.content.RecentMediaStorage; import tv.danmaku.ijk.media.example.fragments.TracksFragment; import tv.danmaku.ijk.media.example.widget.media.AndroidMediaController; import tv.danmaku.ijk.media.example.widget.media.IjkVideoView; import tv.danmaku.ijk.media.example.widget.media.MeasureHelper; public class VideoActivity extends AppCompatActivity implements TracksFragment.ITrackHolder { private static final String TAG = "VideoActivity"; private String mVideoPath; private Uri mVideoUri; private AndroidMediaController mMediaController; private IjkVideoView mVideoView; private TextView mToastTextView; private TableLayout mHudView; private DrawerLayout mDrawerLayout; private ViewGroup mRightDrawer; private Settings mSettings; private boolean mBackPressed; public static Intent newIntent(Context context, String videoPath, String videoTitle) { Intent intent = new Intent(context, VideoActivity.class); intent.putExtra("videoPath", videoPath); intent.putExtra("videoTitle", videoTitle); return intent; } public static void intentTo(Context context, String videoPath, String videoTitle) { context.startActivity(newIntent(context, videoPath, videoTitle)); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_player); mSettings = new Settings(this); // handle arguments mVideoPath = getIntent().getStringExtra("videoPath"); Intent intent = getIntent(); String intentAction = intent.getAction(); if (!TextUtils.isEmpty(intentAction)) { if (intentAction.equals(Intent.ACTION_VIEW)) { mVideoPath = intent.getDataString(); } else if (intentAction.equals(Intent.ACTION_SEND)) { mVideoUri = intent.getParcelableExtra(Intent.EXTRA_STREAM); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { String scheme = mVideoUri.getScheme(); if (TextUtils.isEmpty(scheme)) { Log.e(TAG, "Null unknown scheme\n"); finish(); return; } if (scheme.equals(ContentResolver.SCHEME_ANDROID_RESOURCE)) { mVideoPath = mVideoUri.getPath(); } else if (scheme.equals(ContentResolver.SCHEME_CONTENT)) { Log.e(TAG, "Can not resolve content below Android-ICS\n"); finish(); return; } else { Log.e(TAG, "Unknown scheme " + scheme + "\n"); finish(); return; } } } } if (!TextUtils.isEmpty(mVideoPath)) { new RecentMediaStorage(this).saveUrlAsync(mVideoPath); } // init UI Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); ActionBar actionBar = getSupportActionBar(); mMediaController = new AndroidMediaController(this, false); mMediaController.setSupportActionBar(actionBar); mToastTextView = (TextView) findViewById(R.id.toast_text_view); mHudView = (TableLayout) findViewById(R.id.hud_view); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); mRightDrawer = (ViewGroup) findViewById(R.id.right_drawer); mDrawerLayout.setScrimColor(Color.TRANSPARENT); // init player IjkMediaPlayer.loadLibrariesOnce(null); IjkMediaPlayer.native_profileBegin("libijkplayer.so"); mVideoView = (IjkVideoView) findViewById(R.id.video_view); mVideoView.setMediaController(mMediaController); mVideoView.setHudView(mHudView); // prefer mVideoPath if (mVideoPath != null) mVideoView.setVideoPath(mVideoPath); else if (mVideoUri != null) mVideoView.setVideoURI(mVideoUri); else { Log.e(TAG, "Null Data Source\n"); finish(); return; } mVideoView.start(); } @Override public void onBackPressed() { mBackPressed = true; super.onBackPressed(); } @Override protected void onStop() { super.onStop(); if (mBackPressed || !mVideoView.isBackgroundPlayEnabled()) { mVideoView.stopPlayback(); mVideoView.release(true); mVideoView.stopBackgroundPlay(); } else { mVideoView.enterBackground(); } IjkMediaPlayer.native_profileEnd(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_player, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_toggle_ratio) { int aspectRatio = mVideoView.toggleAspectRatio(); String aspectRatioText = MeasureHelper.getAspectRatioText(this, aspectRatio); mToastTextView.setText(aspectRatioText); mMediaController.showOnce(mToastTextView); return true; } else if (id == R.id.action_toggle_player) { int player = mVideoView.togglePlayer(); String playerText = IjkVideoView.getPlayerText(this, player); mToastTextView.setText(playerText); mMediaController.showOnce(mToastTextView); return true; } else if (id == R.id.action_toggle_render) { int render = mVideoView.toggleRender(); String renderText = IjkVideoView.getRenderText(this, render); mToastTextView.setText(renderText); mMediaController.showOnce(mToastTextView); return true; } else if (id == R.id.action_show_info) { mVideoView.showMediaInfo(); } else if (id == R.id.action_show_tracks) { if (mDrawerLayout.isDrawerOpen(mRightDrawer)) { Fragment f = getSupportFragmentManager().findFragmentById(R.id.right_drawer); if (f != null) { FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.remove(f); transaction.commit(); } mDrawerLayout.closeDrawer(mRightDrawer); } else { Fragment f = TracksFragment.newInstance(); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.right_drawer, f); transaction.commit(); mDrawerLayout.openDrawer(mRightDrawer); } } return super.onOptionsItemSelected(item); } @Override public ITrackInfo[] getTrackInfo() { if (mVideoView == null) return null; return mVideoView.getTrackInfo(); } @Override public void selectTrack(int stream) { mVideoView.selectTrack(stream); } @Override public void deselectTrack(int stream) { mVideoView.deselectTrack(stream); } @Override public int getSelectedTrack(int trackType) { if (mVideoView == null) return -1; return mVideoView.getSelectedTrack(trackType); } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/application/AppActivity.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.application; import android.Manifest; import android.annotation.SuppressLint; import android.content.pm.PackageManager; import android.os.Bundle; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import tv.danmaku.ijk.media.example.R; import tv.danmaku.ijk.media.example.activities.RecentMediaActivity; import tv.danmaku.ijk.media.example.activities.SampleMediaActivity; import tv.danmaku.ijk.media.example.activities.SettingsActivity; @SuppressLint("Registered") public class AppActivity extends AppCompatActivity { private static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_app); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) { // TODO: show explanation } else { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE); } } } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission was granted, yay! Do the task you need to do. } else { // permission denied, boo! Disable the functionality that depends on this permission. } } } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_app, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_settings) { SettingsActivity.intentTo(this); return true; } else if (id == R.id.action_recent) { RecentMediaActivity.intentTo(this); } else if (id == R.id.action_sample) { SampleMediaActivity.intentTo(this); } return super.onOptionsItemSelected(item); } @Override public boolean onPrepareOptionsMenu(Menu menu) { boolean show = super.onPrepareOptionsMenu(menu); if (!show) return show; return true; } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/application/Settings.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.application; import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; import tv.danmaku.ijk.media.example.R; public class Settings { private Context mAppContext; private SharedPreferences mSharedPreferences; public static final int PV_PLAYER__Auto = 0; public static final int PV_PLAYER__AndroidMediaPlayer = 1; public static final int PV_PLAYER__IjkMediaPlayer = 2; public static final int PV_PLAYER__IjkExoMediaPlayer = 3; public Settings(Context context) { mAppContext = context.getApplicationContext(); mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(mAppContext); } public boolean getEnableBackgroundPlay() { String key = mAppContext.getString(R.string.pref_key_enable_background_play); return mSharedPreferences.getBoolean(key, false); } public int getPlayer() { String key = mAppContext.getString(R.string.pref_key_player); String value = mSharedPreferences.getString(key, ""); try { return Integer.valueOf(value).intValue(); } catch (NumberFormatException e) { return 0; } } public boolean getUsingMediaCodec() { String key = mAppContext.getString(R.string.pref_key_using_media_codec); return mSharedPreferences.getBoolean(key, false); } public boolean getUsingMediaCodecAutoRotate() { String key = mAppContext.getString(R.string.pref_key_using_media_codec_auto_rotate); return mSharedPreferences.getBoolean(key, false); } public boolean getMediaCodecHandleResolutionChange() { String key = mAppContext.getString(R.string.pref_key_media_codec_handle_resolution_change); return mSharedPreferences.getBoolean(key, false); } public boolean getUsingOpenSLES() { String key = mAppContext.getString(R.string.pref_key_using_opensl_es); return mSharedPreferences.getBoolean(key, false); } public String getPixelFormat() { String key = mAppContext.getString(R.string.pref_key_pixel_format); return mSharedPreferences.getString(key, ""); } public boolean getEnableNoView() { String key = mAppContext.getString(R.string.pref_key_enable_no_view); return mSharedPreferences.getBoolean(key, false); } public boolean getEnableSurfaceView() { String key = mAppContext.getString(R.string.pref_key_enable_surface_view); return mSharedPreferences.getBoolean(key, false); } public boolean getEnableTextureView() { String key = mAppContext.getString(R.string.pref_key_enable_texture_view); return mSharedPreferences.getBoolean(key, false); } public boolean getEnableDetachedSurfaceTextureView() { String key = mAppContext.getString(R.string.pref_key_enable_detached_surface_texture); return mSharedPreferences.getBoolean(key, false); } public boolean getUsingMediaDataSource() { String key = mAppContext.getString(R.string.pref_key_using_mediadatasource); return mSharedPreferences.getBoolean(key, false); } public String getLastDirectory() { String key = mAppContext.getString(R.string.pref_key_last_directory); return mSharedPreferences.getString(key, "/"); } public void setLastDirectory(String path) { String key = mAppContext.getString(R.string.pref_key_last_directory); mSharedPreferences.edit().putString(key, path).apply(); } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/content/PathCursor.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.content; import android.database.AbstractCursor; import android.provider.BaseColumns; import android.text.TextUtils; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; import java.util.TreeSet; public class PathCursor extends AbstractCursor { private List mFileList = new ArrayList<>(); public static final String CN_ID = BaseColumns._ID; public static final String CN_FILE_NAME = "file_name"; public static final String CN_FILE_PATH = "file_path"; public static final String CN_IS_DIRECTORY = "is_directory"; public static final String CN_IS_VIDEO = "is_video"; public static final String[] columnNames = new String[]{CN_ID, CN_FILE_NAME, CN_FILE_PATH, CN_IS_DIRECTORY, CN_IS_VIDEO}; public static final int CI_ID = 0; public static final int CI_FILE_NAME = 1; public static final int CI_FILE_PATH = 2; public static final int CI_IS_DIRECTORY = 3; public static final int CI_IS_VIDEO = 4; PathCursor(File parentDirectory, File[] fileList) { if (parentDirectory.getParent() != null) { FileItem parentFile = new FileItem(new File(parentDirectory, "..")); parentFile.isDirectory = true; mFileList.add(parentFile); } if (fileList != null) { for (File file : fileList) { mFileList.add(new FileItem(file)); } Collections.sort(this.mFileList, sComparator); } } @Override public int getCount() { return mFileList.size(); } @Override public String[] getColumnNames() { return columnNames; } @Override public String getString(int column) { switch (column) { case CI_FILE_NAME: return mFileList.get(getPosition()).file.getName(); case CI_FILE_PATH: return mFileList.get(getPosition()).file.toString(); } return null; } @Override public short getShort(int column) { return (short) getLong(column); } @Override public int getInt(int column) { return (int) getLong(column); } @Override public long getLong(int column) { switch (column) { case CI_ID: return getPosition(); case CI_IS_DIRECTORY: return mFileList.get(getPosition()).isDirectory ? 1 : 0; case CI_IS_VIDEO: return mFileList.get(getPosition()).isVideo ? 1 : 0; } return 0; } @Override public float getFloat(int column) { return 0; } @Override public double getDouble(int column) { return 0; } @Override public boolean isNull(int column) { return mFileList == null; } public static Comparator sComparator = new Comparator() { @Override public int compare(FileItem lhs, FileItem rhs) { if (lhs.isDirectory && !rhs.isDirectory) return -1; else if (!lhs.isDirectory && rhs.isDirectory) return 1; return lhs.file.getName().compareToIgnoreCase(rhs.file.getName()); } }; private static Set sMediaExtSet = new TreeSet(String.CASE_INSENSITIVE_ORDER); static { sMediaExtSet.add("flv"); sMediaExtSet.add("mp4"); } private class FileItem { public File file; public boolean isDirectory; public boolean isVideo; public FileItem(String file) { this(new File(file)); } public FileItem(File file) { this.file = file; this.isDirectory = file.isDirectory(); String fileName = file.getName(); if (!TextUtils.isEmpty(fileName)) { int extPos = fileName.lastIndexOf('.'); if (extPos >= 0) { String ext = fileName.substring(extPos + 1); if (!TextUtils.isEmpty(ext) && sMediaExtSet.contains(ext)) { this.isVideo = true; } } } } } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/content/PathCursorLoader.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.content; import android.content.Context; import android.database.Cursor; import android.os.Environment; import android.support.v4.content.AsyncTaskLoader; import java.io.File; public class PathCursorLoader extends AsyncTaskLoader { private File mPath; public PathCursorLoader(Context context) { this(context, Environment.getExternalStorageDirectory()); } public PathCursorLoader(Context context, String path) { super(context); mPath = new File(path).getAbsoluteFile(); } public PathCursorLoader(Context context, File path) { super(context); mPath = path; } @Override public Cursor loadInBackground() { File[] file_list = mPath.listFiles(); return new PathCursor(mPath, file_list); } @Override protected void onStartLoading() { forceLoad(); } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/content/RecentMediaStorage.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.content; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.os.AsyncTask; import android.support.v4.content.AsyncTaskLoader; import android.text.TextUtils; public class RecentMediaStorage { private Context mAppContext; public RecentMediaStorage(Context context) { mAppContext = context.getApplicationContext(); } public void saveUrlAsync(String url) { new AsyncTask() { @Override protected Void doInBackground(String... params) { saveUrl(params[0]); return null; } }.execute(url); } public void saveUrl(String url) { ContentValues cv = new ContentValues(); cv.putNull(Entry.COLUMN_NAME_ID); cv.put(Entry.COLUMN_NAME_URL, url); cv.put(Entry.COLUMN_NAME_LAST_ACCESS, System.currentTimeMillis()); cv.put(Entry.COLUMN_NAME_NAME, getNameOfUrl(url)); save(cv); } public void save(ContentValues contentValue) { OpenHelper openHelper = new OpenHelper(mAppContext); SQLiteDatabase db = openHelper.getWritableDatabase(); db.replace(Entry.TABLE_NAME, null, contentValue); } public static String getNameOfUrl(String url) { return getNameOfUrl(url, ""); } public static String getNameOfUrl(String url, String defaultName) { String name = null; int pos = url.lastIndexOf('/'); if (pos >= 0) name = url.substring(pos + 1); if (TextUtils.isEmpty(name)) name = defaultName; return name; } public static class Entry { public static final String TABLE_NAME = "RecentMedia"; public static final String COLUMN_NAME_ID = "id"; public static final String COLUMN_NAME_URL = "url"; public static final String COLUMN_NAME_NAME = "name"; public static final String COLUMN_NAME_LAST_ACCESS = "last_access"; } public static final String ALL_COLUMNS[] = new String[]{ Entry.COLUMN_NAME_ID + " as _id", Entry.COLUMN_NAME_ID, Entry.COLUMN_NAME_URL, Entry.COLUMN_NAME_NAME, Entry.COLUMN_NAME_LAST_ACCESS}; public static class OpenHelper extends SQLiteOpenHelper { private static final int DATABASE_VERSION = 1; private static final String DATABASE_NAME = "RecentMedia.db"; private static final String SQL_CREATE_ENTRIES = " CREATE TABLE IF NOT EXISTS " + Entry.TABLE_NAME + " (" + Entry.COLUMN_NAME_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + Entry.COLUMN_NAME_URL + " VARCHAR UNIQUE, " + Entry.COLUMN_NAME_NAME + " VARCHAR, " + Entry.COLUMN_NAME_LAST_ACCESS + " INTEGER) "; public OpenHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(SQL_CREATE_ENTRIES); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } } public static class CursorLoader extends AsyncTaskLoader { public CursorLoader(Context context) { super(context); } @Override public Cursor loadInBackground() { Context context = getContext(); OpenHelper openHelper = new OpenHelper(context); SQLiteDatabase db = openHelper.getReadableDatabase(); return db.query(Entry.TABLE_NAME, ALL_COLUMNS, null, null, null, null, Entry.COLUMN_NAME_LAST_ACCESS + " DESC", "100"); } @Override protected void onStartLoading() { forceLoad(); } } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/eventbus/FileExplorerEvents.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.eventbus; import com.squareup.otto.Bus; import java.io.File; public class FileExplorerEvents { private static final Bus BUS = new Bus(); public static Bus getBus() { return BUS; } private FileExplorerEvents() { // No instances. } public static class OnClickFile { public File mFile; public OnClickFile(String path) { this(new File(path)); } public OnClickFile(File file) { mFile = file; } } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/fragments/FileListFragment.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.fragments; import android.app.Activity; import android.content.Context; import android.database.Cursor; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.support.v4.widget.SimpleCursorAdapter; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import java.io.File; import tv.danmaku.ijk.media.example.R; import tv.danmaku.ijk.media.example.content.PathCursor; import tv.danmaku.ijk.media.example.content.PathCursorLoader; import tv.danmaku.ijk.media.example.eventbus.FileExplorerEvents; public class FileListFragment extends Fragment implements LoaderManager.LoaderCallbacks { private static final String ARG_PATH = "path"; private TextView mPathView; private ListView mFileListView; private VideoAdapter mAdapter; private String mPath; public static FileListFragment newInstance(String path) { FileListFragment f = new FileListFragment(); // Supply index input as an argument. Bundle args = new Bundle(); args.putString(ARG_PATH, path); f.setArguments(args); return f; } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ViewGroup viewGroup = (ViewGroup) inflater.inflate(R.layout.fragment_file_list, container, false); mPathView = (TextView) viewGroup.findViewById(R.id.path_view); mFileListView = (ListView) viewGroup.findViewById(R.id.file_list_view); mPathView.setVisibility(View.VISIBLE); return viewGroup; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Activity activity = getActivity(); Bundle bundle = getArguments(); if (bundle != null) { mPath = bundle.getString(ARG_PATH); mPath = new File(mPath).getAbsolutePath(); mPathView.setText(mPath); } mAdapter = new VideoAdapter(activity); mFileListView.setAdapter(mAdapter); mFileListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, final int position, final long id) { String path = mAdapter.getFilePath(position); if (TextUtils.isEmpty(path)) return; FileExplorerEvents.getBus().post(new FileExplorerEvents.OnClickFile(path)); } }); getLoaderManager().initLoader(1, null, this); } @Override public Loader onCreateLoader(int id, Bundle args) { if (TextUtils.isEmpty(mPath)) return null; return new PathCursorLoader(getActivity(), mPath); } @Override public void onLoadFinished(Loader loader, Cursor data) { mAdapter.swapCursor(data); mAdapter.notifyDataSetChanged(); } @Override public void onLoaderReset(Loader loader) { } final class VideoAdapter extends SimpleCursorAdapter { final class ViewHolder { public ImageView iconImageView; public TextView nameTextView; } public VideoAdapter(Context context) { super(context, android.R.layout.simple_list_item_2, null, new String[]{PathCursor.CN_FILE_NAME, PathCursor.CN_FILE_PATH}, new int[]{android.R.id.text1, android.R.id.text2}, 0); } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = convertView; if (view == null) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); view = inflater.inflate(R.layout.fragment_file_list_item, parent, false); } ViewHolder viewHolder = (ViewHolder) view.getTag(); if (viewHolder == null) { viewHolder = new ViewHolder(); viewHolder.iconImageView = (ImageView) view.findViewById(R.id.icon); viewHolder.nameTextView = (TextView) view.findViewById(R.id.name); } if (isDirectory(position)) { viewHolder.iconImageView.setImageResource(R.drawable.ic_theme_folder); } else if (isVideo(position)) { viewHolder.iconImageView.setImageResource(R.drawable.ic_theme_play_arrow); } else { viewHolder.iconImageView.setImageResource(R.drawable.ic_theme_description); } viewHolder.nameTextView.setText(getFileName(position)); return view; } @Override public long getItemId(int position) { final Cursor cursor = moveToPosition(position); if (cursor == null) return 0; return cursor.getLong(PathCursor.CI_ID); } Cursor moveToPosition(int position) { final Cursor cursor = getCursor(); if (cursor.getCount() == 0 || position >= cursor.getCount()) { return null; } cursor.moveToPosition(position); return cursor; } public boolean isDirectory(int position) { final Cursor cursor = moveToPosition(position); if (cursor == null) return true; return cursor.getInt(PathCursor.CI_IS_DIRECTORY) != 0; } public boolean isVideo(int position) { final Cursor cursor = moveToPosition(position); if (cursor == null) return true; return cursor.getInt(PathCursor.CI_IS_VIDEO) != 0; } public String getFileName(int position) { final Cursor cursor = moveToPosition(position); if (cursor == null) return ""; return cursor.getString(PathCursor.CI_FILE_NAME); } public String getFilePath(int position) { final Cursor cursor = moveToPosition(position); if (cursor == null) return ""; return cursor.getString(PathCursor.CI_FILE_PATH); } } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/fragments/RecentMediaListFragment.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.fragments; import android.app.Activity; import android.content.Context; import android.database.Cursor; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.support.v4.widget.SimpleCursorAdapter; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ListView; import tv.danmaku.ijk.media.example.R; import tv.danmaku.ijk.media.example.activities.VideoActivity; import tv.danmaku.ijk.media.example.content.RecentMediaStorage; public class RecentMediaListFragment extends Fragment implements LoaderManager.LoaderCallbacks { private ListView mFileListView; private RecentMediaAdapter mAdapter; public static RecentMediaListFragment newInstance() { RecentMediaListFragment f = new RecentMediaListFragment(); return f; } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ViewGroup viewGroup = (ViewGroup) inflater.inflate(R.layout.fragment_file_list, container, false); mFileListView = (ListView) viewGroup.findViewById(R.id.file_list_view); return viewGroup; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); final Activity activity = getActivity(); mAdapter = new RecentMediaAdapter(activity); mFileListView.setAdapter(mAdapter); mFileListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, final int position, final long id) { String url = mAdapter.getUrl(position); String name = mAdapter.getName(position); VideoActivity.intentTo(activity, url, name); } }); getLoaderManager().initLoader(2, null, this); } @Override public Loader onCreateLoader(int id, Bundle args) { return new RecentMediaStorage.CursorLoader(getActivity()); } @Override public void onLoadFinished(Loader loader, Cursor data) { mAdapter.swapCursor(data); mAdapter.notifyDataSetChanged(); } @Override public void onLoaderReset(Loader loader) { } final class RecentMediaAdapter extends SimpleCursorAdapter { private int mIndex_id = -1; private int mIndex_url = -1; private int mIndex_name = -1; public RecentMediaAdapter(Context context) { super(context, android.R.layout.simple_list_item_2, null, new String[]{RecentMediaStorage.Entry.COLUMN_NAME_NAME, RecentMediaStorage.Entry.COLUMN_NAME_URL}, new int[]{android.R.id.text1, android.R.id.text2}, 0); } @Override public Cursor swapCursor(Cursor c) { Cursor res = super.swapCursor(c); mIndex_id = c.getColumnIndex(RecentMediaStorage.Entry.COLUMN_NAME_ID); mIndex_url = c.getColumnIndex(RecentMediaStorage.Entry.COLUMN_NAME_URL); mIndex_name = c.getColumnIndex(RecentMediaStorage.Entry.COLUMN_NAME_NAME); return res; } @Override public long getItemId(int position) { final Cursor cursor = moveToPosition(position); if (cursor == null) return 0; return cursor.getLong(mIndex_id); } Cursor moveToPosition(int position) { final Cursor cursor = getCursor(); if (cursor.getCount() == 0 || position >= cursor.getCount()) { return null; } cursor.moveToPosition(position); return cursor; } public String getUrl(int position) { final Cursor cursor = moveToPosition(position); if (cursor == null) return ""; return cursor.getString(mIndex_url); } public String getName(int position) { final Cursor cursor = moveToPosition(position); if (cursor == null) return ""; return cursor.getString(mIndex_name); } } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/fragments/SampleMediaListFragment.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.fragments; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; import tv.danmaku.ijk.media.example.R; import tv.danmaku.ijk.media.example.activities.VideoActivity; public class SampleMediaListFragment extends Fragment { private ListView mFileListView; private SampleMediaAdapter mAdapter; public static SampleMediaListFragment newInstance() { SampleMediaListFragment f = new SampleMediaListFragment(); return f; } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ViewGroup viewGroup = (ViewGroup) inflater.inflate(R.layout.fragment_file_list, container, false); mFileListView = (ListView) viewGroup.findViewById(R.id.file_list_view); return viewGroup; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); final Activity activity = getActivity(); mAdapter = new SampleMediaAdapter(activity); mFileListView.setAdapter(mAdapter); mFileListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, final int position, final long id) { SampleMediaItem item = mAdapter.getItem(position); String name = item.mName; String url = item.mUrl; VideoActivity.intentTo(activity, url, name); } }); String manifest_string = "{\n" + " \"version\": \"1.0.0\",\n" + " \"adaptationSet\": [\n" + " {\n" + " \"duration\": 1000,\n" + " \"id\": 1,\n" + " \"representation\": [\n" + " {\n" + " \"id\": 1,\n" + " \"codec\": \"avc1.64001e,mp4a.40.5\",\n" + " \"url\": \"http://las-tech.org.cn/kwai/las-test_ld500d.flv\",\n" + " \"backupUrl\": [],\n" + " \"host\": \"las-tech.org.cn\",\n" + " \"maxBitrate\": 700,\n" + " \"width\": 640,\n" + " \"height\": 360,\n" + " \"frameRate\": 25,\n" + " \"qualityType\": \"SMOOTH\",\n" + " \"qualityTypeName\": \"流畅\",\n" + " \"hidden\": false,\n" + " \"disabledFromAdaptive\": false,\n" + " \"defaultSelected\": false\n" + " },\n" + " {\n" + " \"id\": 2,\n" + " \"codec\": \"avc1.64001f,mp4a.40.5\",\n" + " \"url\": \"http://las-tech.org.cn/kwai/las-test_sd1000d.flv\",\n" + " \"backupUrl\": [],\n" + " \"host\": \"las-tech.org.cn\",\n" + " \"maxBitrate\": 1300,\n" + " \"width\": 960,\n" + " \"height\": 540,\n" + " \"frameRate\": 25,\n" + " \"qualityType\": \"STANDARD\",\n" + " \"qualityTypeName\": \"标清\",\n" + " \"hidden\": false,\n" + " \"disabledFromAdaptive\": false,\n" + " \"defaultSelected\": true\n" + " },\n" + " {\n" + " \"id\": 3,\n" + " \"codec\": \"avc1.64001f,mp4a.40.5\",\n" + " \"url\": \"http://las-tech.org.cn/kwai/las-test.flv\",\n" + " \"backupUrl\": [],\n" + " \"host\": \"las-tech.org.cn\",\n" + " \"maxBitrate\": 2300,\n" + " \"width\": 1280,\n" + " \"height\": 720,\n" + " \"frameRate\": 30,\n" + " \"qualityType\": \"HIGH\",\n" + " \"qualityTypeName\": \"高清\",\n" + " \"hidden\": false,\n" + " \"disabledFromAdaptive\": false,\n" + " \"defaultSelected\": false\n" + " }\n" + " ]\n" + " }\n" + " ]\n" + "}"; mAdapter.addItem(manifest_string, "las test"); 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"); mAdapter.addItem("http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear3/prog_index.m3u8", "bipbop basic 640x480 @ 1 Mbps"); mAdapter.addItem("http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear4/prog_index.m3u8", "bipbop basic 960x720 @ 2 Mbps"); mAdapter.addItem("http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear0/prog_index.m3u8", "bipbop basic 22.050Hz stereo @ 40 kbps"); mAdapter.addItem("http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8", "bipbop advanced master playlist"); mAdapter.addItem("http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear1/prog_index.m3u8", "bipbop advanced 416x234 @ 265 kbps"); mAdapter.addItem("http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear2/prog_index.m3u8", "bipbop advanced 640x360 @ 580 kbps"); mAdapter.addItem("http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear3/prog_index.m3u8", "bipbop advanced 960x540 @ 910 kbps"); mAdapter.addItem("http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear4/prog_index.m3u8", "bipbop advanced 1289x720 @ 1 Mbps"); mAdapter.addItem("http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear5/prog_index.m3u8", "bipbop advanced 1920x1080 @ 2 Mbps"); mAdapter.addItem("http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear0/prog_index.m3u8", "bipbop advanced 22.050Hz stereo @ 40 kbps"); } final class SampleMediaItem { String mUrl; String mName; public SampleMediaItem(String url, String name) { mUrl = url; mName = name; } } final class SampleMediaAdapter extends ArrayAdapter { public SampleMediaAdapter(Context context) { super(context, android.R.layout.simple_list_item_2); } public void addItem(String url, String name) { add(new SampleMediaItem(url, name)); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = convertView; if (view == null) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); view = inflater.inflate(android.R.layout.simple_list_item_2, parent, false); } ViewHolder viewHolder = (ViewHolder) view.getTag(); if (viewHolder == null) { viewHolder = new ViewHolder(); viewHolder.mNameTextView = (TextView) view.findViewById(android.R.id.text1); viewHolder.mUrlTextView = (TextView) view.findViewById(android.R.id.text2); } SampleMediaItem item = getItem(position); viewHolder.mNameTextView.setText(item.mName); viewHolder.mUrlTextView.setText(item.mUrl); return view; } final class ViewHolder { public TextView mNameTextView; public TextView mUrlTextView; } } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/fragments/SettingsFragment.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.fragments; import android.os.Bundle; import android.support.v7.preference.PreferenceFragmentCompat; import tv.danmaku.ijk.media.example.R; public class SettingsFragment extends PreferenceFragmentCompat { public static SettingsFragment newInstance() { SettingsFragment f = new SettingsFragment(); return f; } @Override public void onCreatePreferences(Bundle bundle, String s) { addPreferencesFromResource(R.xml.settings); } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/fragments/TracksFragment.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.fragments; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; import java.util.Locale; import tv.danmaku.ijk.media.player.misc.ITrackInfo; import tv.danmaku.ijk.media.example.R; public class TracksFragment extends Fragment { private ListView mTrackListView; private TrackAdapter mAdapter; public static TracksFragment newInstance() { TracksFragment f = new TracksFragment(); return f; } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ViewGroup viewGroup = (ViewGroup) inflater.inflate(R.layout.fragment_track_list, container, false); mTrackListView = (ListView) viewGroup.findViewById(R.id.track_list_view); return viewGroup; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); final Activity activity = getActivity(); mAdapter = new TrackAdapter(activity); mTrackListView.setAdapter(mAdapter); if (activity instanceof ITrackHolder) { final ITrackHolder trackHolder = (ITrackHolder) activity; mAdapter.setTrackHolder(trackHolder); int selectedVideoTrack = trackHolder.getSelectedTrack(ITrackInfo.MEDIA_TRACK_TYPE_VIDEO); int selectedAudioTrack = trackHolder.getSelectedTrack(ITrackInfo.MEDIA_TRACK_TYPE_AUDIO); int selectedSubtitleTrack = trackHolder.getSelectedTrack(ITrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT); if (selectedVideoTrack >= 0) mTrackListView.setItemChecked(selectedVideoTrack, true); if (selectedAudioTrack >= 0) mTrackListView.setItemChecked(selectedAudioTrack, true); if (selectedSubtitleTrack >= 0) mTrackListView.setItemChecked(selectedSubtitleTrack, true); mTrackListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, final int position, final long id) { TrackItem trackItem = (TrackItem) mTrackListView.getItemAtPosition(position); for (int i = 0; i < mAdapter.getCount(); ++i) { TrackItem compareItem = mAdapter.getItem(i); if (compareItem.mIndex == trackItem.mIndex) continue; if (compareItem.mTrackInfo.getTrackType() != trackItem.mTrackInfo.getTrackType()) continue; if (mTrackListView.isItemChecked(i)) mTrackListView.setItemChecked(i, false); } if (mTrackListView.isItemChecked(position)) { trackHolder.selectTrack(trackItem.mIndex); } else { trackHolder.deselectTrack(trackItem.mIndex); } } }); } else { Log.e("TracksFragment", "activity is not an instance of ITrackHolder."); } } public interface ITrackHolder { ITrackInfo[] getTrackInfo(); int getSelectedTrack(int trackType); void selectTrack(int stream); void deselectTrack(int stream); } final class TrackItem { public int mIndex; public ITrackInfo mTrackInfo; public String mInfoInline; public TrackItem(int index, ITrackInfo trackInfo) { mIndex = index; mTrackInfo = trackInfo; mInfoInline = String.format(Locale.US, "# %d: %s", mIndex, mTrackInfo.getInfoInline()); } public String getInfoInline() { return mInfoInline; } } final class TrackAdapter extends ArrayAdapter { private ITrackHolder mTrackHolder; private ITrackInfo[] mTrackInfos; public TrackAdapter(Context context) { super(context, android.R.layout.simple_list_item_checked); } public void setTrackHolder(ITrackHolder trackHolder) { clear(); mTrackHolder = trackHolder; mTrackInfos = mTrackHolder.getTrackInfo(); if (mTrackInfos != null) { for(ITrackInfo trackInfo: mTrackInfos) { int index = getCount(); TrackItem item = new TrackItem(index, trackInfo); add(item); } } } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = convertView; if (view == null) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); view = inflater.inflate(android.R.layout.simple_list_item_checked, parent, false); } ViewHolder viewHolder = (ViewHolder) view.getTag(); if (viewHolder == null) { viewHolder = new ViewHolder(); viewHolder.mNameTextView = (TextView) view.findViewById(android.R.id.text1); } TrackItem item = getItem(position); viewHolder.mNameTextView.setText(item.getInfoInline()); return view; } final class ViewHolder { public TextView mNameTextView; } } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/services/MediaPlayerService.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.services; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.support.annotation.Nullable; import tv.danmaku.ijk.media.player.IMediaPlayer; public class MediaPlayerService extends Service { private static IMediaPlayer sMediaPlayer; public static Intent newIntent(Context context) { Intent intent = new Intent(context, MediaPlayerService.class); return intent; } public static void intentToStart(Context context) { context.startService(newIntent(context)); } public static void intentToStop(Context context) { context.stopService(newIntent(context)); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } public static void setMediaPlayer(IMediaPlayer mp) { if (sMediaPlayer != null && sMediaPlayer != mp) { if (sMediaPlayer.isPlaying()) sMediaPlayer.stop(); sMediaPlayer.release(); sMediaPlayer = null; } sMediaPlayer = mp; } public static IMediaPlayer getMediaPlayer() { return sMediaPlayer; } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/AndroidMediaController.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.widget.media; import android.content.Context; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.app.ActionBar; import android.util.AttributeSet; import android.view.View; import android.widget.MediaController; import java.util.ArrayList; public class AndroidMediaController extends MediaController implements IMediaController { private ActionBar mActionBar; public AndroidMediaController(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public AndroidMediaController(Context context, boolean useFastForward) { super(context, useFastForward); initView(context); } public AndroidMediaController(Context context) { super(context); initView(context); } private void initView(Context context) { } public void setSupportActionBar(@Nullable ActionBar actionBar) { mActionBar = actionBar; if (isShowing()) { actionBar.show(); } else { actionBar.hide(); } } @Override public void show() { super.show(); if (mActionBar != null) mActionBar.show(); } @Override public void hide() { super.hide(); if (mActionBar != null) mActionBar.hide(); for (View view : mShowOnceArray) view.setVisibility(View.GONE); mShowOnceArray.clear(); } //---------- // Extends //---------- private ArrayList mShowOnceArray = new ArrayList(); public void showOnce(@NonNull View view) { mShowOnceArray.add(view); view.setVisibility(View.VISIBLE); show(); } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/FileMediaDataSource.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.widget.media; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import tv.danmaku.ijk.media.player.misc.IMediaDataSource; public class FileMediaDataSource implements IMediaDataSource { private RandomAccessFile mFile; private long mFileSize; public FileMediaDataSource(File file) throws IOException { mFile = new RandomAccessFile(file, "r"); mFileSize = mFile.length(); } @Override public int readAt(long position, byte[] buffer, int offset, int size) throws IOException { if (mFile.getFilePointer() != position) mFile.seek(position); if (size == 0) return 0; return mFile.read(buffer, 0, size); } @Override public long getSize() throws IOException { return mFileSize; } @Override public void close() throws IOException { mFileSize = 0; mFile.close(); mFile = null; } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/IMediaController.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.widget.media; import android.view.View; import android.widget.MediaController; public interface IMediaController { void hide(); boolean isShowing(); void setAnchorView(View view); void setEnabled(boolean enabled); void setMediaPlayer(MediaController.MediaPlayerControl player); void show(int timeout); void show(); //---------- // Extends //---------- void showOnce(View view); } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/IRenderView.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.widget.media; import android.graphics.SurfaceTexture; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.Surface; import android.view.SurfaceHolder; import android.view.View; import tv.danmaku.ijk.media.player.IMediaPlayer; public interface IRenderView { int AR_ASPECT_FIT_PARENT = 0; // without clip int AR_ASPECT_FILL_PARENT = 1; // may clip int AR_ASPECT_WRAP_CONTENT = 2; int AR_MATCH_PARENT = 3; int AR_16_9_FIT_PARENT = 4; int AR_4_3_FIT_PARENT = 5; View getView(); boolean shouldWaitForResize(); void setVideoSize(int videoWidth, int videoHeight); void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen); void setVideoRotation(int degree); void setAspectRatio(int aspectRatio); void addRenderCallback(@NonNull IRenderCallback callback); void removeRenderCallback(@NonNull IRenderCallback callback); interface ISurfaceHolder { void bindToMediaPlayer(IMediaPlayer mp); @NonNull IRenderView getRenderView(); @Nullable SurfaceHolder getSurfaceHolder(); @Nullable Surface openSurface(); @Nullable SurfaceTexture getSurfaceTexture(); } interface IRenderCallback { /** * @param holder * @param width could be 0 * @param height could be 0 */ void onSurfaceCreated(@NonNull ISurfaceHolder holder, int width, int height); /** * @param holder * @param format could be 0 * @param width * @param height */ void onSurfaceChanged(@NonNull ISurfaceHolder holder, int format, int width, int height); void onSurfaceDestroyed(@NonNull ISurfaceHolder holder); } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/IjkVideoView.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.widget.media; import android.annotation.TargetApi; import android.content.Context; import android.content.DialogInterface; import android.content.res.Resources; import android.media.AudioManager; import android.media.MediaPlayer; import android.net.Uri; import android.os.Build; import android.support.annotation.NonNull; import android.support.v7.app.AlertDialog; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; import android.widget.MediaController; import android.widget.TableLayout; import android.widget.TextView; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import tv.danmaku.ijk.media.exo.IjkExoMediaPlayer; import tv.danmaku.ijk.media.player.AndroidMediaPlayer; import tv.danmaku.ijk.media.player.IMediaPlayer; import tv.danmaku.ijk.media.player.IjkMediaPlayer; import tv.danmaku.ijk.media.player.IjkTimedText; import tv.danmaku.ijk.media.player.TextureMediaPlayer; import tv.danmaku.ijk.media.player.misc.IMediaDataSource; import tv.danmaku.ijk.media.player.misc.IMediaFormat; import tv.danmaku.ijk.media.player.misc.ITrackInfo; import tv.danmaku.ijk.media.player.misc.IjkMediaFormat; import tv.danmaku.ijk.media.example.R; import tv.danmaku.ijk.media.example.application.Settings; import tv.danmaku.ijk.media.example.services.MediaPlayerService; public class IjkVideoView extends FrameLayout implements MediaController.MediaPlayerControl { private String TAG = "IjkVideoView"; // settable by the client private Uri mUri; private String mManifestString; private Map mHeaders; // all possible internal states private static final int STATE_ERROR = -1; private static final int STATE_IDLE = 0; private static final int STATE_PREPARING = 1; private static final int STATE_PREPARED = 2; private static final int STATE_PLAYING = 3; private static final int STATE_PAUSED = 4; private static final int STATE_PLAYBACK_COMPLETED = 5; // mCurrentState is a VideoView object's current state. // mTargetState is the state that a method caller intends to reach. // For instance, regardless the VideoView object's current state, // calling pause() intends to bring the object to a target state // of STATE_PAUSED. private int mCurrentState = STATE_IDLE; private int mTargetState = STATE_IDLE; // All the stuff we need for playing and showing a video private IRenderView.ISurfaceHolder mSurfaceHolder = null; private IMediaPlayer mMediaPlayer = null; // private int mAudioSession; private int mVideoWidth; private int mVideoHeight; private int mSurfaceWidth; private int mSurfaceHeight; private int mVideoRotationDegree; private IMediaController mMediaController; private IMediaPlayer.OnCompletionListener mOnCompletionListener; private IMediaPlayer.OnPreparedListener mOnPreparedListener; private int mCurrentBufferPercentage; private IMediaPlayer.OnErrorListener mOnErrorListener; private IMediaPlayer.OnInfoListener mOnInfoListener; private int mSeekWhenPrepared; // recording the seek position while preparing private boolean mCanPause = true; private boolean mCanSeekBack = true; private boolean mCanSeekForward = true; /** Subtitle rendering widget overlaid on top of the video. */ // private RenderingWidget mSubtitleWidget; /** * Listener for changes to subtitle data, used to redraw when needed. */ // private RenderingWidget.OnChangedListener mSubtitlesChangedListener; private Context mAppContext; private Settings mSettings; private IRenderView mRenderView; private int mVideoSarNum; private int mVideoSarDen; private InfoHudViewHolder mHudViewHolder; private long mPrepareStartTime = 0; private long mPrepareEndTime = 0; private long mSeekStartTime = 0; private long mSeekEndTime = 0; private TextView subtitleDisplay; public IjkVideoView(Context context) { super(context); initVideoView(context); } public IjkVideoView(Context context, AttributeSet attrs) { super(context, attrs); initVideoView(context); } public IjkVideoView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initVideoView(context); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public IjkVideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); initVideoView(context); } // REMOVED: onMeasure // REMOVED: onInitializeAccessibilityEvent // REMOVED: onInitializeAccessibilityNodeInfo // REMOVED: resolveAdjustedSize private void initVideoView(Context context) { mAppContext = context.getApplicationContext(); mSettings = new Settings(mAppContext); initBackground(); initRenders(); mVideoWidth = 0; mVideoHeight = 0; // REMOVED: getHolder().addCallback(mSHCallback); // REMOVED: getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); setFocusable(true); setFocusableInTouchMode(true); requestFocus(); // REMOVED: mPendingSubtitleTracks = new Vector>(); mCurrentState = STATE_IDLE; mTargetState = STATE_IDLE; subtitleDisplay = new TextView(context); subtitleDisplay.setTextSize(24); subtitleDisplay.setGravity(Gravity.CENTER); FrameLayout.LayoutParams layoutParams_txt = new FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM); addView(subtitleDisplay, layoutParams_txt); } public void setRenderView(IRenderView renderView) { if (mRenderView != null) { if (mMediaPlayer != null) mMediaPlayer.setDisplay(null); View renderUIView = mRenderView.getView(); mRenderView.removeRenderCallback(mSHCallback); mRenderView = null; removeView(renderUIView); } if (renderView == null) return; mRenderView = renderView; renderView.setAspectRatio(mCurrentAspectRatio); if (mVideoWidth > 0 && mVideoHeight > 0) renderView.setVideoSize(mVideoWidth, mVideoHeight); if (mVideoSarNum > 0 && mVideoSarDen > 0) renderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen); View renderUIView = mRenderView.getView(); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER); renderUIView.setLayoutParams(lp); addView(renderUIView); mRenderView.addRenderCallback(mSHCallback); mRenderView.setVideoRotation(mVideoRotationDegree); } public void setRender(int render) { switch (render) { case RENDER_NONE: setRenderView(null); break; case RENDER_TEXTURE_VIEW: { TextureRenderView renderView = new TextureRenderView(getContext()); if (mMediaPlayer != null) { renderView.getSurfaceHolder().bindToMediaPlayer(mMediaPlayer); renderView.setVideoSize(mMediaPlayer.getVideoWidth(), mMediaPlayer.getVideoHeight()); renderView.setVideoSampleAspectRatio(mMediaPlayer.getVideoSarNum(), mMediaPlayer.getVideoSarDen()); renderView.setAspectRatio(mCurrentAspectRatio); } setRenderView(renderView); break; } case RENDER_SURFACE_VIEW: { SurfaceRenderView renderView = new SurfaceRenderView(getContext()); setRenderView(renderView); break; } default: Log.e(TAG, String.format(Locale.getDefault(), "invalid render %d\n", render)); break; } } public void setHudView(TableLayout tableLayout) { mHudViewHolder = new InfoHudViewHolder(getContext(), tableLayout); } /** * Sets video path. * * @param path the path of the video. */ public void setVideoPath(String path) { if (path.contains("adaptationSet")){ mManifestString = path; setVideoURI(Uri.parse("ijklas:")); } else { setVideoURI(Uri.parse(path)); } } /** * Sets video URI. * * @param uri the URI of the video. */ public void setVideoURI(Uri uri) { setVideoURI(uri, null); } /** * Sets video URI using specific headers. * * @param uri the URI of the video. * @param headers the headers for the URI request. * Note that the cross domain redirection is allowed by default, but that can be * changed with key/value pairs through the headers parameter with * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value * to disallow or allow cross domain redirection. */ private void setVideoURI(Uri uri, Map headers) { mUri = uri; mHeaders = headers; mSeekWhenPrepared = 0; openVideo(); requestLayout(); invalidate(); } // REMOVED: addSubtitleSource // REMOVED: mPendingSubtitleTracks public void stopPlayback() { if (mMediaPlayer != null) { mMediaPlayer.stop(); mMediaPlayer.release(); mMediaPlayer = null; if (mHudViewHolder != null) mHudViewHolder.setMediaPlayer(null); mCurrentState = STATE_IDLE; mTargetState = STATE_IDLE; AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE); am.abandonAudioFocus(null); } } @TargetApi(Build.VERSION_CODES.M) private void openVideo() { if (mUri == null || mSurfaceHolder == null) { // not ready for playback just yet, will try again later return; } // we shouldn't clear the target state, because somebody might have // called start() previously release(false); AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE); am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); try { mMediaPlayer = createPlayer(mSettings.getPlayer()); // TODO: create SubtitleController in MediaPlayer, but we need // a context for the subtitle renderers final Context context = getContext(); // REMOVED: SubtitleController // REMOVED: mAudioSession mMediaPlayer.setOnPreparedListener(mPreparedListener); mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener); mMediaPlayer.setOnCompletionListener(mCompletionListener); mMediaPlayer.setOnErrorListener(mErrorListener); mMediaPlayer.setOnInfoListener(mInfoListener); mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener); mMediaPlayer.setOnSeekCompleteListener(mSeekCompleteListener); mMediaPlayer.setOnTimedTextListener(mOnTimedTextListener); mCurrentBufferPercentage = 0; String scheme = mUri.getScheme(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mSettings.getUsingMediaDataSource() && (TextUtils.isEmpty(scheme) || scheme.equalsIgnoreCase("file"))) { IMediaDataSource dataSource = new FileMediaDataSource(new File(mUri.toString())); mMediaPlayer.setDataSource(dataSource); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { mMediaPlayer.setDataSource(mAppContext, mUri, mHeaders); } else { mMediaPlayer.setDataSource(mUri.toString()); } bindSurfaceHolder(mMediaPlayer, mSurfaceHolder); mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mMediaPlayer.setScreenOnWhilePlaying(true); mPrepareStartTime = System.currentTimeMillis(); mMediaPlayer.prepareAsync(); if (mHudViewHolder != null) mHudViewHolder.setMediaPlayer(mMediaPlayer); // REMOVED: mPendingSubtitleTracks // we don't set the target state here either, but preserve the // target state that was there before. mCurrentState = STATE_PREPARING; attachMediaController(); } catch (IOException ex) { Log.w(TAG, "Unable to open content: " + mUri, ex); mCurrentState = STATE_ERROR; mTargetState = STATE_ERROR; mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); } catch (IllegalArgumentException ex) { Log.w(TAG, "Unable to open content: " + mUri, ex); mCurrentState = STATE_ERROR; mTargetState = STATE_ERROR; mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); } finally { // REMOVED: mPendingSubtitleTracks.clear(); } } public void setMediaController(IMediaController controller) { if (mMediaController != null) { mMediaController.hide(); } mMediaController = controller; attachMediaController(); } private void attachMediaController() { if (mMediaPlayer != null && mMediaController != null) { mMediaController.setMediaPlayer(this); View anchorView = this.getParent() instanceof View ? (View) this.getParent() : this; mMediaController.setAnchorView(anchorView); mMediaController.setEnabled(isInPlaybackState()); } } IMediaPlayer.OnVideoSizeChangedListener mSizeChangedListener = new IMediaPlayer.OnVideoSizeChangedListener() { public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sarNum, int sarDen) { mVideoWidth = mp.getVideoWidth(); mVideoHeight = mp.getVideoHeight(); mVideoSarNum = mp.getVideoSarNum(); mVideoSarDen = mp.getVideoSarDen(); if (mVideoWidth != 0 && mVideoHeight != 0) { if (mRenderView != null) { mRenderView.setVideoSize(mVideoWidth, mVideoHeight); mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen); } // REMOVED: getHolder().setFixedSize(mVideoWidth, mVideoHeight); requestLayout(); } } }; IMediaPlayer.OnPreparedListener mPreparedListener = new IMediaPlayer.OnPreparedListener() { public void onPrepared(IMediaPlayer mp) { mPrepareEndTime = System.currentTimeMillis(); mHudViewHolder.updateLoadCost(mPrepareEndTime - mPrepareStartTime); mCurrentState = STATE_PREPARED; // Get the capabilities of the player for this stream // REMOVED: Metadata if (mOnPreparedListener != null) { mOnPreparedListener.onPrepared(mMediaPlayer); } if (mMediaController != null) { mMediaController.setEnabled(true); } mVideoWidth = mp.getVideoWidth(); mVideoHeight = mp.getVideoHeight(); int seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be changed after seekTo() call if (seekToPosition != 0) { seekTo(seekToPosition); } if (mVideoWidth != 0 && mVideoHeight != 0) { //Log.i("@@@@", "video size: " + mVideoWidth +"/"+ mVideoHeight); // REMOVED: getHolder().setFixedSize(mVideoWidth, mVideoHeight); if (mRenderView != null) { mRenderView.setVideoSize(mVideoWidth, mVideoHeight); mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen); if (!mRenderView.shouldWaitForResize() || mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) { // We didn't actually change the size (it was already at the size // we need), so we won't get a "surface changed" callback, so // start the video here instead of in the callback. if (mTargetState == STATE_PLAYING) { start(); if (mMediaController != null) { mMediaController.show(); } } else if (!isPlaying() && (seekToPosition != 0 || getCurrentPosition() > 0)) { if (mMediaController != null) { // Show the media controls when we're paused into a video and make 'em stick. mMediaController.show(0); } } } } } else { // We don't know the video size yet, but should start anyway. // The video size might be reported to us later. if (mTargetState == STATE_PLAYING) { start(); } } } }; private IMediaPlayer.OnCompletionListener mCompletionListener = new IMediaPlayer.OnCompletionListener() { public void onCompletion(IMediaPlayer mp) { mCurrentState = STATE_PLAYBACK_COMPLETED; mTargetState = STATE_PLAYBACK_COMPLETED; if (mMediaController != null) { mMediaController.hide(); } if (mOnCompletionListener != null) { mOnCompletionListener.onCompletion(mMediaPlayer); } } }; private IMediaPlayer.OnInfoListener mInfoListener = new IMediaPlayer.OnInfoListener() { public boolean onInfo(IMediaPlayer mp, int arg1, int arg2) { if (mOnInfoListener != null) { mOnInfoListener.onInfo(mp, arg1, arg2); } switch (arg1) { case IMediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING: Log.d(TAG, "MEDIA_INFO_VIDEO_TRACK_LAGGING:"); break; case IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START: Log.d(TAG, "MEDIA_INFO_VIDEO_RENDERING_START:"); break; case IMediaPlayer.MEDIA_INFO_BUFFERING_START: Log.d(TAG, "MEDIA_INFO_BUFFERING_START:"); break; case IMediaPlayer.MEDIA_INFO_BUFFERING_END: Log.d(TAG, "MEDIA_INFO_BUFFERING_END:"); break; case IMediaPlayer.MEDIA_INFO_NETWORK_BANDWIDTH: Log.d(TAG, "MEDIA_INFO_NETWORK_BANDWIDTH: " + arg2); break; case IMediaPlayer.MEDIA_INFO_BAD_INTERLEAVING: Log.d(TAG, "MEDIA_INFO_BAD_INTERLEAVING:"); break; case IMediaPlayer.MEDIA_INFO_NOT_SEEKABLE: Log.d(TAG, "MEDIA_INFO_NOT_SEEKABLE:"); break; case IMediaPlayer.MEDIA_INFO_METADATA_UPDATE: Log.d(TAG, "MEDIA_INFO_METADATA_UPDATE:"); break; case IMediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE: Log.d(TAG, "MEDIA_INFO_UNSUPPORTED_SUBTITLE:"); break; case IMediaPlayer.MEDIA_INFO_SUBTITLE_TIMED_OUT: Log.d(TAG, "MEDIA_INFO_SUBTITLE_TIMED_OUT:"); break; case IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED: mVideoRotationDegree = arg2; Log.d(TAG, "MEDIA_INFO_VIDEO_ROTATION_CHANGED: " + arg2); if (mRenderView != null) mRenderView.setVideoRotation(arg2); break; case IMediaPlayer.MEDIA_INFO_AUDIO_RENDERING_START: Log.d(TAG, "MEDIA_INFO_AUDIO_RENDERING_START:"); break; } return true; } }; private IMediaPlayer.OnErrorListener mErrorListener = new IMediaPlayer.OnErrorListener() { public boolean onError(IMediaPlayer mp, int framework_err, int impl_err) { Log.d(TAG, "Error: " + framework_err + "," + impl_err); mCurrentState = STATE_ERROR; mTargetState = STATE_ERROR; if (mMediaController != null) { mMediaController.hide(); } /* If an error handler has been supplied, use it and finish. */ if (mOnErrorListener != null) { if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) { return true; } } /* Otherwise, pop up an error dialog so the user knows that * something bad has happened. Only try and pop up the dialog * if we're attached to a window. When we're going away and no * longer have a window, don't bother showing the user an error. */ if (getWindowToken() != null) { Resources r = mAppContext.getResources(); int messageId; if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) { messageId = R.string.VideoView_error_text_invalid_progressive_playback; } else { messageId = R.string.VideoView_error_text_unknown; } new AlertDialog.Builder(getContext()) .setMessage(messageId) .setPositiveButton(R.string.VideoView_error_button, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { /* If we get here, there is no onError listener, so * at least inform them that the video is over. */ if (mOnCompletionListener != null) { mOnCompletionListener.onCompletion(mMediaPlayer); } } }) .setCancelable(false) .show(); } return true; } }; private IMediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener = new IMediaPlayer.OnBufferingUpdateListener() { public void onBufferingUpdate(IMediaPlayer mp, int percent) { mCurrentBufferPercentage = percent; } }; private IMediaPlayer.OnSeekCompleteListener mSeekCompleteListener = new IMediaPlayer.OnSeekCompleteListener() { @Override public void onSeekComplete(IMediaPlayer mp) { mSeekEndTime = System.currentTimeMillis(); mHudViewHolder.updateSeekCost(mSeekEndTime - mSeekStartTime); } }; private IMediaPlayer.OnTimedTextListener mOnTimedTextListener = new IMediaPlayer.OnTimedTextListener() { @Override public void onTimedText(IMediaPlayer mp, IjkTimedText text) { if (text != null) { subtitleDisplay.setText(text.getText()); } } }; /** * Register a callback to be invoked when the media file * is loaded and ready to go. * * @param l The callback that will be run */ public void setOnPreparedListener(IMediaPlayer.OnPreparedListener l) { mOnPreparedListener = l; } /** * Register a callback to be invoked when the end of a media file * has been reached during playback. * * @param l The callback that will be run */ public void setOnCompletionListener(IMediaPlayer.OnCompletionListener l) { mOnCompletionListener = l; } /** * Register a callback to be invoked when an error occurs * during playback or setup. If no listener is specified, * or if the listener returned false, VideoView will inform * the user of any errors. * * @param l The callback that will be run */ public void setOnErrorListener(IMediaPlayer.OnErrorListener l) { mOnErrorListener = l; } /** * Register a callback to be invoked when an informational event * occurs during playback or setup. * * @param l The callback that will be run */ public void setOnInfoListener(IMediaPlayer.OnInfoListener l) { mOnInfoListener = l; } // REMOVED: mSHCallback private void bindSurfaceHolder(IMediaPlayer mp, IRenderView.ISurfaceHolder holder) { if (mp == null) return; if (holder == null) { mp.setDisplay(null); return; } holder.bindToMediaPlayer(mp); } IRenderView.IRenderCallback mSHCallback = new IRenderView.IRenderCallback() { @Override public void onSurfaceChanged(@NonNull IRenderView.ISurfaceHolder holder, int format, int w, int h) { if (holder.getRenderView() != mRenderView) { Log.e(TAG, "onSurfaceChanged: unmatched render callback\n"); return; } mSurfaceWidth = w; mSurfaceHeight = h; boolean isValidState = (mTargetState == STATE_PLAYING); boolean hasValidSize = !mRenderView.shouldWaitForResize() || (mVideoWidth == w && mVideoHeight == h); if (mMediaPlayer != null && isValidState && hasValidSize) { if (mSeekWhenPrepared != 0) { seekTo(mSeekWhenPrepared); } start(); } } @Override public void onSurfaceCreated(@NonNull IRenderView.ISurfaceHolder holder, int width, int height) { if (holder.getRenderView() != mRenderView) { Log.e(TAG, "onSurfaceCreated: unmatched render callback\n"); return; } mSurfaceHolder = holder; if (mMediaPlayer != null) bindSurfaceHolder(mMediaPlayer, holder); else openVideo(); } @Override public void onSurfaceDestroyed(@NonNull IRenderView.ISurfaceHolder holder) { if (holder.getRenderView() != mRenderView) { Log.e(TAG, "onSurfaceDestroyed: unmatched render callback\n"); return; } // after we return from this we can't use the surface any more mSurfaceHolder = null; // REMOVED: if (mMediaController != null) mMediaController.hide(); // REMOVED: release(true); releaseWithoutStop(); } }; public void releaseWithoutStop() { if (mMediaPlayer != null) mMediaPlayer.setDisplay(null); } /* * release the media player in any state */ public void release(boolean cleartargetstate) { if (mMediaPlayer != null) { mMediaPlayer.reset(); mMediaPlayer.release(); mMediaPlayer = null; // REMOVED: mPendingSubtitleTracks.clear(); mCurrentState = STATE_IDLE; if (cleartargetstate) { mTargetState = STATE_IDLE; } AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE); am.abandonAudioFocus(null); } } @Override public boolean onTouchEvent(MotionEvent ev) { if (isInPlaybackState() && mMediaController != null) { toggleMediaControlsVisiblity(); } return false; } @Override public boolean onTrackballEvent(MotionEvent ev) { if (isInPlaybackState() && mMediaController != null) { toggleMediaControlsVisiblity(); } return false; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK && keyCode != KeyEvent.KEYCODE_VOLUME_UP && keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE && keyCode != KeyEvent.KEYCODE_MENU && keyCode != KeyEvent.KEYCODE_CALL && keyCode != KeyEvent.KEYCODE_ENDCALL; if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) { if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) { if (mMediaPlayer.isPlaying()) { pause(); mMediaController.show(); } else { start(); mMediaController.hide(); } return true; } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) { if (!mMediaPlayer.isPlaying()) { start(); mMediaController.hide(); } return true; } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) { if (mMediaPlayer.isPlaying()) { pause(); mMediaController.show(); } return true; } else { toggleMediaControlsVisiblity(); } } return super.onKeyDown(keyCode, event); } private void toggleMediaControlsVisiblity() { if (mMediaController.isShowing()) { mMediaController.hide(); } else { mMediaController.show(); } } @Override public void start() { if (isInPlaybackState()) { mMediaPlayer.start(); mCurrentState = STATE_PLAYING; } mTargetState = STATE_PLAYING; } @Override public void pause() { if (isInPlaybackState()) { if (mMediaPlayer.isPlaying()) { mMediaPlayer.pause(); mCurrentState = STATE_PAUSED; } } mTargetState = STATE_PAUSED; } public void suspend() { release(false); } public void resume() { openVideo(); } @Override public int getDuration() { if (isInPlaybackState()) { return (int) mMediaPlayer.getDuration(); } return -1; } @Override public int getCurrentPosition() { if (isInPlaybackState()) { return (int) mMediaPlayer.getCurrentPosition(); } return 0; } @Override public void seekTo(int msec) { if (isInPlaybackState()) { mSeekStartTime = System.currentTimeMillis(); mMediaPlayer.seekTo(msec); mSeekWhenPrepared = 0; } else { mSeekWhenPrepared = msec; } } @Override public boolean isPlaying() { return isInPlaybackState() && mMediaPlayer.isPlaying(); } @Override public int getBufferPercentage() { if (mMediaPlayer != null) { return mCurrentBufferPercentage; } return 0; } private boolean isInPlaybackState() { return (mMediaPlayer != null && mCurrentState != STATE_ERROR && mCurrentState != STATE_IDLE && mCurrentState != STATE_PREPARING); } @Override public boolean canPause() { return mCanPause; } @Override public boolean canSeekBackward() { return mCanSeekBack; } @Override public boolean canSeekForward() { return mCanSeekForward; } @Override public int getAudioSessionId() { return 0; } // REMOVED: getAudioSessionId(); // REMOVED: onAttachedToWindow(); // REMOVED: onDetachedFromWindow(); // REMOVED: onLayout(); // REMOVED: draw(); // REMOVED: measureAndLayoutSubtitleWidget(); // REMOVED: setSubtitleWidget(); // REMOVED: getSubtitleLooper(); //------------------------- // Extend: Aspect Ratio //------------------------- private static final int[] s_allAspectRatio = { IRenderView.AR_ASPECT_FIT_PARENT, IRenderView.AR_ASPECT_FILL_PARENT, IRenderView.AR_ASPECT_WRAP_CONTENT, // IRenderView.AR_MATCH_PARENT, IRenderView.AR_16_9_FIT_PARENT, IRenderView.AR_4_3_FIT_PARENT}; private int mCurrentAspectRatioIndex = 0; private int mCurrentAspectRatio = s_allAspectRatio[0]; public int toggleAspectRatio() { mCurrentAspectRatioIndex++; mCurrentAspectRatioIndex %= s_allAspectRatio.length; mCurrentAspectRatio = s_allAspectRatio[mCurrentAspectRatioIndex]; if (mRenderView != null) mRenderView.setAspectRatio(mCurrentAspectRatio); return mCurrentAspectRatio; } //------------------------- // Extend: Render //------------------------- public static final int RENDER_NONE = 0; public static final int RENDER_SURFACE_VIEW = 1; public static final int RENDER_TEXTURE_VIEW = 2; private List mAllRenders = new ArrayList(); private int mCurrentRenderIndex = 0; private int mCurrentRender = RENDER_NONE; private void initRenders() { mAllRenders.clear(); if (mSettings.getEnableSurfaceView()) mAllRenders.add(RENDER_SURFACE_VIEW); if (mSettings.getEnableTextureView() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) mAllRenders.add(RENDER_TEXTURE_VIEW); if (mSettings.getEnableNoView()) mAllRenders.add(RENDER_NONE); if (mAllRenders.isEmpty()) mAllRenders.add(RENDER_SURFACE_VIEW); mCurrentRender = mAllRenders.get(mCurrentRenderIndex); setRender(mCurrentRender); } public int toggleRender() { mCurrentRenderIndex++; mCurrentRenderIndex %= mAllRenders.size(); mCurrentRender = mAllRenders.get(mCurrentRenderIndex); setRender(mCurrentRender); return mCurrentRender; } @NonNull public static String getRenderText(Context context, int render) { String text; switch (render) { case RENDER_NONE: text = context.getString(R.string.VideoView_render_none); break; case RENDER_SURFACE_VIEW: text = context.getString(R.string.VideoView_render_surface_view); break; case RENDER_TEXTURE_VIEW: text = context.getString(R.string.VideoView_render_texture_view); break; default: text = context.getString(R.string.N_A); break; } return text; } //------------------------- // Extend: Player //------------------------- public int togglePlayer() { if (mMediaPlayer != null) mMediaPlayer.release(); if (mRenderView != null) mRenderView.getView().invalidate(); openVideo(); return mSettings.getPlayer(); } @NonNull public static String getPlayerText(Context context, int player) { String text; switch (player) { case Settings.PV_PLAYER__AndroidMediaPlayer: text = context.getString(R.string.VideoView_player_AndroidMediaPlayer); break; case Settings.PV_PLAYER__IjkMediaPlayer: text = context.getString(R.string.VideoView_player_IjkMediaPlayer); break; case Settings.PV_PLAYER__IjkExoMediaPlayer: text = context.getString(R.string.VideoView_player_IjkExoMediaPlayer); break; default: text = context.getString(R.string.N_A); break; } return text; } public IMediaPlayer createPlayer(int playerType) { IMediaPlayer mediaPlayer = null; switch (playerType) { case Settings.PV_PLAYER__IjkExoMediaPlayer: { IjkExoMediaPlayer IjkExoMediaPlayer = new IjkExoMediaPlayer(mAppContext); mediaPlayer = IjkExoMediaPlayer; } break; case Settings.PV_PLAYER__AndroidMediaPlayer: { AndroidMediaPlayer androidMediaPlayer = new AndroidMediaPlayer(); mediaPlayer = androidMediaPlayer; } break; case Settings.PV_PLAYER__IjkMediaPlayer: default: { IjkMediaPlayer ijkMediaPlayer = null; if (mUri != null) { ijkMediaPlayer = new IjkMediaPlayer(); ijkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG); if (mManifestString != null) { ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "iformat", "ijklas"); ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "find_stream_info", 0); ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "manifest_string", mManifestString); } if (mSettings.getUsingMediaCodec()) { ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1); if (mSettings.getUsingMediaCodecAutoRotate()) { ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1); } else { ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 0); } if (mSettings.getMediaCodecHandleResolutionChange()) { ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 1); } else { ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 0); } } else { ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 0); } if (mSettings.getUsingOpenSLES()) { ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 1); } else { ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 0); } String pixelFormat = mSettings.getPixelFormat(); if (TextUtils.isEmpty(pixelFormat)) { ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32); } else { ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", pixelFormat); } ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1); ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0); ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "http-detect-range-support", 0); ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48); } mediaPlayer = ijkMediaPlayer; } break; } if (mSettings.getEnableDetachedSurfaceTextureView()) { mediaPlayer = new TextureMediaPlayer(mediaPlayer); } return mediaPlayer; } //------------------------- // Extend: Background //------------------------- private boolean mEnableBackgroundPlay = false; private void initBackground() { mEnableBackgroundPlay = mSettings.getEnableBackgroundPlay(); if (mEnableBackgroundPlay) { MediaPlayerService.intentToStart(getContext()); mMediaPlayer = MediaPlayerService.getMediaPlayer(); if (mHudViewHolder != null) mHudViewHolder.setMediaPlayer(mMediaPlayer); } } public boolean isBackgroundPlayEnabled() { return mEnableBackgroundPlay; } public void enterBackground() { MediaPlayerService.setMediaPlayer(mMediaPlayer); } public void stopBackgroundPlay() { MediaPlayerService.setMediaPlayer(null); } //------------------------- // Extend: Background //------------------------- public void showMediaInfo() { if (mMediaPlayer == null) return; int selectedVideoTrack = MediaPlayerCompat.getSelectedTrack(mMediaPlayer, ITrackInfo.MEDIA_TRACK_TYPE_VIDEO); int selectedAudioTrack = MediaPlayerCompat.getSelectedTrack(mMediaPlayer, ITrackInfo.MEDIA_TRACK_TYPE_AUDIO); int selectedSubtitleTrack = MediaPlayerCompat.getSelectedTrack(mMediaPlayer, ITrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT); TableLayoutBinder builder = new TableLayoutBinder(getContext()); builder.appendSection(R.string.mi_player); builder.appendRow2(R.string.mi_player, MediaPlayerCompat.getName(mMediaPlayer)); builder.appendSection(R.string.mi_media); builder.appendRow2(R.string.mi_resolution, buildResolution(mVideoWidth, mVideoHeight, mVideoSarNum, mVideoSarDen)); builder.appendRow2(R.string.mi_length, buildTimeMilli(mMediaPlayer.getDuration())); ITrackInfo trackInfos[] = mMediaPlayer.getTrackInfo(); if (trackInfos != null) { int index = -1; for (ITrackInfo trackInfo : trackInfos) { index++; int trackType = trackInfo.getTrackType(); if (index == selectedVideoTrack) { builder.appendSection(getContext().getString(R.string.mi_stream_fmt1, index) + " " + getContext().getString(R.string.mi__selected_video_track)); } else if (index == selectedAudioTrack) { builder.appendSection(getContext().getString(R.string.mi_stream_fmt1, index) + " " + getContext().getString(R.string.mi__selected_audio_track)); } else if (index == selectedSubtitleTrack) { builder.appendSection(getContext().getString(R.string.mi_stream_fmt1, index) + " " + getContext().getString(R.string.mi__selected_subtitle_track)); } else { builder.appendSection(getContext().getString(R.string.mi_stream_fmt1, index)); } builder.appendRow2(R.string.mi_type, buildTrackType(trackType)); builder.appendRow2(R.string.mi_language, buildLanguage(trackInfo.getLanguage())); IMediaFormat mediaFormat = trackInfo.getFormat(); if (mediaFormat == null) { } else if (mediaFormat instanceof IjkMediaFormat) { switch (trackType) { case ITrackInfo.MEDIA_TRACK_TYPE_VIDEO: builder.appendRow2(R.string.mi_codec, mediaFormat.getString(IjkMediaFormat.KEY_IJK_CODEC_LONG_NAME_UI)); builder.appendRow2(R.string.mi_profile_level, mediaFormat.getString(IjkMediaFormat.KEY_IJK_CODEC_PROFILE_LEVEL_UI)); builder.appendRow2(R.string.mi_pixel_format, mediaFormat.getString(IjkMediaFormat.KEY_IJK_CODEC_PIXEL_FORMAT_UI)); builder.appendRow2(R.string.mi_resolution, mediaFormat.getString(IjkMediaFormat.KEY_IJK_RESOLUTION_UI)); builder.appendRow2(R.string.mi_frame_rate, mediaFormat.getString(IjkMediaFormat.KEY_IJK_FRAME_RATE_UI)); builder.appendRow2(R.string.mi_bit_rate, mediaFormat.getString(IjkMediaFormat.KEY_IJK_BIT_RATE_UI)); break; case ITrackInfo.MEDIA_TRACK_TYPE_AUDIO: builder.appendRow2(R.string.mi_codec, mediaFormat.getString(IjkMediaFormat.KEY_IJK_CODEC_LONG_NAME_UI)); builder.appendRow2(R.string.mi_profile_level, mediaFormat.getString(IjkMediaFormat.KEY_IJK_CODEC_PROFILE_LEVEL_UI)); builder.appendRow2(R.string.mi_sample_rate, mediaFormat.getString(IjkMediaFormat.KEY_IJK_SAMPLE_RATE_UI)); builder.appendRow2(R.string.mi_channels, mediaFormat.getString(IjkMediaFormat.KEY_IJK_CHANNEL_UI)); builder.appendRow2(R.string.mi_bit_rate, mediaFormat.getString(IjkMediaFormat.KEY_IJK_BIT_RATE_UI)); break; default: break; } } } } AlertDialog.Builder adBuilder = builder.buildAlertDialogBuilder(); adBuilder.setTitle(R.string.media_information); adBuilder.setNegativeButton(R.string.close, null); adBuilder.show(); } private String buildResolution(int width, int height, int sarNum, int sarDen) { StringBuilder sb = new StringBuilder(); sb.append(width); sb.append(" x "); sb.append(height); if (sarNum > 1 || sarDen > 1) { sb.append("["); sb.append(sarNum); sb.append(":"); sb.append(sarDen); sb.append("]"); } return sb.toString(); } private String buildTimeMilli(long duration) { long total_seconds = duration / 1000; long hours = total_seconds / 3600; long minutes = (total_seconds % 3600) / 60; long seconds = total_seconds % 60; if (duration <= 0) { return "--:--"; } if (hours >= 100) { return String.format(Locale.US, "%d:%02d:%02d", hours, minutes, seconds); } else if (hours > 0) { return String.format(Locale.US, "%02d:%02d:%02d", hours, minutes, seconds); } else { return String.format(Locale.US, "%02d:%02d", minutes, seconds); } } private String buildTrackType(int type) { Context context = getContext(); switch (type) { case ITrackInfo.MEDIA_TRACK_TYPE_VIDEO: return context.getString(R.string.TrackType_video); case ITrackInfo.MEDIA_TRACK_TYPE_AUDIO: return context.getString(R.string.TrackType_audio); case ITrackInfo.MEDIA_TRACK_TYPE_SUBTITLE: return context.getString(R.string.TrackType_subtitle); case ITrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT: return context.getString(R.string.TrackType_timedtext); case ITrackInfo.MEDIA_TRACK_TYPE_METADATA: return context.getString(R.string.TrackType_metadata); case ITrackInfo.MEDIA_TRACK_TYPE_UNKNOWN: default: return context.getString(R.string.TrackType_unknown); } } private String buildLanguage(String language) { if (TextUtils.isEmpty(language)) return "und"; return language; } public ITrackInfo[] getTrackInfo() { if (mMediaPlayer == null) return null; return mMediaPlayer.getTrackInfo(); } public void selectTrack(int stream) { MediaPlayerCompat.selectTrack(mMediaPlayer, stream); } public void deselectTrack(int stream) { MediaPlayerCompat.deselectTrack(mMediaPlayer, stream); } public int getSelectedTrack(int trackType) { return MediaPlayerCompat.getSelectedTrack(mMediaPlayer, trackType); } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/InfoHudViewHolder.java ================================================ package tv.danmaku.ijk.media.example.widget.media; import android.content.Context; import android.os.Handler; import android.os.Message; import android.util.SparseArray; import android.view.View; import android.widget.TableLayout; import java.util.Locale; import tv.danmaku.ijk.media.player.IMediaPlayer; import tv.danmaku.ijk.media.player.IjkMediaPlayer; import tv.danmaku.ijk.media.player.MediaPlayerProxy; import tv.danmaku.ijk.media.example.R; public class InfoHudViewHolder { private TableLayoutBinder mTableLayoutBinder; private SparseArray mRowMap = new SparseArray(); private IMediaPlayer mMediaPlayer; private long mLoadCost = 0; private long mSeekCost = 0; public InfoHudViewHolder(Context context, TableLayout tableLayout) { mTableLayoutBinder = new TableLayoutBinder(context, tableLayout); } private void appendSection(int nameId) { mTableLayoutBinder.appendSection(nameId); } private void appendRow(int nameId) { View rowView = mTableLayoutBinder.appendRow2(nameId, null); mRowMap.put(nameId, rowView); } private void setRowValue(int id, String value) { View rowView = mRowMap.get(id); if (rowView == null) { rowView = mTableLayoutBinder.appendRow2(id, value); mRowMap.put(id, rowView); } else { mTableLayoutBinder.setValueText(rowView, value); } } public void setMediaPlayer(IMediaPlayer mp) { mMediaPlayer = mp; if (mMediaPlayer != null) { mHandler.sendEmptyMessageDelayed(MSG_UPDATE_HUD, 500); } else { mHandler.removeMessages(MSG_UPDATE_HUD); } } private static String formatedDurationMilli(long duration) { if (duration >= 1000) { return String.format(Locale.US, "%.2f sec", ((float)duration) / 1000); } else { return String.format(Locale.US, "%d msec", duration); } } private static String formatedSpeed(long bytes,long elapsed_milli) { if (elapsed_milli <= 0) { return "0 B/s"; } if (bytes <= 0) { return "0 B/s"; } float bytes_per_sec = ((float)bytes) * 1000.f / elapsed_milli; if (bytes_per_sec >= 1000 * 1000) { return String.format(Locale.US, "%.2f MB/s", ((float)bytes_per_sec) / 1000 / 1000); } else if (bytes_per_sec >= 1000) { return String.format(Locale.US, "%.1f KB/s", ((float)bytes_per_sec) / 1000); } else { return String.format(Locale.US, "%d B/s", (long)bytes_per_sec); } } public void updateLoadCost(long time) { mLoadCost = time; } public void updateSeekCost(long time) { mSeekCost = time; } private static String formatedSize(long bytes) { if (bytes >= 100 * 1000) { return String.format(Locale.US, "%.2f MB", ((float)bytes) / 1000 / 1000); } else if (bytes >= 100) { return String.format(Locale.US, "%.1f KB", ((float)bytes) / 1000); } else { return String.format(Locale.US, "%d B", bytes); } } private static final int MSG_UPDATE_HUD = 1; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_UPDATE_HUD: { InfoHudViewHolder holder = InfoHudViewHolder.this; IjkMediaPlayer mp = null; if (mMediaPlayer == null) break; if (mMediaPlayer instanceof IjkMediaPlayer) { mp = (IjkMediaPlayer) mMediaPlayer; } else if (mMediaPlayer instanceof MediaPlayerProxy) { MediaPlayerProxy proxy = (MediaPlayerProxy) mMediaPlayer; IMediaPlayer internal = proxy.getInternalMediaPlayer(); if (internal != null && internal instanceof IjkMediaPlayer) mp = (IjkMediaPlayer) internal; } if (mp == null) break; int vdec = mp.getVideoDecoder(); switch (vdec) { case IjkMediaPlayer.FFP_PROPV_DECODER_AVCODEC: setRowValue(R.string.vdec, "avcodec"); break; case IjkMediaPlayer.FFP_PROPV_DECODER_MEDIACODEC: setRowValue(R.string.vdec, "MediaCodec"); break; default: setRowValue(R.string.vdec, ""); break; } float fpsOutput = mp.getVideoOutputFramesPerSecond(); float fpsDecode = mp.getVideoDecodeFramesPerSecond(); setRowValue(R.string.fps, String.format(Locale.US, "%.2f / %.2f", fpsDecode, fpsOutput)); long videoCachedDuration = mp.getVideoCachedDuration(); long audioCachedDuration = mp.getAudioCachedDuration(); long videoCachedBytes = mp.getVideoCachedBytes(); long audioCachedBytes = mp.getAudioCachedBytes(); long tcpSpeed = mp.getTcpSpeed(); long bitRate = mp.getBitRate(); long seekLoadDuration = mp.getSeekLoadDuration(); setRowValue(R.string.v_cache, String.format(Locale.US, "%s, %s", formatedDurationMilli(videoCachedDuration), formatedSize(videoCachedBytes))); setRowValue(R.string.a_cache, String.format(Locale.US, "%s, %s", formatedDurationMilli(audioCachedDuration), formatedSize(audioCachedBytes))); setRowValue(R.string.load_cost, String.format(Locale.US, "%d ms", mLoadCost)); setRowValue(R.string.seek_cost, String.format(Locale.US, "%d ms", mSeekCost)); setRowValue(R.string.seek_load_cost, String.format(Locale.US, "%d ms", seekLoadDuration)); setRowValue(R.string.tcp_speed, String.format(Locale.US, "%s", formatedSpeed(tcpSpeed, 1000))); setRowValue(R.string.bit_rate, String.format(Locale.US, "%.2f kbs", bitRate/1000f)); mHandler.removeMessages(MSG_UPDATE_HUD); mHandler.sendEmptyMessageDelayed(MSG_UPDATE_HUD, 500); } } } }; } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/MeasureHelper.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.widget.media; import android.content.Context; import android.support.annotation.NonNull; import android.view.View; import java.lang.ref.WeakReference; import tv.danmaku.ijk.media.example.R; public final class MeasureHelper { private WeakReference mWeakView; private int mVideoWidth; private int mVideoHeight; private int mVideoSarNum; private int mVideoSarDen; private int mVideoRotationDegree; private int mMeasuredWidth; private int mMeasuredHeight; private int mCurrentAspectRatio = IRenderView.AR_ASPECT_FIT_PARENT; public MeasureHelper(View view) { mWeakView = new WeakReference(view); } public View getView() { if (mWeakView == null) return null; return mWeakView.get(); } public void setVideoSize(int videoWidth, int videoHeight) { mVideoWidth = videoWidth; mVideoHeight = videoHeight; } public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) { mVideoSarNum = videoSarNum; mVideoSarDen = videoSarDen; } public void setVideoRotation(int videoRotationDegree) { mVideoRotationDegree = videoRotationDegree; } /** * Must be called by View.onMeasure(int, int) * * @param widthMeasureSpec * @param heightMeasureSpec */ public void doMeasure(int widthMeasureSpec, int heightMeasureSpec) { //Log.i("@@@@", "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", " // + MeasureSpec.toString(heightMeasureSpec) + ")"); if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) { int tempSpec = widthMeasureSpec; widthMeasureSpec = heightMeasureSpec; heightMeasureSpec = tempSpec; } int width = View.getDefaultSize(mVideoWidth, widthMeasureSpec); int height = View.getDefaultSize(mVideoHeight, heightMeasureSpec); if (mCurrentAspectRatio == IRenderView.AR_MATCH_PARENT) { width = widthMeasureSpec; height = heightMeasureSpec; } else if (mVideoWidth > 0 && mVideoHeight > 0) { int widthSpecMode = View.MeasureSpec.getMode(widthMeasureSpec); int widthSpecSize = View.MeasureSpec.getSize(widthMeasureSpec); int heightSpecMode = View.MeasureSpec.getMode(heightMeasureSpec); int heightSpecSize = View.MeasureSpec.getSize(heightMeasureSpec); if (widthSpecMode == View.MeasureSpec.AT_MOST && heightSpecMode == View.MeasureSpec.AT_MOST) { float specAspectRatio = (float) widthSpecSize / (float) heightSpecSize; float displayAspectRatio; switch (mCurrentAspectRatio) { case IRenderView.AR_16_9_FIT_PARENT: displayAspectRatio = 16.0f / 9.0f; if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) displayAspectRatio = 1.0f / displayAspectRatio; break; case IRenderView.AR_4_3_FIT_PARENT: displayAspectRatio = 4.0f / 3.0f; if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) displayAspectRatio = 1.0f / displayAspectRatio; break; case IRenderView.AR_ASPECT_FIT_PARENT: case IRenderView.AR_ASPECT_FILL_PARENT: case IRenderView.AR_ASPECT_WRAP_CONTENT: default: displayAspectRatio = (float) mVideoWidth / (float) mVideoHeight; if (mVideoSarNum > 0 && mVideoSarDen > 0) displayAspectRatio = displayAspectRatio * mVideoSarNum / mVideoSarDen; break; } boolean shouldBeWider = displayAspectRatio > specAspectRatio; switch (mCurrentAspectRatio) { case IRenderView.AR_ASPECT_FIT_PARENT: case IRenderView.AR_16_9_FIT_PARENT: case IRenderView.AR_4_3_FIT_PARENT: if (shouldBeWider) { // too wide, fix width width = widthSpecSize; height = (int) (width / displayAspectRatio); } else { // too high, fix height height = heightSpecSize; width = (int) (height * displayAspectRatio); } break; case IRenderView.AR_ASPECT_FILL_PARENT: if (shouldBeWider) { // not high enough, fix height height = heightSpecSize; width = (int) (height * displayAspectRatio); } else { // not wide enough, fix width width = widthSpecSize; height = (int) (width / displayAspectRatio); } break; case IRenderView.AR_ASPECT_WRAP_CONTENT: default: if (shouldBeWider) { // too wide, fix width width = Math.min(mVideoWidth, widthSpecSize); height = (int) (width / displayAspectRatio); } else { // too high, fix height height = Math.min(mVideoHeight, heightSpecSize); width = (int) (height * displayAspectRatio); } break; } } else if (widthSpecMode == View.MeasureSpec.EXACTLY && heightSpecMode == View.MeasureSpec.EXACTLY) { // the size is fixed width = widthSpecSize; height = heightSpecSize; // for compatibility, we adjust size based on aspect ratio if (mVideoWidth * height < width * mVideoHeight) { //Log.i("@@@", "image too wide, correcting"); width = height * mVideoWidth / mVideoHeight; } else if (mVideoWidth * height > width * mVideoHeight) { //Log.i("@@@", "image too tall, correcting"); height = width * mVideoHeight / mVideoWidth; } } else if (widthSpecMode == View.MeasureSpec.EXACTLY) { // only the width is fixed, adjust the height to match aspect ratio if possible width = widthSpecSize; height = width * mVideoHeight / mVideoWidth; if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) { // couldn't match aspect ratio within the constraints height = heightSpecSize; } } else if (heightSpecMode == View.MeasureSpec.EXACTLY) { // only the height is fixed, adjust the width to match aspect ratio if possible height = heightSpecSize; width = height * mVideoWidth / mVideoHeight; if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) { // couldn't match aspect ratio within the constraints width = widthSpecSize; } } else { // neither the width nor the height are fixed, try to use actual video size width = mVideoWidth; height = mVideoHeight; if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) { // too tall, decrease both width and height height = heightSpecSize; width = height * mVideoWidth / mVideoHeight; } if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) { // too wide, decrease both width and height width = widthSpecSize; height = width * mVideoHeight / mVideoWidth; } } } else { // no size yet, just adopt the given spec sizes } mMeasuredWidth = width; mMeasuredHeight = height; } public int getMeasuredWidth() { return mMeasuredWidth; } public int getMeasuredHeight() { return mMeasuredHeight; } public void setAspectRatio(int aspectRatio) { mCurrentAspectRatio = aspectRatio; } @NonNull public static String getAspectRatioText(Context context, int aspectRatio) { String text; switch (aspectRatio) { case IRenderView.AR_ASPECT_FIT_PARENT: text = context.getString(R.string.VideoView_ar_aspect_fit_parent); break; case IRenderView.AR_ASPECT_FILL_PARENT: text = context.getString(R.string.VideoView_ar_aspect_fill_parent); break; case IRenderView.AR_ASPECT_WRAP_CONTENT: text = context.getString(R.string.VideoView_ar_aspect_wrap_content); break; case IRenderView.AR_MATCH_PARENT: text = context.getString(R.string.VideoView_ar_match_parent); break; case IRenderView.AR_16_9_FIT_PARENT: text = context.getString(R.string.VideoView_ar_16_9_fit_parent); break; case IRenderView.AR_4_3_FIT_PARENT: text = context.getString(R.string.VideoView_ar_4_3_fit_parent); break; default: text = context.getString(R.string.N_A); break; } return text; } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/MediaPlayerCompat.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.widget.media; import tv.danmaku.ijk.media.player.IMediaPlayer; import tv.danmaku.ijk.media.player.IjkMediaPlayer; import tv.danmaku.ijk.media.player.MediaPlayerProxy; import tv.danmaku.ijk.media.player.TextureMediaPlayer; public class MediaPlayerCompat { public static String getName(IMediaPlayer mp) { if (mp == null) { return "null"; } else if (mp instanceof TextureMediaPlayer) { StringBuilder sb = new StringBuilder("TextureMediaPlayer <"); IMediaPlayer internalMediaPlayer = ((TextureMediaPlayer) mp).getInternalMediaPlayer(); if (internalMediaPlayer == null) { sb.append("null>"); } else { sb.append(internalMediaPlayer.getClass().getSimpleName()); sb.append(">"); } return sb.toString(); } else { return mp.getClass().getSimpleName(); } } public static IjkMediaPlayer getIjkMediaPlayer(IMediaPlayer mp) { IjkMediaPlayer ijkMediaPlayer = null; if (mp == null) { return null; } if (mp instanceof IjkMediaPlayer) { ijkMediaPlayer = (IjkMediaPlayer) mp; } else if (mp instanceof MediaPlayerProxy && ((MediaPlayerProxy) mp).getInternalMediaPlayer() instanceof IjkMediaPlayer) { ijkMediaPlayer = (IjkMediaPlayer) ((MediaPlayerProxy) mp).getInternalMediaPlayer(); } return ijkMediaPlayer; } public static void selectTrack(IMediaPlayer mp, int stream) { IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp); if (ijkMediaPlayer == null) return; ijkMediaPlayer.selectTrack(stream); } public static void deselectTrack(IMediaPlayer mp, int stream) { IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp); if (ijkMediaPlayer == null) return; ijkMediaPlayer.deselectTrack(stream); } public static int getSelectedTrack(IMediaPlayer mp, int trackType) { IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp); if (ijkMediaPlayer == null) return -1; return ijkMediaPlayer.getSelectedTrack(trackType); } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/SurfaceRenderView.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.widget.media; import android.annotation.TargetApi; import android.content.Context; import android.graphics.SurfaceTexture; import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.util.Log; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import java.lang.ref.WeakReference; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import tv.danmaku.ijk.media.player.IMediaPlayer; import tv.danmaku.ijk.media.player.ISurfaceTextureHolder; public class SurfaceRenderView extends SurfaceView implements IRenderView { private MeasureHelper mMeasureHelper; public SurfaceRenderView(Context context) { super(context); initView(context); } public SurfaceRenderView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public SurfaceRenderView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public SurfaceRenderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); initView(context); } private void initView(Context context) { mMeasureHelper = new MeasureHelper(this); mSurfaceCallback = new SurfaceCallback(this); getHolder().addCallback(mSurfaceCallback); //noinspection deprecation getHolder().setType(SurfaceHolder.SURFACE_TYPE_NORMAL); } @Override public View getView() { return this; } @Override public boolean shouldWaitForResize() { return true; } //-------------------- // Layout & Measure //-------------------- @Override public void setVideoSize(int videoWidth, int videoHeight) { if (videoWidth > 0 && videoHeight > 0) { mMeasureHelper.setVideoSize(videoWidth, videoHeight); getHolder().setFixedSize(videoWidth, videoHeight); requestLayout(); } } @Override public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) { if (videoSarNum > 0 && videoSarDen > 0) { mMeasureHelper.setVideoSampleAspectRatio(videoSarNum, videoSarDen); requestLayout(); } } @Override public void setVideoRotation(int degree) { Log.e("", "SurfaceView doesn't support rotation (" + degree + ")!\n"); } @Override public void setAspectRatio(int aspectRatio) { mMeasureHelper.setAspectRatio(aspectRatio); requestLayout(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(mMeasureHelper.getMeasuredWidth(), mMeasureHelper.getMeasuredHeight()); } //-------------------- // SurfaceViewHolder //-------------------- private static final class InternalSurfaceHolder implements IRenderView.ISurfaceHolder { private SurfaceRenderView mSurfaceView; private SurfaceHolder mSurfaceHolder; public InternalSurfaceHolder(@NonNull SurfaceRenderView surfaceView, @Nullable SurfaceHolder surfaceHolder) { mSurfaceView = surfaceView; mSurfaceHolder = surfaceHolder; } public void bindToMediaPlayer(IMediaPlayer mp) { if (mp != null) { if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) && (mp instanceof ISurfaceTextureHolder)) { ISurfaceTextureHolder textureHolder = (ISurfaceTextureHolder) mp; textureHolder.setSurfaceTexture(null); } mp.setDisplay(mSurfaceHolder); } } @NonNull @Override public IRenderView getRenderView() { return mSurfaceView; } @Nullable @Override public SurfaceHolder getSurfaceHolder() { return mSurfaceHolder; } @Nullable @Override public SurfaceTexture getSurfaceTexture() { return null; } @Nullable @Override public Surface openSurface() { if (mSurfaceHolder == null) return null; return mSurfaceHolder.getSurface(); } } //------------------------- // SurfaceHolder.Callback //------------------------- @Override public void addRenderCallback(IRenderCallback callback) { mSurfaceCallback.addRenderCallback(callback); } @Override public void removeRenderCallback(IRenderCallback callback) { mSurfaceCallback.removeRenderCallback(callback); } private SurfaceCallback mSurfaceCallback; private static final class SurfaceCallback implements SurfaceHolder.Callback { private SurfaceHolder mSurfaceHolder; private boolean mIsFormatChanged; private int mFormat; private int mWidth; private int mHeight; private WeakReference mWeakSurfaceView; private Map mRenderCallbackMap = new ConcurrentHashMap(); public SurfaceCallback(@NonNull SurfaceRenderView surfaceView) { mWeakSurfaceView = new WeakReference(surfaceView); } public void addRenderCallback(@NonNull IRenderCallback callback) { mRenderCallbackMap.put(callback, callback); ISurfaceHolder surfaceHolder = null; if (mSurfaceHolder != null) { if (surfaceHolder == null) surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder); callback.onSurfaceCreated(surfaceHolder, mWidth, mHeight); } if (mIsFormatChanged) { if (surfaceHolder == null) surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder); callback.onSurfaceChanged(surfaceHolder, mFormat, mWidth, mHeight); } } public void removeRenderCallback(@NonNull IRenderCallback callback) { mRenderCallbackMap.remove(callback); } @Override public void surfaceCreated(SurfaceHolder holder) { mSurfaceHolder = holder; mIsFormatChanged = false; mFormat = 0; mWidth = 0; mHeight = 0; ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder); for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) { renderCallback.onSurfaceCreated(surfaceHolder, 0, 0); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { mSurfaceHolder = null; mIsFormatChanged = false; mFormat = 0; mWidth = 0; mHeight = 0; ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder); for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) { renderCallback.onSurfaceDestroyed(surfaceHolder); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { mSurfaceHolder = holder; mIsFormatChanged = true; mFormat = format; mWidth = width; mHeight = height; // mMeasureHelper.setVideoSize(width, height); ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder); for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) { renderCallback.onSurfaceChanged(surfaceHolder, format, width, height); } } } //-------------------- // Accessibility //-------------------- @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); event.setClassName(SurfaceRenderView.class.getName()); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { info.setClassName(SurfaceRenderView.class.getName()); } } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/TableLayoutBinder.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.widget.media; import android.content.Context; import android.support.v7.app.AlertDialog; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TableLayout; import android.widget.TextView; import tv.danmaku.ijk.media.example.R; public class TableLayoutBinder { private Context mContext; public ViewGroup mTableView; public TableLayout mTableLayout; public TableLayoutBinder(Context context) { this(context, R.layout.table_media_info); } public TableLayoutBinder(Context context, int layoutResourceId) { mContext = context; mTableView = (ViewGroup) LayoutInflater.from(mContext).inflate(layoutResourceId, null); mTableLayout = (TableLayout) mTableView.findViewById(R.id.table); } public TableLayoutBinder(Context context, TableLayout tableLayout) { mContext = context; mTableView = tableLayout; mTableLayout = tableLayout; } public View appendRow1(String name, String value) { return appendRow(R.layout.table_media_info_row1, name, value); } public View appendRow1(int nameId, String value) { return appendRow1(mContext.getString(nameId), value); } public View appendRow2(String name, String value) { return appendRow(R.layout.table_media_info_row2, name, value); } public View appendRow2(int nameId, String value) { return appendRow2(mContext.getString(nameId), value); } public View appendSection(String name) { return appendRow(R.layout.table_media_info_section, name, null); } public View appendSection(int nameId) { return appendSection(mContext.getString(nameId)); } public View appendRow(int layoutId, String name, String value) { ViewGroup rowView = (ViewGroup) LayoutInflater.from(mContext).inflate(layoutId, mTableLayout, false); setNameValueText(rowView, name, value); mTableLayout.addView(rowView); return rowView; } public ViewHolder obtainViewHolder(View rowView) { ViewHolder viewHolder = (ViewHolder) rowView.getTag(); if (viewHolder == null) { viewHolder = new ViewHolder(); viewHolder.mNameTextView = (TextView) rowView.findViewById(R.id.name); viewHolder.mValueTextView = (TextView) rowView.findViewById(R.id.value); rowView.setTag(viewHolder); } return viewHolder; } public void setNameValueText(View rowView, String name, String value) { ViewHolder viewHolder = obtainViewHolder(rowView); viewHolder.setName(name); viewHolder.setValue(value); } public void setValueText(View rowView, String value) { ViewHolder viewHolder = obtainViewHolder(rowView); viewHolder.setValue(value); } public ViewGroup buildLayout() { return mTableView; } public AlertDialog.Builder buildAlertDialogBuilder() { AlertDialog.Builder dlgBuilder = new AlertDialog.Builder(mContext); dlgBuilder.setView(buildLayout()); return dlgBuilder; } private static class ViewHolder { public TextView mNameTextView; public TextView mValueTextView; public void setName(String name) { if (mNameTextView != null) { mNameTextView.setText(name); } } public void setValue(String value) { if (mValueTextView != null) { mValueTextView.setText(value); } } } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/media/TextureRenderView.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.widget.media; import android.annotation.TargetApi; import android.content.Context; import android.graphics.SurfaceTexture; import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.util.Log; import android.view.Surface; import android.view.SurfaceHolder; import android.view.TextureView; import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import java.lang.ref.WeakReference; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import tv.danmaku.ijk.media.player.IMediaPlayer; import tv.danmaku.ijk.media.player.ISurfaceTextureHolder; import tv.danmaku.ijk.media.player.ISurfaceTextureHost; @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public class TextureRenderView extends TextureView implements IRenderView { private static final String TAG = "TextureRenderView"; private MeasureHelper mMeasureHelper; public TextureRenderView(Context context) { super(context); initView(context); } public TextureRenderView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public TextureRenderView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public TextureRenderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); initView(context); } private void initView(Context context) { mMeasureHelper = new MeasureHelper(this); mSurfaceCallback = new SurfaceCallback(this); setSurfaceTextureListener(mSurfaceCallback); } @Override public View getView() { return this; } @Override public boolean shouldWaitForResize() { return false; } @Override protected void onDetachedFromWindow() { mSurfaceCallback.willDetachFromWindow(); super.onDetachedFromWindow(); mSurfaceCallback.didDetachFromWindow(); } //-------------------- // Layout & Measure //-------------------- @Override public void setVideoSize(int videoWidth, int videoHeight) { if (videoWidth > 0 && videoHeight > 0) { mMeasureHelper.setVideoSize(videoWidth, videoHeight); requestLayout(); } } @Override public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) { if (videoSarNum > 0 && videoSarDen > 0) { mMeasureHelper.setVideoSampleAspectRatio(videoSarNum, videoSarDen); requestLayout(); } } @Override public void setVideoRotation(int degree) { mMeasureHelper.setVideoRotation(degree); setRotation(degree); } @Override public void setAspectRatio(int aspectRatio) { mMeasureHelper.setAspectRatio(aspectRatio); requestLayout(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(mMeasureHelper.getMeasuredWidth(), mMeasureHelper.getMeasuredHeight()); } //-------------------- // TextureViewHolder //-------------------- public IRenderView.ISurfaceHolder getSurfaceHolder() { return new InternalSurfaceHolder(this, mSurfaceCallback.mSurfaceTexture, mSurfaceCallback); } private static final class InternalSurfaceHolder implements IRenderView.ISurfaceHolder { private TextureRenderView mTextureView; private SurfaceTexture mSurfaceTexture; private ISurfaceTextureHost mSurfaceTextureHost; public InternalSurfaceHolder(@NonNull TextureRenderView textureView, @Nullable SurfaceTexture surfaceTexture, @NonNull ISurfaceTextureHost surfaceTextureHost) { mTextureView = textureView; mSurfaceTexture = surfaceTexture; mSurfaceTextureHost = surfaceTextureHost; } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public void bindToMediaPlayer(IMediaPlayer mp) { if (mp == null) return; if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) && (mp instanceof ISurfaceTextureHolder)) { ISurfaceTextureHolder textureHolder = (ISurfaceTextureHolder) mp; mTextureView.mSurfaceCallback.setOwnSurfaceTexture(false); SurfaceTexture surfaceTexture = textureHolder.getSurfaceTexture(); if (surfaceTexture != null) { mTextureView.setSurfaceTexture(surfaceTexture); } else { textureHolder.setSurfaceTexture(mSurfaceTexture); textureHolder.setSurfaceTextureHost(mTextureView.mSurfaceCallback); } } else { mp.setSurface(openSurface()); } } @NonNull @Override public IRenderView getRenderView() { return mTextureView; } @Nullable @Override public SurfaceHolder getSurfaceHolder() { return null; } @Nullable @Override public SurfaceTexture getSurfaceTexture() { return mSurfaceTexture; } @Nullable @Override public Surface openSurface() { if (mSurfaceTexture == null) return null; return new Surface(mSurfaceTexture); } } //------------------------- // SurfaceHolder.Callback //------------------------- @Override public void addRenderCallback(IRenderCallback callback) { mSurfaceCallback.addRenderCallback(callback); } @Override public void removeRenderCallback(IRenderCallback callback) { mSurfaceCallback.removeRenderCallback(callback); } private SurfaceCallback mSurfaceCallback; private static final class SurfaceCallback implements TextureView.SurfaceTextureListener, ISurfaceTextureHost { private SurfaceTexture mSurfaceTexture; private boolean mIsFormatChanged; private int mWidth; private int mHeight; private boolean mOwnSurfaceTexture = true; private boolean mWillDetachFromWindow = false; private boolean mDidDetachFromWindow = false; private WeakReference mWeakRenderView; private Map mRenderCallbackMap = new ConcurrentHashMap(); public SurfaceCallback(@NonNull TextureRenderView renderView) { mWeakRenderView = new WeakReference(renderView); } public void setOwnSurfaceTexture(boolean ownSurfaceTexture) { mOwnSurfaceTexture = ownSurfaceTexture; } public void addRenderCallback(@NonNull IRenderCallback callback) { mRenderCallbackMap.put(callback, callback); ISurfaceHolder surfaceHolder = null; if (mSurfaceTexture != null) { if (surfaceHolder == null) surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), mSurfaceTexture, this); callback.onSurfaceCreated(surfaceHolder, mWidth, mHeight); } if (mIsFormatChanged) { if (surfaceHolder == null) surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), mSurfaceTexture, this); callback.onSurfaceChanged(surfaceHolder, 0, mWidth, mHeight); } } public void removeRenderCallback(@NonNull IRenderCallback callback) { mRenderCallbackMap.remove(callback); } @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { mSurfaceTexture = surface; mIsFormatChanged = false; mWidth = 0; mHeight = 0; ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), surface, this); for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) { renderCallback.onSurfaceCreated(surfaceHolder, 0, 0); } } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { mSurfaceTexture = surface; mIsFormatChanged = true; mWidth = width; mHeight = height; ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), surface, this); for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) { renderCallback.onSurfaceChanged(surfaceHolder, 0, width, height); } } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { mSurfaceTexture = surface; mIsFormatChanged = false; mWidth = 0; mHeight = 0; ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), surface, this); for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) { renderCallback.onSurfaceDestroyed(surfaceHolder); } Log.d(TAG, "onSurfaceTextureDestroyed: destroy: " + mOwnSurfaceTexture); return mOwnSurfaceTexture; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { } //------------------------- // ISurfaceTextureHost //------------------------- @Override public void releaseSurfaceTexture(SurfaceTexture surfaceTexture) { if (surfaceTexture == null) { Log.d(TAG, "releaseSurfaceTexture: null"); } else if (mDidDetachFromWindow) { if (surfaceTexture != mSurfaceTexture) { Log.d(TAG, "releaseSurfaceTexture: didDetachFromWindow(): release different SurfaceTexture"); surfaceTexture.release(); } else if (!mOwnSurfaceTexture) { Log.d(TAG, "releaseSurfaceTexture: didDetachFromWindow(): release detached SurfaceTexture"); surfaceTexture.release(); } else { Log.d(TAG, "releaseSurfaceTexture: didDetachFromWindow(): already released by TextureView"); } } else if (mWillDetachFromWindow) { if (surfaceTexture != mSurfaceTexture) { Log.d(TAG, "releaseSurfaceTexture: willDetachFromWindow(): release different SurfaceTexture"); surfaceTexture.release(); } else if (!mOwnSurfaceTexture) { Log.d(TAG, "releaseSurfaceTexture: willDetachFromWindow(): re-attach SurfaceTexture to TextureView"); setOwnSurfaceTexture(true); } else { Log.d(TAG, "releaseSurfaceTexture: willDetachFromWindow(): will released by TextureView"); } } else { if (surfaceTexture != mSurfaceTexture) { Log.d(TAG, "releaseSurfaceTexture: alive: release different SurfaceTexture"); surfaceTexture.release(); } else if (!mOwnSurfaceTexture) { Log.d(TAG, "releaseSurfaceTexture: alive: re-attach SurfaceTexture to TextureView"); setOwnSurfaceTexture(true); } else { Log.d(TAG, "releaseSurfaceTexture: alive: will released by TextureView"); } } } public void willDetachFromWindow() { Log.d(TAG, "willDetachFromWindow()"); mWillDetachFromWindow = true; } public void didDetachFromWindow() { Log.d(TAG, "didDetachFromWindow()"); mDidDetachFromWindow = true; } } //-------------------- // Accessibility //-------------------- @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); event.setClassName(TextureRenderView.class.getName()); } @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); info.setClassName(TextureRenderView.class.getName()); } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/java/tv/danmaku/ijk/media/example/widget/preference/IjkListPreference.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.example.widget.preference; import android.content.Context; import android.content.res.TypedArray; import android.support.v7.preference.ListPreference; import android.text.TextUtils; import android.util.AttributeSet; import tv.danmaku.ijk.media.example.R; public class IjkListPreference extends ListPreference { private CharSequence[] mEntrySummaries; public IjkListPreference(Context context) { super(context); initPreference(context, null); } public IjkListPreference(Context context, AttributeSet attrs) { super(context, attrs); initPreference(context, attrs); } public IjkListPreference(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPreference(context, attrs); } public IjkListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); initPreference(context, attrs); } private void initPreference(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.IjkListPreference, 0, 0); if (a == null) return; mEntrySummaries = a .getTextArray(R.styleable.IjkListPreference_entrySummaries); a.recycle(); } @Override protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { super.onSetInitialValue(restoreValue, defaultValue); syncSummary(); } @Override public void setValue(String value) { super.setValue(value); syncSummary(); } @Override public void setValueIndex(int index) { super.setValueIndex(index); syncSummary(); } public int getEntryIndex() { CharSequence[] entryValues = getEntryValues(); CharSequence value = getValue(); if (entryValues == null || value == null) { return -1; } for (int i = 0; i < entryValues.length; ++i) { if (TextUtils.equals(value, entryValues[i])) { return i; } } return -1; } // ----- summary -------------------- public void setEntrySummaries(Context context, int resId) { setEntrySummaries(context.getResources().getTextArray(resId)); } public void setEntrySummaries(CharSequence[] entrySummaries) { mEntrySummaries = entrySummaries; notifyChanged(); } public CharSequence[] getEntrySummaries() { return mEntrySummaries; } private void syncSummary() { int index = getEntryIndex(); if (index < 0) return; if (mEntrySummaries != null && index < mEntrySummaries.length) { setSummary(mEntrySummaries[index]); } else { setSummary(getEntries()[index]); } } } ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/project.properties ================================================ # This file is automatically generated by Android Tools. # Do not modify this file -- YOUR CHANGES WILL BE ERASED! # # This file must be checked in Version Control Systems. # # To customize properties used by the Ant build system edit # "ant.properties", and override values to adapt the script to your # project structure. # # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. target=android-22 android.library.reference.1=../../../player-arm64/src/main android.library.reference.2=../../../player-armv5/src/main android.library.reference.3=../../../player-armv7a/src/main android.library.reference.4=../../../player-x86/src/main android.library.reference.5=../../../player-java/src/main android.library.reference.6=../../../../contrib/appcompat ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/layout/activity_app.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/layout/activity_player.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/layout/fragment_file_list.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/layout/fragment_file_list_item.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/layout/fragment_track_list.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/layout/table_media_info.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/layout/table_media_info_row1.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/layout/table_media_info_row2.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/layout/table_media_info_section.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/layout/widget_toolbar.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/menu/menu_app.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/menu/menu_player.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/values/attrs.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/values/colors.xml ================================================ #66000000 @color/ijk_color_blue_500 #E3F2FD #BBDEFB #90CAF9 #64B5F6 #42A5F5 #2196F3 #1E88E5 #1976D2 #1565C0 #0D47A1 #77000000 ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/values/dimens.xml ================================================ 16dp 16dp @dimen/activity_horizontal_margin @dimen/activity_vertical_margin ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/values/ids.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/values/strings.xml ================================================ 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 * * * Video Audio Subtitle Timed text Meta data Unknown Invalid progressive playback Unknown OK Aspect / Fit parent Aspect / Fill parent Aspect / Wrap content Free / Fill parent 16:9 / Fit parent 4:3 / Fit parent Render: None Render: SurfaceView Render: TextureView Player: None Player: AndroidMediaPlayer Player: IjkMediaPlayer Player: IjkExoMediaPlayer ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/values/strings_pref.xml ================================================ General pref.enable_background_play Enable background play need Android 4.0+ pref.using_android_player Using system player pref.player Choose Player Auto Select AndroidMediaPlayer IjkMediaPlayer IjkExoMediaPlayer 0 1 2 3 Auto Select AndroidMediaPlayer IjkMediaPlayer IjkExoMediaPlayer Video: ijkplayer pref.using_media_codec Using MediaCodec pref.using_media_codec_auto_rotate Using MediaCodec auto rotate pref.media_codec_handle_resolution_change MediaCodec handle resolution change pref.pixel_format Pixel Format Auto Select RGB 565 RGB 888 RGBX 8888 YV12 OpenGL ES2 fcc-rv16 fcc-rv24 fcc-rv32 fcc-yv12 fcc-_es2 Auto Select RGB 565 RGB 888 RGBX 8888 YV12 OpenGL ES2 Audio: ijkplayer pref.using_opensl_es Using OpenSL ES RenderView pref.enable_no_view Enable NoView pref.enable_surface_view Enable SurfaceView pref.enable_texture_view Enable TextureView pref.enable_detached_surface_texture Enable detached SurfaceTexture Misc pref.using_mediadatasource Using MediaDataSource ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/values/styles.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/values/themes.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/values-v11/styles.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/values-v14/styles.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/values-w820dp/dimens.xml ================================================ 64dp ================================================ FILE: android/ijkplayer/ijkplayer-example/src/main/res/xml/settings.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-exo/.gitignore ================================================ /build ================================================ FILE: android/ijkplayer/ijkplayer-exo/build.gradle ================================================ apply plugin: 'com.android.library' android { // http://tools.android.com/tech-docs/new-build-system/tips //noinspection GroovyAssignabilityCheck compileSdkVersion rootProject.ext.compileSdkVersion //noinspection GroovyAssignabilityCheck buildToolsVersion rootProject.ext.buildToolsVersion lintOptions { abortOnError false } defaultConfig { minSdkVersion 9 targetSdkVersion rootProject.ext.targetSdkVersion } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.google.android.exoplayer:exoplayer:r1.5.11' compile project(':ijkplayer-java') // compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8' } gradle.startParameter.taskNames.each { task -> def subProjectName = task; if (task.startsWith(':')) subProjectName = task.split(":")[1] if (subProjectName.equals(project.name)) apply from: new File(rootProject.projectDir, "tools/gradle-on-demand.gradle"); } ================================================ FILE: android/ijkplayer/ijkplayer-exo/gradle.properties ================================================ POM_NAME=ijkplayer-exo POM_ARTIFACT_ID=ijkplayer-exo POM_PACKAGING=aar ================================================ FILE: android/ijkplayer/ijkplayer-exo/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /opt/android/ADK/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: android/ijkplayer/ijkplayer-exo/src/androidTest/java/tv/danmaku/ijk/media/exo/ApplicationTest.java ================================================ package tv.danmaku.ijk.media.exo; import android.app.Application; import android.test.ApplicationTestCase; /** * Testing Fundamentals */ public class ApplicationTest extends ApplicationTestCase { public ApplicationTest() { super(Application.class); } } ================================================ FILE: android/ijkplayer/ijkplayer-exo/src/main/AndroidManifest.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/IjkExoMediaPlayer.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.exo; import android.content.Context; import android.net.Uri; import android.view.Surface; import android.view.SurfaceHolder; import com.google.android.exoplayer.ExoPlayer; import com.google.android.exoplayer.util.Util; import java.io.FileDescriptor; import java.util.Map; import tv.danmaku.ijk.media.exo.demo.EventLogger; import tv.danmaku.ijk.media.exo.demo.player.DemoPlayer; import tv.danmaku.ijk.media.exo.demo.player.DemoPlayer.RendererBuilder; import tv.danmaku.ijk.media.exo.demo.player.ExtractorRendererBuilder; import tv.danmaku.ijk.media.exo.demo.player.HlsRendererBuilder; import tv.danmaku.ijk.media.exo.demo.player.SmoothStreamingRendererBuilder; import tv.danmaku.ijk.media.exo.demo.SmoothStreamingTestMediaDrmCallback; import tv.danmaku.ijk.media.player.AbstractMediaPlayer; import tv.danmaku.ijk.media.player.IMediaPlayer; import tv.danmaku.ijk.media.player.MediaInfo; import tv.danmaku.ijk.media.player.misc.IjkTrackInfo; public class IjkExoMediaPlayer extends AbstractMediaPlayer { private Context mAppContext; private DemoPlayer mInternalPlayer; private EventLogger mEventLogger; private String mDataSource; private int mVideoWidth; private int mVideoHeight; private Surface mSurface; private RendererBuilder mRendererBuilder; public IjkExoMediaPlayer(Context context) { mAppContext = context.getApplicationContext(); mDemoListener = new DemoPlayerListener(); mEventLogger = new EventLogger(); mEventLogger.startSession(); } @Override public void setDisplay(SurfaceHolder sh) { if (sh == null) setSurface(null); else setSurface(sh.getSurface()); } @Override public void setSurface(Surface surface) { mSurface = surface; if (mInternalPlayer != null) mInternalPlayer.setSurface(surface); } @Override public void setDataSource(Context context, Uri uri) { mDataSource = uri.toString(); mRendererBuilder = getRendererBuilder(); } @Override public void setDataSource(Context context, Uri uri, Map headers) { // TODO: handle headers setDataSource(context, uri); } @Override public void setDataSource(String path) { setDataSource(mAppContext, Uri.parse(path)); } @Override public void setDataSource(FileDescriptor fd) { // TODO: no support throw new UnsupportedOperationException("no support"); } @Override public String getDataSource() { return mDataSource; } @Override public void prepareAsync() throws IllegalStateException { if (mInternalPlayer != null) throw new IllegalStateException("can't prepare a prepared player"); mInternalPlayer = new DemoPlayer(mRendererBuilder); mInternalPlayer.addListener(mDemoListener); mInternalPlayer.addListener(mEventLogger); mInternalPlayer.setInfoListener(mEventLogger); mInternalPlayer.setInternalErrorListener(mEventLogger); if (mSurface != null) mInternalPlayer.setSurface(mSurface); mInternalPlayer.prepare(); mInternalPlayer.setPlayWhenReady(false); } @Override public void start() throws IllegalStateException { if (mInternalPlayer == null) return; mInternalPlayer.setPlayWhenReady(true); } @Override public void stop() throws IllegalStateException { if (mInternalPlayer == null) return; mInternalPlayer.release(); } @Override public void pause() throws IllegalStateException { if (mInternalPlayer == null) return; mInternalPlayer.setPlayWhenReady(false); } @Override public void setWakeMode(Context context, int mode) { // FIXME: implement } @Override public void setScreenOnWhilePlaying(boolean screenOn) { // TODO: do nothing } @Override public IjkTrackInfo[] getTrackInfo() { // TODO: implement return null; } @Override public int getVideoWidth() { return mVideoWidth; } @Override public int getVideoHeight() { return mVideoHeight; } @Override public boolean isPlaying() { if (mInternalPlayer == null) return false; int state = mInternalPlayer.getPlaybackState(); switch (state) { case ExoPlayer.STATE_BUFFERING: case ExoPlayer.STATE_READY: return mInternalPlayer.getPlayWhenReady(); case ExoPlayer.STATE_IDLE: case ExoPlayer.STATE_PREPARING: case ExoPlayer.STATE_ENDED: default: return false; } } @Override public void seekTo(long msec) throws IllegalStateException { if (mInternalPlayer == null) return; mInternalPlayer.seekTo(msec); } @Override public long getCurrentPosition() { if (mInternalPlayer == null) return 0; return mInternalPlayer.getCurrentPosition(); } @Override public long getDuration() { if (mInternalPlayer == null) return 0; return mInternalPlayer.getDuration(); } @Override public int getVideoSarNum() { return 1; } @Override public int getVideoSarDen() { return 1; } @Override public void reset() { if (mInternalPlayer != null) { mInternalPlayer.release(); mInternalPlayer.removeListener(mDemoListener); mInternalPlayer.removeListener(mEventLogger); mInternalPlayer.setInfoListener(null); mInternalPlayer.setInternalErrorListener(null); mInternalPlayer = null; } mSurface = null; mDataSource = null; mVideoWidth = 0; mVideoHeight = 0; } @Override public void setLooping(boolean looping) { // TODO: no support throw new UnsupportedOperationException("no support"); } @Override public boolean isLooping() { // TODO: no support return false; } @Override public void setVolume(float leftVolume, float rightVolume) { // TODO: no support } @Override public int getAudioSessionId() { // TODO: no support return 0; } @Override public MediaInfo getMediaInfo() { // TODO: no support return null; } @Override public void setLogEnabled(boolean enable) { // do nothing } @Override public boolean isPlayable() { return true; } @Override public void setAudioStreamType(int streamtype) { // do nothing } @Override public void setKeepInBackground(boolean keepInBackground) { // do nothing } @Override public void release() { if (mInternalPlayer != null) { reset(); mDemoListener = null; mEventLogger.endSession(); mEventLogger = null; } } public int getBufferedPercentage() { if (mInternalPlayer == null) return 0; return mInternalPlayer.getBufferedPercentage(); } private RendererBuilder getRendererBuilder() { Uri contentUri = Uri.parse(mDataSource); String userAgent = Util.getUserAgent(mAppContext, "IjkExoMediaPlayer"); int contentType = inferContentType(contentUri); switch (contentType) { case Util.TYPE_SS: return new SmoothStreamingRendererBuilder(mAppContext, userAgent, contentUri.toString(), new SmoothStreamingTestMediaDrmCallback()); /* case Util.TYPE_DASH: return new DashRendererBuilder(mAppContext , userAgent, contentUri.toString(), new WidevineTestMediaDrmCallback(contentId, provider));*/ case Util.TYPE_HLS: return new HlsRendererBuilder(mAppContext, userAgent, contentUri.toString()); case Util.TYPE_OTHER: default: return new ExtractorRendererBuilder(mAppContext, userAgent, contentUri); } } /** * Makes a best guess to infer the type from a media {@link Uri} * * @param uri The {@link Uri} of the media. * @return The inferred type. */ private static int inferContentType(Uri uri) { String lastPathSegment = uri.getLastPathSegment(); return Util.inferContentType(lastPathSegment); } private class DemoPlayerListener implements DemoPlayer.Listener { private boolean mIsPrepareing = false; private boolean mDidPrepare = false; private boolean mIsBuffering = false; public void onStateChanged(boolean playWhenReady, int playbackState) { if (mIsBuffering) { switch (playbackState) { case ExoPlayer.STATE_ENDED: case ExoPlayer.STATE_READY: notifyOnInfo(IMediaPlayer.MEDIA_INFO_BUFFERING_END, mInternalPlayer.getBufferedPercentage()); mIsBuffering = false; break; } } if (mIsPrepareing) { switch (playbackState) { case ExoPlayer.STATE_READY: notifyOnPrepared(); mIsPrepareing = false; mDidPrepare = false; break; } } switch (playbackState) { case ExoPlayer.STATE_IDLE: notifyOnCompletion(); break; case ExoPlayer.STATE_PREPARING: mIsPrepareing = true; break; case ExoPlayer.STATE_BUFFERING: notifyOnInfo(IMediaPlayer.MEDIA_INFO_BUFFERING_START, mInternalPlayer.getBufferedPercentage()); mIsBuffering = true; break; case ExoPlayer.STATE_READY: break; case ExoPlayer.STATE_ENDED: notifyOnCompletion(); break; default: break; } } public void onError(Exception e) { notifyOnError(IMediaPlayer.MEDIA_ERROR_UNKNOWN, IMediaPlayer.MEDIA_ERROR_UNKNOWN); } public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { mVideoWidth = width; mVideoHeight = height; notifyOnVideoSizeChanged(width, height, 1, 1); if (unappliedRotationDegrees > 0) notifyOnInfo(IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED, unappliedRotationDegrees); } } private DemoPlayerListener mDemoListener; } ================================================ FILE: android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/demo/EventLogger.java ================================================ /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.exo.demo; import android.media.MediaCodec.CryptoException; import android.os.SystemClock; import android.util.Log; import com.google.android.exoplayer.ExoPlayer; import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException; import com.google.android.exoplayer.TimeRange; import com.google.android.exoplayer.audio.AudioTrack; import com.google.android.exoplayer.chunk.Format; import tv.danmaku.ijk.media.exo.demo.player.DemoPlayer; import com.google.android.exoplayer.util.VerboseLogUtil; import java.io.IOException; import java.text.NumberFormat; import java.util.Locale; /** * Logs player events using {link Log}. */ public class EventLogger implements DemoPlayer.Listener, DemoPlayer.InfoListener, DemoPlayer.InternalErrorListener { private static final String TAG = "EventLogger"; private static final NumberFormat TIME_FORMAT; static { TIME_FORMAT = NumberFormat.getInstance(Locale.US); TIME_FORMAT.setMinimumFractionDigits(2); TIME_FORMAT.setMaximumFractionDigits(2); } private long sessionStartTimeMs; private long[] loadStartTimeMs; private long[] availableRangeValuesUs; public EventLogger() { loadStartTimeMs = new long[DemoPlayer.RENDERER_COUNT]; } public void startSession() { sessionStartTimeMs = SystemClock.elapsedRealtime(); Log.d(TAG, "start [0]"); } public void endSession() { Log.d(TAG, "end [" + getSessionTimeString() + "]"); } // DemoPlayer.Listener @Override public void onStateChanged(boolean playWhenReady, int state) { Log.d(TAG, "state [" + getSessionTimeString() + ", " + playWhenReady + ", " + getStateString(state) + "]"); } @Override public void onError(Exception e) { Log.e(TAG, "playerFailed [" + getSessionTimeString() + "]", e); } @Override public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { Log.d(TAG, "videoSizeChanged [" + width + ", " + height + ", " + unappliedRotationDegrees + ", " + pixelWidthHeightRatio + "]"); } // DemoPlayer.InfoListener @Override public void onBandwidthSample(int elapsedMs, long bytes, long bitrateEstimate) { Log.d(TAG, "bandwidth [" + getSessionTimeString() + ", " + bytes + ", " + getTimeString(elapsedMs) + ", " + bitrateEstimate + "]"); } @Override public void onDroppedFrames(int count, long elapsed) { Log.d(TAG, "droppedFrames [" + getSessionTimeString() + ", " + count + "]"); } @Override public void onLoadStarted(int sourceId, long length, int type, int trigger, Format format, long mediaStartTimeMs, long mediaEndTimeMs) { loadStartTimeMs[sourceId] = SystemClock.elapsedRealtime(); if (VerboseLogUtil.isTagEnabled(TAG)) { Log.v(TAG, "loadStart [" + getSessionTimeString() + ", " + sourceId + ", " + type + ", " + mediaStartTimeMs + ", " + mediaEndTimeMs + "]"); } } @Override public void onLoadCompleted(int sourceId, long bytesLoaded, int type, int trigger, Format format, long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs) { if (VerboseLogUtil.isTagEnabled(TAG)) { long downloadTime = SystemClock.elapsedRealtime() - loadStartTimeMs[sourceId]; Log.v(TAG, "loadEnd [" + getSessionTimeString() + ", " + sourceId + ", " + downloadTime + "]"); } } @Override public void onVideoFormatEnabled(Format format, int trigger, long mediaTimeMs) { Log.d(TAG, "videoFormat [" + getSessionTimeString() + ", " + format.id + ", " + Integer.toString(trigger) + "]"); } @Override public void onAudioFormatEnabled(Format format, int trigger, long mediaTimeMs) { Log.d(TAG, "audioFormat [" + getSessionTimeString() + ", " + format.id + ", " + Integer.toString(trigger) + "]"); } // DemoPlayer.InternalErrorListener @Override public void onLoadError(int sourceId, IOException e) { printInternalError("loadError", e); } @Override public void onRendererInitializationError(Exception e) { printInternalError("rendererInitError", e); } @Override public void onDrmSessionManagerError(Exception e) { printInternalError("drmSessionManagerError", e); } @Override public void onDecoderInitializationError(DecoderInitializationException e) { printInternalError("decoderInitializationError", e); } @Override public void onAudioTrackInitializationError(AudioTrack.InitializationException e) { printInternalError("audioTrackInitializationError", e); } @Override public void onAudioTrackWriteError(AudioTrack.WriteException e) { printInternalError("audioTrackWriteError", e); } @Override public void onAudioTrackUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) { printInternalError("audioTrackUnderrun [" + bufferSize + ", " + bufferSizeMs + ", " + elapsedSinceLastFeedMs + "]", null); } @Override public void onCryptoError(CryptoException e) { printInternalError("cryptoError", e); } @Override public void onDecoderInitialized(String decoderName, long elapsedRealtimeMs, long initializationDurationMs) { Log.d(TAG, "decoderInitialized [" + getSessionTimeString() + ", " + decoderName + "]"); } @Override public void onAvailableRangeChanged(int sourceId, TimeRange availableRange) { availableRangeValuesUs = availableRange.getCurrentBoundsUs(availableRangeValuesUs); Log.d(TAG, "availableRange [" + availableRange.isStatic() + ", " + availableRangeValuesUs[0] + ", " + availableRangeValuesUs[1] + "]"); } private void printInternalError(String type, Exception e) { Log.e(TAG, "internalError [" + getSessionTimeString() + ", " + type + "]", e); } private String getStateString(int state) { switch (state) { case ExoPlayer.STATE_BUFFERING: return "B"; case ExoPlayer.STATE_ENDED: return "E"; case ExoPlayer.STATE_IDLE: return "I"; case ExoPlayer.STATE_PREPARING: return "P"; case ExoPlayer.STATE_READY: return "R"; default: return "?"; } } private String getSessionTimeString() { return getTimeString(SystemClock.elapsedRealtime() - sessionStartTimeMs); } private String getTimeString(long timeMs) { return TIME_FORMAT.format((timeMs) / 1000f); } } ================================================ FILE: android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/demo/SmoothStreamingTestMediaDrmCallback.java ================================================ /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.exo.demo; import android.annotation.TargetApi; import android.text.TextUtils; import com.google.android.exoplayer.drm.ExoMediaDrm.KeyRequest; import com.google.android.exoplayer.drm.ExoMediaDrm.ProvisionRequest; import com.google.android.exoplayer.drm.MediaDrmCallback; import com.google.android.exoplayer.drm.StreamingDrmSessionManager; import com.google.android.exoplayer.util.Util; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.UUID; /** * Demo {link StreamingDrmSessionManager} for smooth streaming test content. */ @TargetApi(18) public class SmoothStreamingTestMediaDrmCallback implements MediaDrmCallback { private static final String PLAYREADY_TEST_DEFAULT_URI = "http://playready.directtaps.net/pr/svc/rightsmanager.asmx"; private static final Map PROVISIONING_REQUEST_PROPERTIES = Collections.singletonMap("Content-Type", "application/octet-stream"); private static final Map KEY_REQUEST_PROPERTIES; static { HashMap keyRequestProperties = new HashMap<>(); keyRequestProperties.put("Content-Type", "text/xml"); keyRequestProperties.put("SOAPAction", "http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"); KEY_REQUEST_PROPERTIES = keyRequestProperties; } @Override public byte[] executeProvisionRequest(UUID uuid, ProvisionRequest request) throws IOException { String url = request.getDefaultUrl() + "&signedRequest=" + new String(request.getData()); return Util.executePost(url, null, PROVISIONING_REQUEST_PROPERTIES); } @Override public byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws Exception { String url = request.getDefaultUrl(); if (TextUtils.isEmpty(url)) { url = PLAYREADY_TEST_DEFAULT_URI; } return Util.executePost(url, request.getData(), KEY_REQUEST_PROPERTIES); } } ================================================ FILE: android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/demo/player/DashRendererBuilder.java ================================================ /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.exo.demo.player; import android.content.Context; import android.media.AudioManager; import android.media.MediaCodec; import android.os.Handler; import android.util.Log; import com.google.android.exoplayer.DefaultLoadControl; import com.google.android.exoplayer.LoadControl; import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; import com.google.android.exoplayer.MediaCodecSelector; import com.google.android.exoplayer.MediaCodecVideoTrackRenderer; import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.audio.AudioCapabilities; import com.google.android.exoplayer.chunk.ChunkSampleSource; import com.google.android.exoplayer.chunk.ChunkSource; import com.google.android.exoplayer.chunk.FormatEvaluator.AdaptiveEvaluator; import com.google.android.exoplayer.dash.DashChunkSource; import com.google.android.exoplayer.dash.DefaultDashTrackSelector; import com.google.android.exoplayer.dash.mpd.AdaptationSet; import com.google.android.exoplayer.dash.mpd.MediaPresentationDescription; import com.google.android.exoplayer.dash.mpd.MediaPresentationDescriptionParser; import com.google.android.exoplayer.dash.mpd.Period; import com.google.android.exoplayer.dash.mpd.UtcTimingElement; import com.google.android.exoplayer.dash.mpd.UtcTimingElementResolver; import com.google.android.exoplayer.dash.mpd.UtcTimingElementResolver.UtcTimingCallback; import tv.danmaku.ijk.media.exo.demo.player.DemoPlayer.RendererBuilder; import com.google.android.exoplayer.drm.FrameworkMediaCrypto; import com.google.android.exoplayer.drm.MediaDrmCallback; import com.google.android.exoplayer.drm.StreamingDrmSessionManager; import com.google.android.exoplayer.drm.UnsupportedDrmException; import com.google.android.exoplayer.text.TextTrackRenderer; import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer.upstream.DefaultAllocator; import com.google.android.exoplayer.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer.upstream.DefaultUriDataSource; import com.google.android.exoplayer.upstream.UriDataSource; import com.google.android.exoplayer.util.ManifestFetcher; import com.google.android.exoplayer.util.Util; import java.io.IOException; /** * A {link RendererBuilder} for DASH. */ public class DashRendererBuilder implements RendererBuilder { private static final String TAG = "DashRendererBuilder"; private static final int BUFFER_SEGMENT_SIZE = 64 * 1024; private static final int VIDEO_BUFFER_SEGMENTS = 200; private static final int AUDIO_BUFFER_SEGMENTS = 54; private static final int TEXT_BUFFER_SEGMENTS = 2; private static final int LIVE_EDGE_LATENCY_MS = 30000; private static final int SECURITY_LEVEL_UNKNOWN = -1; private static final int SECURITY_LEVEL_1 = 1; private static final int SECURITY_LEVEL_3 = 3; private final Context context; private final String userAgent; private final String url; private final MediaDrmCallback drmCallback; private AsyncRendererBuilder currentAsyncBuilder; public DashRendererBuilder(Context context, String userAgent, String url, MediaDrmCallback drmCallback) { this.context = context; this.userAgent = userAgent; this.url = url; this.drmCallback = drmCallback; } @Override public void buildRenderers(DemoPlayer player) { currentAsyncBuilder = new AsyncRendererBuilder(context, userAgent, url, drmCallback, player); currentAsyncBuilder.init(); } @Override public void cancel() { if (currentAsyncBuilder != null) { currentAsyncBuilder.cancel(); currentAsyncBuilder = null; } } private static final class AsyncRendererBuilder implements ManifestFetcher.ManifestCallback, UtcTimingCallback { private final Context context; private final String userAgent; private final MediaDrmCallback drmCallback; private final DemoPlayer player; private final ManifestFetcher manifestFetcher; private final UriDataSource manifestDataSource; private boolean canceled; private MediaPresentationDescription manifest; private long elapsedRealtimeOffset; public AsyncRendererBuilder(Context context, String userAgent, String url, MediaDrmCallback drmCallback, DemoPlayer player) { this.context = context; this.userAgent = userAgent; this.drmCallback = drmCallback; this.player = player; MediaPresentationDescriptionParser parser = new MediaPresentationDescriptionParser(); manifestDataSource = new DefaultUriDataSource(context, userAgent); manifestFetcher = new ManifestFetcher<>(url, manifestDataSource, parser); } public void init() { manifestFetcher.singleLoad(player.getMainHandler().getLooper(), this); } public void cancel() { canceled = true; } @Override public void onSingleManifest(MediaPresentationDescription manifest) { if (canceled) { return; } this.manifest = manifest; if (manifest.dynamic && manifest.utcTiming != null) { UtcTimingElementResolver.resolveTimingElement(manifestDataSource, manifest.utcTiming, manifestFetcher.getManifestLoadCompleteTimestamp(), this); } else { buildRenderers(); } } @Override public void onSingleManifestError(IOException e) { if (canceled) { return; } player.onRenderersError(e); } @Override public void onTimestampResolved(UtcTimingElement utcTiming, long elapsedRealtimeOffset) { if (canceled) { return; } this.elapsedRealtimeOffset = elapsedRealtimeOffset; buildRenderers(); } @Override public void onTimestampError(UtcTimingElement utcTiming, IOException e) { if (canceled) { return; } Log.e(TAG, "Failed to resolve UtcTiming element [" + utcTiming + "]", e); // Be optimistic and continue in the hope that the device clock is correct. buildRenderers(); } private void buildRenderers() { Period period = manifest.getPeriod(0); Handler mainHandler = player.getMainHandler(); LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE)); DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(mainHandler, player); boolean hasContentProtection = false; for (int i = 0; i < period.adaptationSets.size(); i++) { AdaptationSet adaptationSet = period.adaptationSets.get(i); if (adaptationSet.type != AdaptationSet.TYPE_UNKNOWN) { hasContentProtection |= adaptationSet.hasContentProtection(); } } // Check drm support if necessary. boolean filterHdContent = false; StreamingDrmSessionManager drmSessionManager = null; if (hasContentProtection) { if (Util.SDK_INT < 18) { player.onRenderersError( new UnsupportedDrmException(UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME)); return; } try { drmSessionManager = StreamingDrmSessionManager.newWidevineInstance( player.getPlaybackLooper(), drmCallback, null, player.getMainHandler(), player); filterHdContent = getWidevineSecurityLevel(drmSessionManager) != SECURITY_LEVEL_1; } catch (UnsupportedDrmException e) { player.onRenderersError(e); return; } } // Build the video renderer. DataSource videoDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); ChunkSource videoChunkSource = new DashChunkSource(manifestFetcher, DefaultDashTrackSelector.newVideoInstance(context, true, filterHdContent), videoDataSource, new AdaptiveEvaluator(bandwidthMeter), LIVE_EDGE_LATENCY_MS, elapsedRealtimeOffset, mainHandler, player, DemoPlayer.TYPE_VIDEO); ChunkSampleSource videoSampleSource = new ChunkSampleSource(videoChunkSource, loadControl, VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_VIDEO); TrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, videoSampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, drmSessionManager, true, mainHandler, player, 50); // Build the audio renderer. DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); ChunkSource audioChunkSource = new DashChunkSource(manifestFetcher, DefaultDashTrackSelector.newAudioInstance(), audioDataSource, null, LIVE_EDGE_LATENCY_MS, elapsedRealtimeOffset, mainHandler, player, DemoPlayer.TYPE_AUDIO); ChunkSampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource, loadControl, AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_AUDIO); TrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(audioSampleSource, MediaCodecSelector.DEFAULT, drmSessionManager, true, mainHandler, player, AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC); // Build the text renderer. DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); ChunkSource textChunkSource = new DashChunkSource(manifestFetcher, DefaultDashTrackSelector.newTextInstance(), textDataSource, null, LIVE_EDGE_LATENCY_MS, elapsedRealtimeOffset, mainHandler, player, DemoPlayer.TYPE_TEXT); ChunkSampleSource textSampleSource = new ChunkSampleSource(textChunkSource, loadControl, TEXT_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_TEXT); TrackRenderer textRenderer = new TextTrackRenderer(textSampleSource, player, mainHandler.getLooper()); // Invoke the callback. TrackRenderer[] renderers = new TrackRenderer[DemoPlayer.RENDERER_COUNT]; renderers[DemoPlayer.TYPE_VIDEO] = videoRenderer; renderers[DemoPlayer.TYPE_AUDIO] = audioRenderer; renderers[DemoPlayer.TYPE_TEXT] = textRenderer; player.onRenderers(renderers, bandwidthMeter); } private static int getWidevineSecurityLevel(StreamingDrmSessionManager sessionManager) { String securityLevelProperty = sessionManager.getPropertyString("securityLevel"); return securityLevelProperty.equals("L1") ? SECURITY_LEVEL_1 : securityLevelProperty .equals("L3") ? SECURITY_LEVEL_3 : SECURITY_LEVEL_UNKNOWN; } } } ================================================ FILE: android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/demo/player/DemoPlayer.java ================================================ /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.exo.demo.player; import android.media.MediaCodec.CryptoException; import android.os.Handler; import android.os.Looper; import android.view.Surface; import com.google.android.exoplayer.CodecCounters; import com.google.android.exoplayer.DummyTrackRenderer; import com.google.android.exoplayer.ExoPlaybackException; import com.google.android.exoplayer.ExoPlayer; import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; import com.google.android.exoplayer.MediaCodecTrackRenderer; import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException; import com.google.android.exoplayer.MediaCodecVideoTrackRenderer; import com.google.android.exoplayer.MediaFormat; import com.google.android.exoplayer.SingleSampleSource; import com.google.android.exoplayer.TimeRange; import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.audio.AudioTrack; import com.google.android.exoplayer.chunk.ChunkSampleSource; import com.google.android.exoplayer.chunk.Format; import com.google.android.exoplayer.dash.DashChunkSource; import com.google.android.exoplayer.drm.StreamingDrmSessionManager; import com.google.android.exoplayer.extractor.ExtractorSampleSource; import com.google.android.exoplayer.hls.HlsSampleSource; import com.google.android.exoplayer.metadata.MetadataTrackRenderer.MetadataRenderer; import com.google.android.exoplayer.metadata.id3.Id3Frame; import com.google.android.exoplayer.text.Cue; import com.google.android.exoplayer.text.TextRenderer; import com.google.android.exoplayer.upstream.BandwidthMeter; import com.google.android.exoplayer.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer.util.DebugTextViewHelper; import com.google.android.exoplayer.util.PlayerControl; import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** * A wrapper around {link ExoPlayer} that provides a higher level interface. It can be prepared * with one of a number of {link RendererBuilder} classes to suit different use cases (e.g. DASH, * SmoothStreaming and so on). */ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventListener, HlsSampleSource.EventListener, ExtractorSampleSource.EventListener, SingleSampleSource.EventListener, DefaultBandwidthMeter.EventListener, MediaCodecVideoTrackRenderer.EventListener, MediaCodecAudioTrackRenderer.EventListener, StreamingDrmSessionManager.EventListener, DashChunkSource.EventListener, TextRenderer, MetadataRenderer>, DebugTextViewHelper.Provider { /** * Builds renderers for the player. */ public interface RendererBuilder { /** * Builds renderers for playback. * * @param player The player for which renderers are being built. {link DemoPlayer#onRenderers} * should be invoked once the renderers have been built. If building fails, * {link DemoPlayer#onRenderersError} should be invoked. */ void buildRenderers(DemoPlayer player); /** * Cancels the current build operation, if there is one. Else does nothing. *

* A canceled build operation must not invoke {link DemoPlayer#onRenderers} or * {link DemoPlayer#onRenderersError} on the player, which may have been released. */ void cancel(); } /** * A listener for core events. */ public interface Listener { void onStateChanged(boolean playWhenReady, int playbackState); void onError(Exception e); void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio); } /** * A listener for internal errors. *

* These errors are not visible to the user, and hence this listener is provided for * informational purposes only. Note however that an internal error may cause a fatal * error if the player fails to recover. If this happens, {link Listener#onError(Exception)} * will be invoked. */ public interface InternalErrorListener { void onRendererInitializationError(Exception e); void onAudioTrackInitializationError(AudioTrack.InitializationException e); void onAudioTrackWriteError(AudioTrack.WriteException e); void onAudioTrackUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs); void onDecoderInitializationError(DecoderInitializationException e); void onCryptoError(CryptoException e); void onLoadError(int sourceId, IOException e); void onDrmSessionManagerError(Exception e); } /** * A listener for debugging information. */ public interface InfoListener { void onVideoFormatEnabled(Format format, int trigger, long mediaTimeMs); void onAudioFormatEnabled(Format format, int trigger, long mediaTimeMs); void onDroppedFrames(int count, long elapsed); void onBandwidthSample(int elapsedMs, long bytes, long bitrateEstimate); void onLoadStarted(int sourceId, long length, int type, int trigger, Format format, long mediaStartTimeMs, long mediaEndTimeMs); void onLoadCompleted(int sourceId, long bytesLoaded, int type, int trigger, Format format, long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs); void onDecoderInitialized(String decoderName, long elapsedRealtimeMs, long initializationDurationMs); void onAvailableRangeChanged(int sourceId, TimeRange availableRange); } /** * A listener for receiving notifications of timed text. */ public interface CaptionListener { void onCues(List cues); } /** * A listener for receiving ID3 metadata parsed from the media stream. */ public interface Id3MetadataListener { void onId3Metadata(List id3Frames); } // Constants pulled into this class for convenience. public static final int STATE_IDLE = ExoPlayer.STATE_IDLE; public static final int STATE_PREPARING = ExoPlayer.STATE_PREPARING; public static final int STATE_BUFFERING = ExoPlayer.STATE_BUFFERING; public static final int STATE_READY = ExoPlayer.STATE_READY; public static final int STATE_ENDED = ExoPlayer.STATE_ENDED; public static final int TRACK_DISABLED = ExoPlayer.TRACK_DISABLED; public static final int TRACK_DEFAULT = ExoPlayer.TRACK_DEFAULT; public static final int RENDERER_COUNT = 4; public static final int TYPE_VIDEO = 0; public static final int TYPE_AUDIO = 1; public static final int TYPE_TEXT = 2; public static final int TYPE_METADATA = 3; private static final int RENDERER_BUILDING_STATE_IDLE = 1; private static final int RENDERER_BUILDING_STATE_BUILDING = 2; private static final int RENDERER_BUILDING_STATE_BUILT = 3; private final RendererBuilder rendererBuilder; private final ExoPlayer player; private final PlayerControl playerControl; private final Handler mainHandler; private final CopyOnWriteArrayList listeners; private int rendererBuildingState; private int lastReportedPlaybackState; private boolean lastReportedPlayWhenReady; private Surface surface; private TrackRenderer videoRenderer; private CodecCounters codecCounters; private Format videoFormat; private int videoTrackToRestore; private BandwidthMeter bandwidthMeter; private boolean backgrounded; private CaptionListener captionListener; private Id3MetadataListener id3MetadataListener; private InternalErrorListener internalErrorListener; private InfoListener infoListener; public DemoPlayer(RendererBuilder rendererBuilder) { this.rendererBuilder = rendererBuilder; player = ExoPlayer.Factory.newInstance(RENDERER_COUNT, 1000, 5000); player.addListener(this); playerControl = new PlayerControl(player); mainHandler = new Handler(); listeners = new CopyOnWriteArrayList<>(); lastReportedPlaybackState = STATE_IDLE; rendererBuildingState = RENDERER_BUILDING_STATE_IDLE; // Disable text initially. player.setSelectedTrack(TYPE_TEXT, TRACK_DISABLED); } public PlayerControl getPlayerControl() { return playerControl; } public void addListener(Listener listener) { listeners.add(listener); } public void removeListener(Listener listener) { listeners.remove(listener); } public void setInternalErrorListener(InternalErrorListener listener) { internalErrorListener = listener; } public void setInfoListener(InfoListener listener) { infoListener = listener; } public void setCaptionListener(CaptionListener listener) { captionListener = listener; } public void setMetadataListener(Id3MetadataListener listener) { id3MetadataListener = listener; } public void setSurface(Surface surface) { this.surface = surface; pushSurface(false); } public Surface getSurface() { return surface; } public void blockingClearSurface() { surface = null; pushSurface(true); } public int getTrackCount(int type) { return player.getTrackCount(type); } public MediaFormat getTrackFormat(int type, int index) { return player.getTrackFormat(type, index); } public int getSelectedTrack(int type) { return player.getSelectedTrack(type); } public void setSelectedTrack(int type, int index) { player.setSelectedTrack(type, index); if (type == TYPE_TEXT && index < 0 && captionListener != null) { captionListener.onCues(Collections.emptyList()); } } public boolean getBackgrounded() { return backgrounded; } public void setBackgrounded(boolean backgrounded) { if (this.backgrounded == backgrounded) { return; } this.backgrounded = backgrounded; if (backgrounded) { videoTrackToRestore = getSelectedTrack(TYPE_VIDEO); setSelectedTrack(TYPE_VIDEO, TRACK_DISABLED); blockingClearSurface(); } else { setSelectedTrack(TYPE_VIDEO, videoTrackToRestore); } } public void prepare() { if (rendererBuildingState == RENDERER_BUILDING_STATE_BUILT) { player.stop(); } rendererBuilder.cancel(); videoFormat = null; videoRenderer = null; rendererBuildingState = RENDERER_BUILDING_STATE_BUILDING; maybeReportPlayerState(); rendererBuilder.buildRenderers(this); } /** * Invoked with the results from a {link RendererBuilder}. * * @param renderers Renderers indexed by {link DemoPlayer} TYPE_* constants. An individual * element may be null if there do not exist tracks of the corresponding type. * @param bandwidthMeter Provides an estimate of the currently available bandwidth. May be null. */ /* package */ void onRenderers(TrackRenderer[] renderers, BandwidthMeter bandwidthMeter) { for (int i = 0; i < RENDERER_COUNT; i++) { if (renderers[i] == null) { // Convert a null renderer to a dummy renderer. renderers[i] = new DummyTrackRenderer(); } } // Complete preparation. this.videoRenderer = renderers[TYPE_VIDEO]; this.codecCounters = videoRenderer instanceof MediaCodecTrackRenderer ? ((MediaCodecTrackRenderer) videoRenderer).codecCounters : renderers[TYPE_AUDIO] instanceof MediaCodecTrackRenderer ? ((MediaCodecTrackRenderer) renderers[TYPE_AUDIO]).codecCounters : null; this.bandwidthMeter = bandwidthMeter; pushSurface(false); player.prepare(renderers); rendererBuildingState = RENDERER_BUILDING_STATE_BUILT; } /** * Invoked if a {link RendererBuilder} encounters an error. * * @param e Describes the error. */ /* package */ void onRenderersError(Exception e) { if (internalErrorListener != null) { internalErrorListener.onRendererInitializationError(e); } for (Listener listener : listeners) { listener.onError(e); } rendererBuildingState = RENDERER_BUILDING_STATE_IDLE; maybeReportPlayerState(); } public void setPlayWhenReady(boolean playWhenReady) { player.setPlayWhenReady(playWhenReady); } public void seekTo(long positionMs) { player.seekTo(positionMs); } public void release() { rendererBuilder.cancel(); rendererBuildingState = RENDERER_BUILDING_STATE_IDLE; surface = null; player.release(); } public int getPlaybackState() { if (rendererBuildingState == RENDERER_BUILDING_STATE_BUILDING) { return STATE_PREPARING; } int playerState = player.getPlaybackState(); if (rendererBuildingState == RENDERER_BUILDING_STATE_BUILT && playerState == STATE_IDLE) { // This is an edge case where the renderers are built, but are still being passed to the // player's playback thread. return STATE_PREPARING; } return playerState; } @Override public Format getFormat() { return videoFormat; } @Override public BandwidthMeter getBandwidthMeter() { return bandwidthMeter; } @Override public CodecCounters getCodecCounters() { return codecCounters; } @Override public long getCurrentPosition() { return player.getCurrentPosition(); } public long getDuration() { return player.getDuration(); } public int getBufferedPercentage() { return player.getBufferedPercentage(); } public boolean getPlayWhenReady() { return player.getPlayWhenReady(); } /* package */ Looper getPlaybackLooper() { return player.getPlaybackLooper(); } /* package */ Handler getMainHandler() { return mainHandler; } @Override public void onPlayerStateChanged(boolean playWhenReady, int state) { maybeReportPlayerState(); } @Override public void onPlayerError(ExoPlaybackException exception) { rendererBuildingState = RENDERER_BUILDING_STATE_IDLE; for (Listener listener : listeners) { listener.onError(exception); } } @Override public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { for (Listener listener : listeners) { listener.onVideoSizeChanged(width, height, unappliedRotationDegrees, pixelWidthHeightRatio); } } @Override public void onDroppedFrames(int count, long elapsed) { if (infoListener != null) { infoListener.onDroppedFrames(count, elapsed); } } @Override public void onBandwidthSample(int elapsedMs, long bytes, long bitrateEstimate) { if (infoListener != null) { infoListener.onBandwidthSample(elapsedMs, bytes, bitrateEstimate); } } @Override public void onDownstreamFormatChanged(int sourceId, Format format, int trigger, long mediaTimeMs) { if (infoListener == null) { return; } if (sourceId == TYPE_VIDEO) { videoFormat = format; infoListener.onVideoFormatEnabled(format, trigger, mediaTimeMs); } else if (sourceId == TYPE_AUDIO) { infoListener.onAudioFormatEnabled(format, trigger, mediaTimeMs); } } @Override public void onDrmKeysLoaded() { // Do nothing. } @Override public void onDrmSessionManagerError(Exception e) { if (internalErrorListener != null) { internalErrorListener.onDrmSessionManagerError(e); } } @Override public void onDecoderInitializationError(DecoderInitializationException e) { if (internalErrorListener != null) { internalErrorListener.onDecoderInitializationError(e); } } @Override public void onAudioTrackInitializationError(AudioTrack.InitializationException e) { if (internalErrorListener != null) { internalErrorListener.onAudioTrackInitializationError(e); } } @Override public void onAudioTrackWriteError(AudioTrack.WriteException e) { if (internalErrorListener != null) { internalErrorListener.onAudioTrackWriteError(e); } } @Override public void onAudioTrackUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) { if (internalErrorListener != null) { internalErrorListener.onAudioTrackUnderrun(bufferSize, bufferSizeMs, elapsedSinceLastFeedMs); } } @Override public void onCryptoError(CryptoException e) { if (internalErrorListener != null) { internalErrorListener.onCryptoError(e); } } @Override public void onDecoderInitialized(String decoderName, long elapsedRealtimeMs, long initializationDurationMs) { if (infoListener != null) { infoListener.onDecoderInitialized(decoderName, elapsedRealtimeMs, initializationDurationMs); } } @Override public void onLoadError(int sourceId, IOException e) { if (internalErrorListener != null) { internalErrorListener.onLoadError(sourceId, e); } } @Override public void onCues(List cues) { if (captionListener != null && getSelectedTrack(TYPE_TEXT) != TRACK_DISABLED) { captionListener.onCues(cues); } } @Override public void onMetadata(List id3Frames) { if (id3MetadataListener != null && getSelectedTrack(TYPE_METADATA) != TRACK_DISABLED) { id3MetadataListener.onId3Metadata(id3Frames); } } @Override public void onAvailableRangeChanged(int sourceId, TimeRange availableRange) { if (infoListener != null) { infoListener.onAvailableRangeChanged(sourceId, availableRange); } } @Override public void onPlayWhenReadyCommitted() { // Do nothing. } @Override public void onDrawnToSurface(Surface surface) { // Do nothing. } @Override public void onLoadStarted(int sourceId, long length, int type, int trigger, Format format, long mediaStartTimeMs, long mediaEndTimeMs) { if (infoListener != null) { infoListener.onLoadStarted(sourceId, length, type, trigger, format, mediaStartTimeMs, mediaEndTimeMs); } } @Override public void onLoadCompleted(int sourceId, long bytesLoaded, int type, int trigger, Format format, long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs) { if (infoListener != null) { infoListener.onLoadCompleted(sourceId, bytesLoaded, type, trigger, format, mediaStartTimeMs, mediaEndTimeMs, elapsedRealtimeMs, loadDurationMs); } } @Override public void onLoadCanceled(int sourceId, long bytesLoaded) { // Do nothing. } @Override public void onUpstreamDiscarded(int sourceId, long mediaStartTimeMs, long mediaEndTimeMs) { // Do nothing. } private void maybeReportPlayerState() { boolean playWhenReady = player.getPlayWhenReady(); int playbackState = getPlaybackState(); if (lastReportedPlayWhenReady != playWhenReady || lastReportedPlaybackState != playbackState) { for (Listener listener : listeners) { listener.onStateChanged(playWhenReady, playbackState); } lastReportedPlayWhenReady = playWhenReady; lastReportedPlaybackState = playbackState; } } private void pushSurface(boolean blockForSurfacePush) { if (videoRenderer == null) { return; } if (blockForSurfacePush) { player.blockingSendMessage( videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface); } else { player.sendMessage( videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface); } } } ================================================ FILE: android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/demo/player/ExtractorRendererBuilder.java ================================================ /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.exo.demo.player; import android.content.Context; import android.media.AudioManager; import android.media.MediaCodec; import android.net.Uri; import android.os.Handler; import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; import com.google.android.exoplayer.MediaCodecSelector; import com.google.android.exoplayer.MediaCodecVideoTrackRenderer; import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.audio.AudioCapabilities; import tv.danmaku.ijk.media.exo.demo.player.DemoPlayer.RendererBuilder; import com.google.android.exoplayer.extractor.Extractor; import com.google.android.exoplayer.extractor.ExtractorSampleSource; import com.google.android.exoplayer.text.TextTrackRenderer; import com.google.android.exoplayer.upstream.Allocator; import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer.upstream.DefaultAllocator; import com.google.android.exoplayer.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer.upstream.DefaultUriDataSource; /** * A {link RendererBuilder} for streams that can be read using an {link Extractor}. */ public class ExtractorRendererBuilder implements RendererBuilder { private static final int BUFFER_SEGMENT_SIZE = 64 * 1024; private static final int BUFFER_SEGMENT_COUNT = 256; private final Context context; private final String userAgent; private final Uri uri; public ExtractorRendererBuilder(Context context, String userAgent, Uri uri) { this.context = context; this.userAgent = userAgent; this.uri = uri; } @Override public void buildRenderers(DemoPlayer player) { Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE); Handler mainHandler = player.getMainHandler(); // Build the video and audio renderers. DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(mainHandler, null); DataSource dataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri, dataSource, allocator, BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE, mainHandler, player, 0); MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, sampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, mainHandler, player, 50); MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource, MediaCodecSelector.DEFAULT, null, true, mainHandler, player, AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC); TrackRenderer textRenderer = new TextTrackRenderer(sampleSource, player, mainHandler.getLooper()); // Invoke the callback. TrackRenderer[] renderers = new TrackRenderer[DemoPlayer.RENDERER_COUNT]; renderers[DemoPlayer.TYPE_VIDEO] = videoRenderer; renderers[DemoPlayer.TYPE_AUDIO] = audioRenderer; renderers[DemoPlayer.TYPE_TEXT] = textRenderer; player.onRenderers(renderers, bandwidthMeter); } @Override public void cancel() { // Do nothing. } } ================================================ FILE: android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/demo/player/HlsRendererBuilder.java ================================================ /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.exo.demo.player; import android.content.Context; import android.media.AudioManager; import android.media.MediaCodec; import android.os.Handler; import com.google.android.exoplayer.DefaultLoadControl; import com.google.android.exoplayer.LoadControl; import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; import com.google.android.exoplayer.MediaCodecSelector; import com.google.android.exoplayer.MediaCodecVideoTrackRenderer; import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.audio.AudioCapabilities; import tv.danmaku.ijk.media.exo.demo.player.DemoPlayer.RendererBuilder; import com.google.android.exoplayer.hls.DefaultHlsTrackSelector; import com.google.android.exoplayer.hls.HlsChunkSource; import com.google.android.exoplayer.hls.HlsMasterPlaylist; import com.google.android.exoplayer.hls.HlsPlaylist; import com.google.android.exoplayer.hls.HlsPlaylistParser; import com.google.android.exoplayer.hls.HlsSampleSource; import com.google.android.exoplayer.hls.PtsTimestampAdjusterProvider; import com.google.android.exoplayer.metadata.MetadataTrackRenderer; import com.google.android.exoplayer.metadata.id3.Id3Frame; import com.google.android.exoplayer.metadata.id3.Id3Parser; import com.google.android.exoplayer.text.TextTrackRenderer; import com.google.android.exoplayer.text.eia608.Eia608TrackRenderer; import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer.upstream.DefaultAllocator; import com.google.android.exoplayer.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer.upstream.DefaultUriDataSource; import com.google.android.exoplayer.util.ManifestFetcher; import com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback; import java.io.IOException; import java.util.List; /** * A {link RendererBuilder} for HLS. */ public class HlsRendererBuilder implements RendererBuilder { private static final int BUFFER_SEGMENT_SIZE = 64 * 1024; private static final int MAIN_BUFFER_SEGMENTS = 254; private static final int AUDIO_BUFFER_SEGMENTS = 54; private static final int TEXT_BUFFER_SEGMENTS = 2; private final Context context; private final String userAgent; private final String url; private AsyncRendererBuilder currentAsyncBuilder; public HlsRendererBuilder(Context context, String userAgent, String url) { this.context = context; this.userAgent = userAgent; this.url = url; } @Override public void buildRenderers(DemoPlayer player) { currentAsyncBuilder = new AsyncRendererBuilder(context, userAgent, url, player); currentAsyncBuilder.init(); } @Override public void cancel() { if (currentAsyncBuilder != null) { currentAsyncBuilder.cancel(); currentAsyncBuilder = null; } } private static final class AsyncRendererBuilder implements ManifestCallback { private final Context context; private final String userAgent; private final DemoPlayer player; private final ManifestFetcher playlistFetcher; private boolean canceled; public AsyncRendererBuilder(Context context, String userAgent, String url, DemoPlayer player) { this.context = context; this.userAgent = userAgent; this.player = player; HlsPlaylistParser parser = new HlsPlaylistParser(); playlistFetcher = new ManifestFetcher<>(url, new DefaultUriDataSource(context, userAgent), parser); } public void init() { playlistFetcher.singleLoad(player.getMainHandler().getLooper(), this); } public void cancel() { canceled = true; } @Override public void onSingleManifestError(IOException e) { if (canceled) { return; } player.onRenderersError(e); } @Override public void onSingleManifest(HlsPlaylist manifest) { if (canceled) { return; } Handler mainHandler = player.getMainHandler(); LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE)); DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(); PtsTimestampAdjusterProvider timestampAdjusterProvider = new PtsTimestampAdjusterProvider(); boolean haveSubtitles = false; boolean haveAudios = false; if (manifest instanceof HlsMasterPlaylist) { HlsMasterPlaylist masterPlaylist = (HlsMasterPlaylist) manifest; haveSubtitles = !masterPlaylist.subtitles.isEmpty(); haveAudios = !masterPlaylist.audios.isEmpty(); } // Build the video/id3 renderers. DataSource dataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); HlsChunkSource chunkSource = new HlsChunkSource(true /* isMaster */, dataSource, manifest, DefaultHlsTrackSelector.newDefaultInstance(context), bandwidthMeter, timestampAdjusterProvider); HlsSampleSource sampleSource = new HlsSampleSource(chunkSource, loadControl, MAIN_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_VIDEO); MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, sampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, mainHandler, player, 50); MetadataTrackRenderer> id3Renderer = new MetadataTrackRenderer<>( sampleSource, new Id3Parser(), player, mainHandler.getLooper()); // Build the audio renderer. MediaCodecAudioTrackRenderer audioRenderer; if (haveAudios) { DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); HlsChunkSource audioChunkSource = new HlsChunkSource(false /* isMaster */, audioDataSource, manifest, DefaultHlsTrackSelector.newAudioInstance(), bandwidthMeter, timestampAdjusterProvider); HlsSampleSource audioSampleSource = new HlsSampleSource(audioChunkSource, loadControl, AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_AUDIO); audioRenderer = new MediaCodecAudioTrackRenderer( new SampleSource[] {sampleSource, audioSampleSource}, MediaCodecSelector.DEFAULT, null, true, player.getMainHandler(), player, AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC); } else { audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource, MediaCodecSelector.DEFAULT, null, true, player.getMainHandler(), player, AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC); } // Build the text renderer. TrackRenderer textRenderer; if (haveSubtitles) { DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); HlsChunkSource textChunkSource = new HlsChunkSource(false /* isMaster */, textDataSource, manifest, DefaultHlsTrackSelector.newSubtitleInstance(), bandwidthMeter, timestampAdjusterProvider); HlsSampleSource textSampleSource = new HlsSampleSource(textChunkSource, loadControl, TEXT_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_TEXT); textRenderer = new TextTrackRenderer(textSampleSource, player, mainHandler.getLooper()); } else { textRenderer = new Eia608TrackRenderer(sampleSource, player, mainHandler.getLooper()); } TrackRenderer[] renderers = new TrackRenderer[DemoPlayer.RENDERER_COUNT]; renderers[DemoPlayer.TYPE_VIDEO] = videoRenderer; renderers[DemoPlayer.TYPE_AUDIO] = audioRenderer; renderers[DemoPlayer.TYPE_METADATA] = id3Renderer; renderers[DemoPlayer.TYPE_TEXT] = textRenderer; player.onRenderers(renderers, bandwidthMeter); } } } ================================================ FILE: android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/demo/player/SmoothStreamingRendererBuilder.java ================================================ /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.exo.demo.player; import android.content.Context; import android.media.AudioManager; import android.media.MediaCodec; import android.os.Handler; import com.google.android.exoplayer.DefaultLoadControl; import com.google.android.exoplayer.LoadControl; import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; import com.google.android.exoplayer.MediaCodecSelector; import com.google.android.exoplayer.MediaCodecVideoTrackRenderer; import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.audio.AudioCapabilities; import com.google.android.exoplayer.chunk.ChunkSampleSource; import com.google.android.exoplayer.chunk.ChunkSource; import com.google.android.exoplayer.chunk.FormatEvaluator.AdaptiveEvaluator; import tv.danmaku.ijk.media.exo.demo.player.DemoPlayer.RendererBuilder; import com.google.android.exoplayer.drm.DrmSessionManager; import com.google.android.exoplayer.drm.FrameworkMediaCrypto; import com.google.android.exoplayer.drm.MediaDrmCallback; import com.google.android.exoplayer.drm.StreamingDrmSessionManager; import com.google.android.exoplayer.drm.UnsupportedDrmException; import com.google.android.exoplayer.smoothstreaming.DefaultSmoothStreamingTrackSelector; import com.google.android.exoplayer.smoothstreaming.SmoothStreamingChunkSource; import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest; import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifestParser; import com.google.android.exoplayer.text.TextTrackRenderer; import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer.upstream.DefaultAllocator; import com.google.android.exoplayer.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer.upstream.DefaultHttpDataSource; import com.google.android.exoplayer.upstream.DefaultUriDataSource; import com.google.android.exoplayer.util.ManifestFetcher; import com.google.android.exoplayer.util.Util; import java.io.IOException; /** * A {link RendererBuilder} for SmoothStreaming. */ public class SmoothStreamingRendererBuilder implements RendererBuilder { private static final int BUFFER_SEGMENT_SIZE = 64 * 1024; private static final int VIDEO_BUFFER_SEGMENTS = 200; private static final int AUDIO_BUFFER_SEGMENTS = 54; private static final int TEXT_BUFFER_SEGMENTS = 2; private static final int LIVE_EDGE_LATENCY_MS = 30000; private final Context context; private final String userAgent; private final String url; private final MediaDrmCallback drmCallback; private AsyncRendererBuilder currentAsyncBuilder; public SmoothStreamingRendererBuilder(Context context, String userAgent, String url, MediaDrmCallback drmCallback) { this.context = context; this.userAgent = userAgent; this.url = Util.toLowerInvariant(url).endsWith("/manifest") ? url : url + "/Manifest"; this.drmCallback = drmCallback; } @Override public void buildRenderers(DemoPlayer player) { currentAsyncBuilder = new AsyncRendererBuilder(context, userAgent, url, drmCallback, player); currentAsyncBuilder.init(); } @Override public void cancel() { if (currentAsyncBuilder != null) { currentAsyncBuilder.cancel(); currentAsyncBuilder = null; } } private static final class AsyncRendererBuilder implements ManifestFetcher.ManifestCallback { private final Context context; private final String userAgent; private final MediaDrmCallback drmCallback; private final DemoPlayer player; private final ManifestFetcher manifestFetcher; private boolean canceled; public AsyncRendererBuilder(Context context, String userAgent, String url, MediaDrmCallback drmCallback, DemoPlayer player) { this.context = context; this.userAgent = userAgent; this.drmCallback = drmCallback; this.player = player; SmoothStreamingManifestParser parser = new SmoothStreamingManifestParser(); manifestFetcher = new ManifestFetcher<>(url, new DefaultHttpDataSource(userAgent, null), parser); } public void init() { manifestFetcher.singleLoad(player.getMainHandler().getLooper(), this); } public void cancel() { canceled = true; } @Override public void onSingleManifestError(IOException exception) { if (canceled) { return; } player.onRenderersError(exception); } @Override public void onSingleManifest(SmoothStreamingManifest manifest) { if (canceled) { return; } Handler mainHandler = player.getMainHandler(); LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE)); DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(mainHandler, player); // Check drm support if necessary. DrmSessionManager drmSessionManager = null; if (manifest.protectionElement != null) { if (Util.SDK_INT < 18) { player.onRenderersError( new UnsupportedDrmException(UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME)); return; } try { drmSessionManager = StreamingDrmSessionManager.newFrameworkInstance( manifest.protectionElement.uuid, player.getPlaybackLooper(), drmCallback, null, player.getMainHandler(), player); } catch (UnsupportedDrmException e) { player.onRenderersError(e); return; } } // Build the video renderer. DataSource videoDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); ChunkSource videoChunkSource = new SmoothStreamingChunkSource(manifestFetcher, DefaultSmoothStreamingTrackSelector.newVideoInstance(context, true, false), videoDataSource, new AdaptiveEvaluator(bandwidthMeter), LIVE_EDGE_LATENCY_MS); ChunkSampleSource videoSampleSource = new ChunkSampleSource(videoChunkSource, loadControl, VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_VIDEO); TrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, videoSampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, drmSessionManager, true, mainHandler, player, 50); // Build the audio renderer. DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); ChunkSource audioChunkSource = new SmoothStreamingChunkSource(manifestFetcher, DefaultSmoothStreamingTrackSelector.newAudioInstance(), audioDataSource, null, LIVE_EDGE_LATENCY_MS); ChunkSampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource, loadControl, AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_AUDIO); TrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(audioSampleSource, MediaCodecSelector.DEFAULT, drmSessionManager, true, mainHandler, player, AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC); // Build the text renderer. DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); ChunkSource textChunkSource = new SmoothStreamingChunkSource(manifestFetcher, DefaultSmoothStreamingTrackSelector.newTextInstance(), textDataSource, null, LIVE_EDGE_LATENCY_MS); ChunkSampleSource textSampleSource = new ChunkSampleSource(textChunkSource, loadControl, TEXT_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_TEXT); TrackRenderer textRenderer = new TextTrackRenderer(textSampleSource, player, mainHandler.getLooper()); // Invoke the callback. TrackRenderer[] renderers = new TrackRenderer[DemoPlayer.RENDERER_COUNT]; renderers[DemoPlayer.TYPE_VIDEO] = videoRenderer; renderers[DemoPlayer.TYPE_AUDIO] = audioRenderer; renderers[DemoPlayer.TYPE_TEXT] = textRenderer; player.onRenderers(renderers, bandwidthMeter); } } } ================================================ FILE: android/ijkplayer/ijkplayer-exo/src/main/res/values/strings.xml ================================================ ijkplayer-exo ================================================ FILE: android/ijkplayer/ijkplayer-java/.gitignore ================================================ /build ================================================ FILE: android/ijkplayer/ijkplayer-java/build.gradle ================================================ apply plugin: 'com.android.library' android { // http://tools.android.com/tech-docs/new-build-system/tips //noinspection GroovyAssignabilityCheck compileSdkVersion rootProject.ext.compileSdkVersion //noinspection GroovyAssignabilityCheck buildToolsVersion rootProject.ext.buildToolsVersion lintOptions { abortOnError false } defaultConfig { minSdkVersion 9 targetSdkVersion rootProject.ext.targetSdkVersion } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) } apply from: new File(rootProject.projectDir, "tools/gradle-on-demand.gradle"); ================================================ FILE: android/ijkplayer/ijkplayer-java/gradle.properties ================================================ POM_NAME=ijkplayer-java POM_ARTIFACT_ID=ijkplayer-java POM_PACKAGING=aar ================================================ FILE: android/ijkplayer/ijkplayer-java/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /opt/android/ADK/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: android/ijkplayer/ijkplayer-java/src/androidTest/java/tv/danmaku/ijk/media/player/ApplicationTest.java ================================================ package tv.danmaku.ijk.media.player; import android.app.Application; import android.test.ApplicationTestCase; /** * Testing Fundamentals */ public class ApplicationTest extends ApplicationTestCase { public ApplicationTest() { super(Application.class); } } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/.classpath ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/.project ================================================ ijkplayer-java com.android.ide.eclipse.adt.ResourceManagerBuilder com.android.ide.eclipse.adt.PreCompilerBuilder org.eclipse.jdt.core.javabuilder com.android.ide.eclipse.adt.ApkBuilder com.android.ide.eclipse.adt.AndroidNature org.eclipse.jdt.core.javanature ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/.settings/org.eclipse.jdt.core.prefs ================================================ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.compliance=1.6 org.eclipse.jdt.core.compiler.source=1.6 ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/AndroidManifest.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/AbstractMediaPlayer.java ================================================ /* * Copyright (C) 2013-2014 Bilibili * Copyright (C) 2013-2014 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player; import tv.danmaku.ijk.media.player.misc.IMediaDataSource; @SuppressWarnings("WeakerAccess") public abstract class AbstractMediaPlayer implements IMediaPlayer { private OnPreparedListener mOnPreparedListener; private OnCompletionListener mOnCompletionListener; private OnBufferingUpdateListener mOnBufferingUpdateListener; private OnSeekCompleteListener mOnSeekCompleteListener; private OnVideoSizeChangedListener mOnVideoSizeChangedListener; private OnErrorListener mOnErrorListener; private OnInfoListener mOnInfoListener; private OnTimedTextListener mOnTimedTextListener; public final void setOnPreparedListener(OnPreparedListener listener) { mOnPreparedListener = listener; } public final void setOnCompletionListener(OnCompletionListener listener) { mOnCompletionListener = listener; } public final void setOnBufferingUpdateListener( OnBufferingUpdateListener listener) { mOnBufferingUpdateListener = listener; } public final void setOnSeekCompleteListener(OnSeekCompleteListener listener) { mOnSeekCompleteListener = listener; } public final void setOnVideoSizeChangedListener( OnVideoSizeChangedListener listener) { mOnVideoSizeChangedListener = listener; } public final void setOnErrorListener(OnErrorListener listener) { mOnErrorListener = listener; } public final void setOnInfoListener(OnInfoListener listener) { mOnInfoListener = listener; } public final void setOnTimedTextListener(OnTimedTextListener listener) { mOnTimedTextListener = listener; } public void resetListeners() { mOnPreparedListener = null; mOnBufferingUpdateListener = null; mOnCompletionListener = null; mOnSeekCompleteListener = null; mOnVideoSizeChangedListener = null; mOnErrorListener = null; mOnInfoListener = null; mOnTimedTextListener = null; } protected final void notifyOnPrepared() { if (mOnPreparedListener != null) mOnPreparedListener.onPrepared(this); } protected final void notifyOnCompletion() { if (mOnCompletionListener != null) mOnCompletionListener.onCompletion(this); } protected final void notifyOnBufferingUpdate(int percent) { if (mOnBufferingUpdateListener != null) mOnBufferingUpdateListener.onBufferingUpdate(this, percent); } protected final void notifyOnSeekComplete() { if (mOnSeekCompleteListener != null) mOnSeekCompleteListener.onSeekComplete(this); } protected final void notifyOnVideoSizeChanged(int width, int height, int sarNum, int sarDen) { if (mOnVideoSizeChangedListener != null) mOnVideoSizeChangedListener.onVideoSizeChanged(this, width, height, sarNum, sarDen); } protected final boolean notifyOnError(int what, int extra) { return mOnErrorListener != null && mOnErrorListener.onError(this, what, extra); } protected final boolean notifyOnInfo(int what, int extra) { return mOnInfoListener != null && mOnInfoListener.onInfo(this, what, extra); } protected final void notifyOnTimedText(IjkTimedText text) { if (mOnTimedTextListener != null) mOnTimedTextListener.onTimedText(this, text); } public void setDataSource(IMediaDataSource mediaDataSource) { throw new UnsupportedOperationException(); } } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/AndroidMediaPlayer.java ================================================ /* * Copyright (C) 2006 Bilibili * Copyright (C) 2006 The Android Open Source Project * Copyright (C) 2013 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player; import android.annotation.TargetApi; import android.content.Context; import android.media.AudioManager; import android.media.MediaDataSource; import android.media.MediaPlayer; import android.media.TimedText; import android.net.Uri; import android.os.Build; import android.text.TextUtils; import android.view.Surface; import android.view.SurfaceHolder; import java.io.FileDescriptor; import java.io.IOException; import java.lang.ref.WeakReference; import java.util.Map; import tv.danmaku.ijk.media.player.misc.AndroidTrackInfo; import tv.danmaku.ijk.media.player.misc.IMediaDataSource; import tv.danmaku.ijk.media.player.misc.ITrackInfo; import tv.danmaku.ijk.media.player.pragma.DebugLog; public class AndroidMediaPlayer extends AbstractMediaPlayer { private final MediaPlayer mInternalMediaPlayer; private final AndroidMediaPlayerListenerHolder mInternalListenerAdapter; private String mDataSource; private MediaDataSource mMediaDataSource; private final Object mInitLock = new Object(); private boolean mIsReleased; private static MediaInfo sMediaInfo; public AndroidMediaPlayer() { synchronized (mInitLock) { mInternalMediaPlayer = new MediaPlayer(); } mInternalMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mInternalListenerAdapter = new AndroidMediaPlayerListenerHolder(this); attachInternalListeners(); } public MediaPlayer getInternalMediaPlayer() { return mInternalMediaPlayer; } @Override public void setDisplay(SurfaceHolder sh) { synchronized (mInitLock) { if (!mIsReleased) { mInternalMediaPlayer.setDisplay(sh); } } } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Override public void setSurface(Surface surface) { mInternalMediaPlayer.setSurface(surface); } @Override public void setDataSource(Context context, Uri uri) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { mInternalMediaPlayer.setDataSource(context, uri); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Override public void setDataSource(Context context, Uri uri, Map headers) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { mInternalMediaPlayer.setDataSource(context, uri, headers); } @Override public void setDataSource(FileDescriptor fd) throws IOException, IllegalArgumentException, IllegalStateException { mInternalMediaPlayer.setDataSource(fd); } @Override public void setDataSource(String path) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { mDataSource = path; Uri uri = Uri.parse(path); String scheme = uri.getScheme(); if (!TextUtils.isEmpty(scheme) && scheme.equalsIgnoreCase("file")) { mInternalMediaPlayer.setDataSource(uri.getPath()); } else { mInternalMediaPlayer.setDataSource(path); } } @TargetApi(Build.VERSION_CODES.M) @Override public void setDataSource(IMediaDataSource mediaDataSource) { releaseMediaDataSource(); mMediaDataSource = new MediaDataSourceProxy(mediaDataSource); mInternalMediaPlayer.setDataSource(mMediaDataSource); } @TargetApi(Build.VERSION_CODES.M) private static class MediaDataSourceProxy extends MediaDataSource { private final IMediaDataSource mMediaDataSource; public MediaDataSourceProxy(IMediaDataSource mediaDataSource) { mMediaDataSource = mediaDataSource; } @Override public int readAt(long position, byte[] buffer, int offset, int size) throws IOException { return mMediaDataSource.readAt(position, buffer, offset, size); } @Override public long getSize() throws IOException { return mMediaDataSource.getSize(); } @Override public void close() throws IOException { mMediaDataSource.close(); } } @Override public String getDataSource() { return mDataSource; } private void releaseMediaDataSource() { if (mMediaDataSource != null) { try { mMediaDataSource.close(); } catch (IOException e) { e.printStackTrace(); } mMediaDataSource = null; } } @Override public void prepareAsync() throws IllegalStateException { mInternalMediaPlayer.prepareAsync(); } @Override public void start() throws IllegalStateException { mInternalMediaPlayer.start(); } @Override public void stop() throws IllegalStateException { mInternalMediaPlayer.stop(); } @Override public void pause() throws IllegalStateException { mInternalMediaPlayer.pause(); } @Override public void setScreenOnWhilePlaying(boolean screenOn) { mInternalMediaPlayer.setScreenOnWhilePlaying(screenOn); } @Override public ITrackInfo[] getTrackInfo() { return AndroidTrackInfo.fromMediaPlayer(mInternalMediaPlayer); } @Override public int getVideoWidth() { return mInternalMediaPlayer.getVideoWidth(); } @Override public int getVideoHeight() { return mInternalMediaPlayer.getVideoHeight(); } @Override public int getVideoSarNum() { return 1; } @Override public int getVideoSarDen() { return 1; } @Override public boolean isPlaying() { try { return mInternalMediaPlayer.isPlaying(); } catch (IllegalStateException e) { DebugLog.printStackTrace(e); return false; } } @Override public void seekTo(long msec) throws IllegalStateException { mInternalMediaPlayer.seekTo((int) msec); } @Override public long getCurrentPosition() { try { return mInternalMediaPlayer.getCurrentPosition(); } catch (IllegalStateException e) { DebugLog.printStackTrace(e); return 0; } } @Override public long getDuration() { try { return mInternalMediaPlayer.getDuration(); } catch (IllegalStateException e) { DebugLog.printStackTrace(e); return 0; } } @Override public void release() { mIsReleased = true; mInternalMediaPlayer.release(); releaseMediaDataSource(); resetListeners(); attachInternalListeners(); } @Override public void reset() { try { mInternalMediaPlayer.reset(); } catch (IllegalStateException e) { DebugLog.printStackTrace(e); } releaseMediaDataSource(); resetListeners(); attachInternalListeners(); } @Override public void setLooping(boolean looping) { mInternalMediaPlayer.setLooping(looping); } @Override public boolean isLooping() { return mInternalMediaPlayer.isLooping(); } @Override public void setVolume(float leftVolume, float rightVolume) { mInternalMediaPlayer.setVolume(leftVolume, rightVolume); } @Override public int getAudioSessionId() { return mInternalMediaPlayer.getAudioSessionId(); } @Override public MediaInfo getMediaInfo() { if (sMediaInfo == null) { MediaInfo module = new MediaInfo(); module.mVideoDecoder = "android"; module.mVideoDecoderImpl = "HW"; module.mAudioDecoder = "android"; module.mAudioDecoderImpl = "HW"; sMediaInfo = module; } return sMediaInfo; } @Override public void setLogEnabled(boolean enable) { } @Override public boolean isPlayable() { return true; } /*-------------------- * misc */ @Override public void setWakeMode(Context context, int mode) { mInternalMediaPlayer.setWakeMode(context, mode); } @Override public void setAudioStreamType(int streamtype) { mInternalMediaPlayer.setAudioStreamType(streamtype); } @Override public void setKeepInBackground(boolean keepInBackground) { } /*-------------------- * Listeners adapter */ private void attachInternalListeners() { mInternalMediaPlayer.setOnPreparedListener(mInternalListenerAdapter); mInternalMediaPlayer .setOnBufferingUpdateListener(mInternalListenerAdapter); mInternalMediaPlayer.setOnCompletionListener(mInternalListenerAdapter); mInternalMediaPlayer .setOnSeekCompleteListener(mInternalListenerAdapter); mInternalMediaPlayer .setOnVideoSizeChangedListener(mInternalListenerAdapter); mInternalMediaPlayer.setOnErrorListener(mInternalListenerAdapter); mInternalMediaPlayer.setOnInfoListener(mInternalListenerAdapter); mInternalMediaPlayer.setOnTimedTextListener(mInternalListenerAdapter); } private class AndroidMediaPlayerListenerHolder implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnSeekCompleteListener, MediaPlayer.OnVideoSizeChangedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnInfoListener, MediaPlayer.OnTimedTextListener { public final WeakReference mWeakMediaPlayer; public AndroidMediaPlayerListenerHolder(AndroidMediaPlayer mp) { mWeakMediaPlayer = new WeakReference(mp); } @Override public boolean onInfo(MediaPlayer mp, int what, int extra) { AndroidMediaPlayer self = mWeakMediaPlayer.get(); return self != null && notifyOnInfo(what, extra); } @Override public boolean onError(MediaPlayer mp, int what, int extra) { AndroidMediaPlayer self = mWeakMediaPlayer.get(); return self != null && notifyOnError(what, extra); } @Override public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { AndroidMediaPlayer self = mWeakMediaPlayer.get(); if (self == null) return; notifyOnVideoSizeChanged(width, height, 1, 1); } @Override public void onSeekComplete(MediaPlayer mp) { AndroidMediaPlayer self = mWeakMediaPlayer.get(); if (self == null) return; notifyOnSeekComplete(); } @Override public void onBufferingUpdate(MediaPlayer mp, int percent) { AndroidMediaPlayer self = mWeakMediaPlayer.get(); if (self == null) return; notifyOnBufferingUpdate(percent); } @Override public void onCompletion(MediaPlayer mp) { AndroidMediaPlayer self = mWeakMediaPlayer.get(); if (self == null) return; notifyOnCompletion(); } @Override public void onPrepared(MediaPlayer mp) { AndroidMediaPlayer self = mWeakMediaPlayer.get(); if (self == null) return; notifyOnPrepared(); } @Override public void onTimedText(MediaPlayer mp, TimedText text) { AndroidMediaPlayer self = mWeakMediaPlayer.get(); if (self == null) return; IjkTimedText ijkText = null; if (text != null) { ijkText = new IjkTimedText(text.getBounds(), text.getText()); } notifyOnTimedText(ijkText); } } } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IMediaPlayer.java ================================================ /* * Copyright (C) 2013-2014 Bilibili * Copyright (C) 2013-2014 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player; import android.annotation.TargetApi; import android.content.Context; import android.net.Uri; import android.os.Build; import android.view.Surface; import android.view.SurfaceHolder; import java.io.FileDescriptor; import java.io.IOException; import java.util.Map; import tv.danmaku.ijk.media.player.misc.IMediaDataSource; import tv.danmaku.ijk.media.player.misc.ITrackInfo; public interface IMediaPlayer { /* * Do not change these values without updating their counterparts in native */ int MEDIA_INFO_UNKNOWN = 1; int MEDIA_INFO_STARTED_AS_NEXT = 2; int MEDIA_INFO_VIDEO_RENDERING_START = 3; int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; int MEDIA_INFO_BUFFERING_START = 701; int MEDIA_INFO_BUFFERING_END = 702; int MEDIA_INFO_NETWORK_BANDWIDTH = 703; int MEDIA_INFO_BAD_INTERLEAVING = 800; int MEDIA_INFO_NOT_SEEKABLE = 801; int MEDIA_INFO_METADATA_UPDATE = 802; int MEDIA_INFO_TIMED_TEXT_ERROR = 900; int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901; int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902; int MEDIA_INFO_VIDEO_ROTATION_CHANGED = 10001; int MEDIA_INFO_AUDIO_RENDERING_START = 10002; int MEDIA_INFO_AUDIO_DECODED_START = 10003; int MEDIA_INFO_VIDEO_DECODED_START = 10004; int MEDIA_INFO_OPEN_INPUT = 10005; int MEDIA_INFO_FIND_STREAM_INFO = 10006; int MEDIA_INFO_COMPONENT_OPEN = 10007; int MEDIA_INFO_VIDEO_SEEK_RENDERING_START = 10008; int MEDIA_INFO_AUDIO_SEEK_RENDERING_START = 10009; int MEDIA_INFO_MEDIA_ACCURATE_SEEK_COMPLETE = 10100; int MEDIA_ERROR_UNKNOWN = 1; int MEDIA_ERROR_SERVER_DIED = 100; int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200; int MEDIA_ERROR_IO = -1004; int MEDIA_ERROR_MALFORMED = -1007; int MEDIA_ERROR_UNSUPPORTED = -1010; int MEDIA_ERROR_TIMED_OUT = -110; void setDisplay(SurfaceHolder sh); void setDataSource(Context context, Uri uri) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException; @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) void setDataSource(Context context, Uri uri, Map headers) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException; void setDataSource(FileDescriptor fd) throws IOException, IllegalArgumentException, IllegalStateException; void setDataSource(String path) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException; String getDataSource(); void prepareAsync() throws IllegalStateException; void start() throws IllegalStateException; void stop() throws IllegalStateException; void pause() throws IllegalStateException; void setScreenOnWhilePlaying(boolean screenOn); int getVideoWidth(); int getVideoHeight(); boolean isPlaying(); void seekTo(long msec) throws IllegalStateException; long getCurrentPosition(); long getDuration(); void release(); void reset(); void setVolume(float leftVolume, float rightVolume); int getAudioSessionId(); MediaInfo getMediaInfo(); @SuppressWarnings("EmptyMethod") @Deprecated void setLogEnabled(boolean enable); @Deprecated boolean isPlayable(); void setOnPreparedListener(OnPreparedListener listener); void setOnCompletionListener(OnCompletionListener listener); void setOnBufferingUpdateListener( OnBufferingUpdateListener listener); void setOnSeekCompleteListener( OnSeekCompleteListener listener); void setOnVideoSizeChangedListener( OnVideoSizeChangedListener listener); void setOnErrorListener(OnErrorListener listener); void setOnInfoListener(OnInfoListener listener); void setOnTimedTextListener(OnTimedTextListener listener); /*-------------------- * Listeners */ interface OnPreparedListener { void onPrepared(IMediaPlayer mp); } interface OnCompletionListener { void onCompletion(IMediaPlayer mp); } interface OnBufferingUpdateListener { void onBufferingUpdate(IMediaPlayer mp, int percent); } interface OnSeekCompleteListener { void onSeekComplete(IMediaPlayer mp); } interface OnVideoSizeChangedListener { void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sar_num, int sar_den); } interface OnErrorListener { boolean onError(IMediaPlayer mp, int what, int extra); } interface OnInfoListener { boolean onInfo(IMediaPlayer mp, int what, int extra); } interface OnTimedTextListener { void onTimedText(IMediaPlayer mp, IjkTimedText text); } /*-------------------- * Optional */ void setAudioStreamType(int streamtype); @Deprecated void setKeepInBackground(boolean keepInBackground); int getVideoSarNum(); int getVideoSarDen(); @Deprecated void setWakeMode(Context context, int mode); void setLooping(boolean looping); boolean isLooping(); /*-------------------- * AndroidMediaPlayer: JELLY_BEAN */ ITrackInfo[] getTrackInfo(); /*-------------------- * AndroidMediaPlayer: ICE_CREAM_SANDWICH: */ void setSurface(Surface surface); /*-------------------- * AndroidMediaPlayer: M: */ void setDataSource(IMediaDataSource mediaDataSource); } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ISurfaceTextureHolder.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player; import android.graphics.SurfaceTexture; public interface ISurfaceTextureHolder { void setSurfaceTexture(SurfaceTexture surfaceTexture); SurfaceTexture getSurfaceTexture(); void setSurfaceTextureHost(ISurfaceTextureHost surfaceTextureHost); } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ISurfaceTextureHost.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player; import android.graphics.SurfaceTexture; public interface ISurfaceTextureHost { void releaseSurfaceTexture(SurfaceTexture surfaceTexture); } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkLibLoader.java ================================================ /* * Copyright (C) 2013-2014 Bilibili * Copyright (C) 2013-2014 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player; public interface IjkLibLoader { void loadLibrary(String libName) throws UnsatisfiedLinkError, SecurityException; } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaCodecInfo.java ================================================ package tv.danmaku.ijk.media.player; import android.annotation.TargetApi; import android.media.MediaCodecInfo; import android.media.MediaCodecInfo.CodecCapabilities; import android.media.MediaCodecInfo.CodecProfileLevel; import android.os.Build; import android.text.TextUtils; import android.util.Log; import java.util.Locale; import java.util.Map; import java.util.TreeMap; public class IjkMediaCodecInfo { private final static String TAG = "IjkMediaCodecInfo"; public static final int RANK_MAX = 1000; public static final int RANK_TESTED = 800; public static final int RANK_ACCEPTABLE = 700; public static final int RANK_LAST_CHANCE = 600; public static final int RANK_SECURE = 300; public static final int RANK_SOFTWARE = 200; public static final int RANK_NON_STANDARD = 100; public static final int RANK_NO_SENSE = 0; public MediaCodecInfo mCodecInfo; public int mRank = 0; public String mMimeType; private static Map sKnownCodecList; private static synchronized Map getKnownCodecList() { if (sKnownCodecList != null) return sKnownCodecList; sKnownCodecList = new TreeMap( String.CASE_INSENSITIVE_ORDER); // ----- Nvidia ----- // Tegra3 // Nexus 7 (2012) // Tegra K1 // Nexus 9 sKnownCodecList.put("OMX.Nvidia.h264.decode", RANK_TESTED); sKnownCodecList.put("OMX.Nvidia.h264.decode.secure", RANK_SECURE); // ----- Intel ----- // Atom Z3735 // Teclast X98 Air sKnownCodecList.put("OMX.Intel.hw_vd.h264", RANK_TESTED + 1); // Atom Z2560 // Dell Venue 7 3730 sKnownCodecList.put("OMX.Intel.VideoDecoder.AVC", RANK_TESTED); // ----- Qualcomm ----- // MSM8260 // Xiaomi MI 1S sKnownCodecList.put("OMX.qcom.video.decoder.avc", RANK_TESTED); sKnownCodecList.put("OMX.ittiam.video.decoder.avc", RANK_NO_SENSE); // ----- Samsung ----- // Exynos 3110 // Nexus S sKnownCodecList.put("OMX.SEC.avc.dec", RANK_TESTED); sKnownCodecList.put("OMX.SEC.AVC.Decoder", RANK_TESTED - 1); // OMX.SEC.avcdec doesn't reorder output pictures on GT-9100 sKnownCodecList.put("OMX.SEC.avcdec", RANK_TESTED - 2); sKnownCodecList.put("OMX.SEC.avc.sw.dec", RANK_SOFTWARE); // Exynos 5 ? sKnownCodecList.put("OMX.Exynos.avc.dec", RANK_TESTED); sKnownCodecList.put("OMX.Exynos.AVC.Decoder", RANK_TESTED - 1); // ------ Huawei hisilicon ------ // Kirin 910, Mali 450 MP // Huawei HONOR 3C (H30-L01) sKnownCodecList.put("OMX.k3.video.decoder.avc", RANK_TESTED); // Kirin 920, Mali T624 // Huawei HONOR 6 sKnownCodecList.put("OMX.IMG.MSVDX.Decoder.AVC", RANK_TESTED); // ----- TI ----- // TI OMAP4460 // Galaxy Nexus sKnownCodecList.put("OMX.TI.DUCATI1.VIDEO.DECODER", RANK_TESTED); // ------ RockChip ------ // Youku TVBox sKnownCodecList.put("OMX.rk.video_decoder.avc", RANK_TESTED); // ------ AMLogic ----- // MiBox1, 1s, 2 sKnownCodecList.put("OMX.amlogic.avc.decoder.awesome", RANK_TESTED); // ------ Marvell ------ // Lenovo A788t sKnownCodecList.put("OMX.MARVELL.VIDEO.HW.CODA7542DECODER", RANK_TESTED); sKnownCodecList.put("OMX.MARVELL.VIDEO.H264DECODER", RANK_SOFTWARE); // ----- TODO: need test ----- sKnownCodecList.remove("OMX.Action.Video.Decoder"); sKnownCodecList.remove("OMX.allwinner.video.decoder.avc"); sKnownCodecList.remove("OMX.BRCM.vc4.decoder.avc"); sKnownCodecList.remove("OMX.brcm.video.h264.hw.decoder"); sKnownCodecList.remove("OMX.brcm.video.h264.decoder"); sKnownCodecList.remove("OMX.cosmo.video.decoder.avc"); sKnownCodecList.remove("OMX.duos.h264.decoder"); sKnownCodecList.remove("OMX.hantro.81x0.video.decoder"); sKnownCodecList.remove("OMX.hantro.G1.video.decoder"); sKnownCodecList.remove("OMX.hisi.video.decoder"); sKnownCodecList.remove("OMX.LG.decoder.video.avc"); sKnownCodecList.remove("OMX.MS.AVC.Decoder"); sKnownCodecList.remove("OMX.RENESAS.VIDEO.DECODER.H264"); sKnownCodecList.remove("OMX.RTK.video.decoder"); sKnownCodecList.remove("OMX.sprd.h264.decoder"); sKnownCodecList.remove("OMX.ST.VFM.H264Dec"); sKnownCodecList.remove("OMX.vpu.video_decoder.avc"); sKnownCodecList.remove("OMX.WMT.decoder.avc"); // Really ? sKnownCodecList.remove("OMX.bluestacks.hw.decoder"); // --------------- // Useless codec // ----- google ----- sKnownCodecList.put("OMX.google.h264.decoder", RANK_SOFTWARE); sKnownCodecList.put("OMX.google.h264.lc.decoder", RANK_SOFTWARE); // ----- huawei k920 ----- sKnownCodecList.put("OMX.k3.ffmpeg.decoder", RANK_SOFTWARE); sKnownCodecList.put("OMX.ffmpeg.video.decoder", RANK_SOFTWARE); // ----- unknown ----- sKnownCodecList.put("OMX.sprd.soft.h264.decoder", RANK_SOFTWARE); return sKnownCodecList; } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public static IjkMediaCodecInfo setupCandidate(MediaCodecInfo codecInfo, String mimeType) { if (codecInfo == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) return null; String name = codecInfo.getName(); if (TextUtils.isEmpty(name)) return null; name = name.toLowerCase(Locale.US); int rank = RANK_NO_SENSE; if (!name.startsWith("omx.")) { rank = RANK_NON_STANDARD; } else if (name.startsWith("omx.pv")) { rank = RANK_SOFTWARE; } else if (name.startsWith("omx.google.")) { rank = RANK_SOFTWARE; } else if (name.startsWith("omx.ffmpeg.")) { rank = RANK_SOFTWARE; } else if (name.startsWith("omx.k3.ffmpeg.")) { rank = RANK_SOFTWARE; } else if (name.startsWith("omx.avcodec.")) { rank = RANK_SOFTWARE; } else if (name.startsWith("omx.ittiam.")) { // unknown codec in qualcomm SoC rank = RANK_NO_SENSE; } else if (name.startsWith("omx.mtk.")) { // 1. MTK only works on 4.3 and above // 2. MTK works on MIUI 6 (4.2.1) if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) rank = RANK_NO_SENSE; else rank = RANK_TESTED; } else { Integer knownRank = getKnownCodecList().get(name); if (knownRank != null) { rank = knownRank; } else { try { CodecCapabilities cap = codecInfo .getCapabilitiesForType(mimeType); if (cap != null) rank = RANK_ACCEPTABLE; else rank = RANK_LAST_CHANCE; } catch (Throwable e) { rank = RANK_LAST_CHANCE; } } } IjkMediaCodecInfo candidate = new IjkMediaCodecInfo(); candidate.mCodecInfo = codecInfo; candidate.mRank = rank; candidate.mMimeType = mimeType; return candidate; } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public void dumpProfileLevels(String mimeType) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) return; try { CodecCapabilities caps = mCodecInfo .getCapabilitiesForType(mimeType); int maxProfile = 0; int maxLevel = 0; if (caps != null) { if (caps.profileLevels != null) { for (CodecProfileLevel profileLevel : caps.profileLevels) { if (profileLevel == null) continue; maxProfile = Math.max(maxProfile, profileLevel.profile); maxLevel = Math.max(maxLevel, profileLevel.level); } } } Log.i(TAG, String.format(Locale.US, "%s", getProfileLevelName(maxProfile, maxLevel))); } catch (Throwable e) { Log.i(TAG, "profile-level: exception"); } } public static String getProfileLevelName(int profile, int level) { return String.format(Locale.US, " %s Profile Level %s (%d,%d)", getProfileName(profile), getLevelName(level), profile, level); } public static String getProfileName(int profile) { switch (profile) { case CodecProfileLevel.AVCProfileBaseline: return "Baseline"; case CodecProfileLevel.AVCProfileMain: return "Main"; case CodecProfileLevel.AVCProfileExtended: return "Extends"; case CodecProfileLevel.AVCProfileHigh: return "High"; case CodecProfileLevel.AVCProfileHigh10: return "High10"; case CodecProfileLevel.AVCProfileHigh422: return "High422"; case CodecProfileLevel.AVCProfileHigh444: return "High444"; default: return "Unknown"; } } public static String getLevelName(int level) { switch (level) { case CodecProfileLevel.AVCLevel1: return "1"; case CodecProfileLevel.AVCLevel1b: return "1b"; case CodecProfileLevel.AVCLevel11: return "11"; case CodecProfileLevel.AVCLevel12: return "12"; case CodecProfileLevel.AVCLevel13: return "13"; case CodecProfileLevel.AVCLevel2: return "2"; case CodecProfileLevel.AVCLevel21: return "21"; case CodecProfileLevel.AVCLevel22: return "22"; case CodecProfileLevel.AVCLevel3: return "3"; case CodecProfileLevel.AVCLevel31: return "31"; case CodecProfileLevel.AVCLevel32: return "32"; case CodecProfileLevel.AVCLevel4: return "4"; case CodecProfileLevel.AVCLevel41: return "41"; case CodecProfileLevel.AVCLevel42: return "42"; case CodecProfileLevel.AVCLevel5: return "5"; case CodecProfileLevel.AVCLevel51: return "51"; case 65536: // CodecProfileLevel.AVCLevel52: return "52"; default: return "0"; } } } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaMeta.java ================================================ package tv.danmaku.ijk.media.player; import android.os.Bundle; import android.text.TextUtils; import java.util.ArrayList; import java.util.Locale; @SuppressWarnings("SameParameterValue") public class IjkMediaMeta { // media meta public static final String IJKM_KEY_FORMAT = "format"; public static final String IJKM_KEY_DURATION_US = "duration_us"; public static final String IJKM_KEY_START_US = "start_us"; public static final String IJKM_KEY_BITRATE = "bitrate"; public static final String IJKM_KEY_VIDEO_STREAM = "video"; public static final String IJKM_KEY_AUDIO_STREAM = "audio"; public static final String IJKM_KEY_TIMEDTEXT_STREAM = "timedtext"; // stream meta public static final String IJKM_KEY_TYPE = "type"; public static final String IJKM_VAL_TYPE__VIDEO = "video"; public static final String IJKM_VAL_TYPE__AUDIO = "audio"; public static final String IJKM_VAL_TYPE__TIMEDTEXT = "timedtext"; public static final String IJKM_VAL_TYPE__UNKNOWN = "unknown"; public static final String IJKM_KEY_LANGUAGE = "language"; public static final String IJKM_KEY_CODEC_NAME = "codec_name"; public static final String IJKM_KEY_CODEC_PROFILE = "codec_profile"; public static final String IJKM_KEY_CODEC_LEVEL = "codec_level"; public static final String IJKM_KEY_CODEC_LONG_NAME = "codec_long_name"; public static final String IJKM_KEY_CODEC_PIXEL_FORMAT = "codec_pixel_format"; public static final String IJKM_KEY_CODEC_PROFILE_ID = "codec_profile_id"; // stream: video public static final String IJKM_KEY_WIDTH = "width"; public static final String IJKM_KEY_HEIGHT = "height"; public static final String IJKM_KEY_FPS_NUM = "fps_num"; public static final String IJKM_KEY_FPS_DEN = "fps_den"; public static final String IJKM_KEY_TBR_NUM = "tbr_num"; public static final String IJKM_KEY_TBR_DEN = "tbr_den"; public static final String IJKM_KEY_SAR_NUM = "sar_num"; public static final String IJKM_KEY_SAR_DEN = "sar_den"; // stream: audio public static final String IJKM_KEY_SAMPLE_RATE = "sample_rate"; public static final String IJKM_KEY_CHANNEL_LAYOUT = "channel_layout"; public static final String IJKM_KEY_STREAMS = "streams"; public static final long AV_CH_FRONT_LEFT = 0x00000001; public static final long AV_CH_FRONT_RIGHT = 0x00000002; public static final long AV_CH_FRONT_CENTER = 0x00000004; public static final long AV_CH_LOW_FREQUENCY = 0x00000008; public static final long AV_CH_BACK_LEFT = 0x00000010; public static final long AV_CH_BACK_RIGHT = 0x00000020; public static final long AV_CH_FRONT_LEFT_OF_CENTER = 0x00000040; public static final long AV_CH_FRONT_RIGHT_OF_CENTER = 0x00000080; public static final long AV_CH_BACK_CENTER = 0x00000100; public static final long AV_CH_SIDE_LEFT = 0x00000200; public static final long AV_CH_SIDE_RIGHT = 0x00000400; public static final long AV_CH_TOP_CENTER = 0x00000800; public static final long AV_CH_TOP_FRONT_LEFT = 0x00001000; public static final long AV_CH_TOP_FRONT_CENTER = 0x00002000; public static final long AV_CH_TOP_FRONT_RIGHT = 0x00004000; public static final long AV_CH_TOP_BACK_LEFT = 0x00008000; public static final long AV_CH_TOP_BACK_CENTER = 0x00010000; public static final long AV_CH_TOP_BACK_RIGHT = 0x00020000; public static final long AV_CH_STEREO_LEFT = 0x20000000; public static final long AV_CH_STEREO_RIGHT = 0x40000000; public static final long AV_CH_WIDE_LEFT = 0x0000000080000000L; public static final long AV_CH_WIDE_RIGHT = 0x0000000100000000L; public static final long AV_CH_SURROUND_DIRECT_LEFT = 0x0000000200000000L; public static final long AV_CH_SURROUND_DIRECT_RIGHT = 0x0000000400000000L; public static final long AV_CH_LOW_FREQUENCY_2 = 0x0000000800000000L; public static final long AV_CH_LAYOUT_MONO = (AV_CH_FRONT_CENTER); public static final long AV_CH_LAYOUT_STEREO = (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT); public static final long AV_CH_LAYOUT_2POINT1 = (AV_CH_LAYOUT_STEREO | AV_CH_LOW_FREQUENCY); public static final long AV_CH_LAYOUT_2_1 = (AV_CH_LAYOUT_STEREO | AV_CH_BACK_CENTER); public static final long AV_CH_LAYOUT_SURROUND = (AV_CH_LAYOUT_STEREO | AV_CH_FRONT_CENTER); public static final long AV_CH_LAYOUT_3POINT1 = (AV_CH_LAYOUT_SURROUND | AV_CH_LOW_FREQUENCY); public static final long AV_CH_LAYOUT_4POINT0 = (AV_CH_LAYOUT_SURROUND | AV_CH_BACK_CENTER); public static final long AV_CH_LAYOUT_4POINT1 = (AV_CH_LAYOUT_4POINT0 | AV_CH_LOW_FREQUENCY); public static final long AV_CH_LAYOUT_2_2 = (AV_CH_LAYOUT_STEREO | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT); public static final long AV_CH_LAYOUT_QUAD = (AV_CH_LAYOUT_STEREO | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT); public static final long AV_CH_LAYOUT_5POINT0 = (AV_CH_LAYOUT_SURROUND | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT); public static final long AV_CH_LAYOUT_5POINT1 = (AV_CH_LAYOUT_5POINT0 | AV_CH_LOW_FREQUENCY); public static final long AV_CH_LAYOUT_5POINT0_BACK = (AV_CH_LAYOUT_SURROUND | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT); public static final long AV_CH_LAYOUT_5POINT1_BACK = (AV_CH_LAYOUT_5POINT0_BACK | AV_CH_LOW_FREQUENCY); public static final long AV_CH_LAYOUT_6POINT0 = (AV_CH_LAYOUT_5POINT0 | AV_CH_BACK_CENTER); public static final long AV_CH_LAYOUT_6POINT0_FRONT = (AV_CH_LAYOUT_2_2 | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER); public static final long AV_CH_LAYOUT_HEXAGONAL = (AV_CH_LAYOUT_5POINT0_BACK | AV_CH_BACK_CENTER); public static final long AV_CH_LAYOUT_6POINT1 = (AV_CH_LAYOUT_5POINT1 | AV_CH_BACK_CENTER); public static final long AV_CH_LAYOUT_6POINT1_BACK = (AV_CH_LAYOUT_5POINT1_BACK | AV_CH_BACK_CENTER); public static final long AV_CH_LAYOUT_6POINT1_FRONT = (AV_CH_LAYOUT_6POINT0_FRONT | AV_CH_LOW_FREQUENCY); public static final long AV_CH_LAYOUT_7POINT0 = (AV_CH_LAYOUT_5POINT0 | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT); public static final long AV_CH_LAYOUT_7POINT0_FRONT = (AV_CH_LAYOUT_5POINT0 | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER); public static final long AV_CH_LAYOUT_7POINT1 = (AV_CH_LAYOUT_5POINT1 | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT); public static final long AV_CH_LAYOUT_7POINT1_WIDE = (AV_CH_LAYOUT_5POINT1 | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER); public static final long AV_CH_LAYOUT_7POINT1_WIDE_BACK = (AV_CH_LAYOUT_5POINT1_BACK | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER); public static final long AV_CH_LAYOUT_OCTAGONAL = (AV_CH_LAYOUT_5POINT0 | AV_CH_BACK_LEFT | AV_CH_BACK_CENTER | AV_CH_BACK_RIGHT); public static final long AV_CH_LAYOUT_STEREO_DOWNMIX = (AV_CH_STEREO_LEFT | AV_CH_STEREO_RIGHT); public static final int FF_PROFILE_H264_CONSTRAINED = (1<<9); // 8+1; constraint_set1_flag public static final int FF_PROFILE_H264_INTRA = (1<<11); // 8+3; constraint_set3_flag public static final int FF_PROFILE_H264_BASELINE = 66; public static final int FF_PROFILE_H264_CONSTRAINED_BASELINE = (66|FF_PROFILE_H264_CONSTRAINED); public static final int FF_PROFILE_H264_MAIN = 77; public static final int FF_PROFILE_H264_EXTENDED = 88; public static final int FF_PROFILE_H264_HIGH = 100; public static final int FF_PROFILE_H264_HIGH_10 = 110; public static final int FF_PROFILE_H264_HIGH_10_INTRA = (110|FF_PROFILE_H264_INTRA); public static final int FF_PROFILE_H264_HIGH_422 = 122; public static final int FF_PROFILE_H264_HIGH_422_INTRA = (122|FF_PROFILE_H264_INTRA); public static final int FF_PROFILE_H264_HIGH_444 = 144; public static final int FF_PROFILE_H264_HIGH_444_PREDICTIVE = 244; public static final int FF_PROFILE_H264_HIGH_444_INTRA = (244|FF_PROFILE_H264_INTRA); public static final int FF_PROFILE_H264_CAVLC_444 = 44; public Bundle mMediaMeta; public String mFormat; public long mDurationUS; public long mStartUS; public long mBitrate; public final ArrayList mStreams = new ArrayList(); public IjkStreamMeta mVideoStream; public IjkStreamMeta mAudioStream; public String getString(String key) { return mMediaMeta.getString(key); } public int getInt(String key) { return getInt(key, 0); } public int getInt(String key, int defaultValue) { String value = getString(key); if (TextUtils.isEmpty(value)) return defaultValue; try { return Integer.parseInt(value); } catch (NumberFormatException e) { return defaultValue; } } public long getLong(String key) { return getLong(key, 0); } public long getLong(String key, long defaultValue) { String value = getString(key); if (TextUtils.isEmpty(value)) return defaultValue; try { return Long.parseLong(value); } catch (NumberFormatException e) { return defaultValue; } } public ArrayList getParcelableArrayList(String key) { return mMediaMeta.getParcelableArrayList(key); } public String getDurationInline() { long duration = mDurationUS + 5000; long secs = duration / 1000000; long mins = secs / 60; secs %= 60; long hours = mins / 60; mins %= 60; return String.format(Locale.US, "%02d:%02d:%02d", hours, mins, secs); } public static IjkMediaMeta parse(Bundle mediaMeta) { if (mediaMeta == null) return null; IjkMediaMeta meta = new IjkMediaMeta(); meta.mMediaMeta = mediaMeta; meta.mFormat = meta.getString(IJKM_KEY_FORMAT); meta.mDurationUS = meta.getLong(IJKM_KEY_DURATION_US); meta.mStartUS = meta.getLong(IJKM_KEY_START_US); meta.mBitrate = meta.getLong(IJKM_KEY_BITRATE); int videoStreamIndex = meta.getInt(IJKM_KEY_VIDEO_STREAM, -1); int audioStreamIndex = meta.getInt(IJKM_KEY_AUDIO_STREAM, -1); int subtitleStreamIndex = meta.getInt(IJKM_KEY_TIMEDTEXT_STREAM, -1); ArrayList streams = meta .getParcelableArrayList(IJKM_KEY_STREAMS); if (streams == null) return meta; int index = -1; for (Bundle streamBundle : streams) { index++; if (streamBundle == null) { continue; } IjkStreamMeta streamMeta = new IjkStreamMeta(index); streamMeta.mMeta = streamBundle; streamMeta.mType = streamMeta.getString(IJKM_KEY_TYPE); streamMeta.mLanguage = streamMeta.getString(IJKM_KEY_LANGUAGE); if (TextUtils.isEmpty(streamMeta.mType)) continue; streamMeta.mCodecName = streamMeta.getString(IJKM_KEY_CODEC_NAME); streamMeta.mCodecProfile = streamMeta .getString(IJKM_KEY_CODEC_PROFILE); streamMeta.mCodecLongName = streamMeta .getString(IJKM_KEY_CODEC_LONG_NAME); streamMeta.mBitrate = streamMeta.getInt(IJKM_KEY_BITRATE); if (streamMeta.mType.equalsIgnoreCase(IJKM_VAL_TYPE__VIDEO)) { streamMeta.mWidth = streamMeta.getInt(IJKM_KEY_WIDTH); streamMeta.mHeight = streamMeta.getInt(IJKM_KEY_HEIGHT); streamMeta.mFpsNum = streamMeta.getInt(IJKM_KEY_FPS_NUM); streamMeta.mFpsDen = streamMeta.getInt(IJKM_KEY_FPS_DEN); streamMeta.mTbrNum = streamMeta.getInt(IJKM_KEY_TBR_NUM); streamMeta.mTbrDen = streamMeta.getInt(IJKM_KEY_TBR_DEN); streamMeta.mSarNum = streamMeta.getInt(IJKM_KEY_SAR_NUM); streamMeta.mSarDen = streamMeta.getInt(IJKM_KEY_SAR_DEN); if (videoStreamIndex == index) { meta.mVideoStream = streamMeta; } } else if (streamMeta.mType.equalsIgnoreCase(IJKM_VAL_TYPE__AUDIO)) { streamMeta.mSampleRate = streamMeta .getInt(IJKM_KEY_SAMPLE_RATE); streamMeta.mChannelLayout = streamMeta .getLong(IJKM_KEY_CHANNEL_LAYOUT); if (audioStreamIndex == index) { meta.mAudioStream = streamMeta; } } meta.mStreams.add(streamMeta); } return meta; } public static class IjkStreamMeta { public Bundle mMeta; public final int mIndex; public String mType; public String mLanguage; // common public String mCodecName; public String mCodecProfile; public String mCodecLongName; public long mBitrate; // video public int mWidth; public int mHeight; public int mFpsNum; public int mFpsDen; public int mTbrNum; public int mTbrDen; public int mSarNum; public int mSarDen; // audio public int mSampleRate; public long mChannelLayout; public IjkStreamMeta(int index) { mIndex = index; } public String getString(String key) { return mMeta.getString(key); } public int getInt(String key) { return getInt(key, 0); } public int getInt(String key, int defaultValue) { String value = getString(key); if (TextUtils.isEmpty(value)) return defaultValue; try { return Integer.parseInt(value); } catch (NumberFormatException e) { return defaultValue; } } public long getLong(String key) { return getLong(key, 0); } public long getLong(String key, long defaultValue) { String value = getString(key); if (TextUtils.isEmpty(value)) return defaultValue; try { return Long.parseLong(value); } catch (NumberFormatException e) { return defaultValue; } } public String getCodecLongNameInline() { if (!TextUtils.isEmpty(mCodecLongName)) { return mCodecLongName; } else if (!TextUtils.isEmpty(mCodecName)) { return mCodecName; } else { return "N/A"; } } public String getCodecShortNameInline() { if (!TextUtils.isEmpty(mCodecName)) { return mCodecName; } else { return "N/A"; } } public String getResolutionInline() { if (mWidth <= 0 || mHeight <= 0) { return "N/A"; } else if (mSarNum <= 0 || mSarDen <= 0) { return String.format(Locale.US, "%d x %d", mWidth, mHeight); } else { return String.format(Locale.US, "%d x %d [SAR %d:%d]", mWidth, mHeight, mSarNum, mSarDen); } } public String getFpsInline() { if (mFpsNum <= 0 || mFpsDen <= 0) { return "N/A"; } else { return String.valueOf(((float) (mFpsNum)) / mFpsDen); } } public String getBitrateInline() { if (mBitrate <= 0) { return "N/A"; } else if (mBitrate < 1000) { return String.format(Locale.US, "%d bit/s", mBitrate); } else { return String.format(Locale.US, "%d kb/s", mBitrate / 1000); } } public String getSampleRateInline() { if (mSampleRate <= 0) { return "N/A"; } else { return String.format(Locale.US, "%d Hz", mSampleRate); } } public String getChannelLayoutInline() { if (mChannelLayout <= 0) { return "N/A"; } else { if (mChannelLayout == AV_CH_LAYOUT_MONO) { return "mono"; } else if (mChannelLayout == AV_CH_LAYOUT_STEREO) { return "stereo"; } else { return String.format(Locale.US, "%x", mChannelLayout); } } } } } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java ================================================ /* * Copyright (C) 2006 Bilibili * Copyright (C) 2006 The Android Open Source Project * Copyright (C) 2013 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.graphics.SurfaceTexture; import android.graphics.Rect; import android.media.MediaCodecInfo; import android.media.MediaCodecList; import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.view.Surface; import android.view.SurfaceHolder; import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.Locale; import java.util.Map; import tv.danmaku.ijk.media.player.annotations.AccessedByNative; import tv.danmaku.ijk.media.player.annotations.CalledByNative; import tv.danmaku.ijk.media.player.misc.IAndroidIO; import tv.danmaku.ijk.media.player.misc.IMediaDataSource; import tv.danmaku.ijk.media.player.misc.ITrackInfo; import tv.danmaku.ijk.media.player.misc.IjkTrackInfo; import tv.danmaku.ijk.media.player.pragma.DebugLog; /** * @author bbcallen * * Java wrapper of ffplay. */ public final class IjkMediaPlayer extends AbstractMediaPlayer { private final static String TAG = IjkMediaPlayer.class.getName(); private static final int MEDIA_NOP = 0; // interface test message private static final int MEDIA_PREPARED = 1; private static final int MEDIA_PLAYBACK_COMPLETE = 2; private static final int MEDIA_BUFFERING_UPDATE = 3; private static final int MEDIA_SEEK_COMPLETE = 4; private static final int MEDIA_SET_VIDEO_SIZE = 5; private static final int MEDIA_TIMED_TEXT = 99; private static final int MEDIA_ERROR = 100; private static final int MEDIA_INFO = 200; protected static final int MEDIA_SET_VIDEO_SAR = 10001; //---------------------------------------- // options public static final int IJK_LOG_UNKNOWN = 0; public static final int IJK_LOG_DEFAULT = 1; public static final int IJK_LOG_VERBOSE = 2; public static final int IJK_LOG_DEBUG = 3; public static final int IJK_LOG_INFO = 4; public static final int IJK_LOG_WARN = 5; public static final int IJK_LOG_ERROR = 6; public static final int IJK_LOG_FATAL = 7; public static final int IJK_LOG_SILENT = 8; public static final int OPT_CATEGORY_FORMAT = 1; public static final int OPT_CATEGORY_CODEC = 2; public static final int OPT_CATEGORY_SWS = 3; public static final int OPT_CATEGORY_PLAYER = 4; public static final int SDL_FCC_YV12 = 0x32315659; // YV12 public static final int SDL_FCC_RV16 = 0x36315652; // RGB565 public static final int SDL_FCC_RV32 = 0x32335652; // RGBX8888 //---------------------------------------- //---------------------------------------- // properties 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_DROP_FRAME_RATE = 10007; public static final int FFP_PROP_INT64_SELECTED_VIDEO_STREAM = 20001; public static final int FFP_PROP_INT64_SELECTED_AUDIO_STREAM = 20002; public static final int FFP_PROP_INT64_SELECTED_TIMEDTEXT_STREAM = 20011; public static final int FFP_PROP_INT64_VIDEO_DECODER = 20003; public static final int FFP_PROP_INT64_AUDIO_DECODER = 20004; public static final int FFP_PROPV_DECODER_UNKNOWN = 0; public static final int FFP_PROPV_DECODER_AVCODEC = 1; public static final int FFP_PROPV_DECODER_MEDIACODEC = 2; public static final int FFP_PROPV_DECODER_VIDEOTOOLBOX = 3; public static final int FFP_PROP_INT64_VIDEO_CACHED_DURATION = 20005; public static final int FFP_PROP_INT64_AUDIO_CACHED_DURATION = 20006; public static final int FFP_PROP_INT64_VIDEO_CACHED_BYTES = 20007; public static final int FFP_PROP_INT64_AUDIO_CACHED_BYTES = 20008; public static final int FFP_PROP_INT64_VIDEO_CACHED_PACKETS = 20009; public static final int FFP_PROP_INT64_AUDIO_CACHED_PACKETS = 20010; public static final int FFP_PROP_INT64_ASYNC_STATISTIC_BUF_BACKWARDS = 20201; public static final int FFP_PROP_INT64_ASYNC_STATISTIC_BUF_FORWARDS = 20202; public static final int FFP_PROP_INT64_ASYNC_STATISTIC_BUF_CAPACITY = 20203; public static final int FFP_PROP_INT64_TRAFFIC_STATISTIC_BYTE_COUNT = 20204; public static final int FFP_PROP_INT64_CACHE_STATISTIC_PHYSICAL_POS = 20205; public static final int FFP_PROP_INT64_CACHE_STATISTIC_FILE_FORWARDS = 20206; public static final int FFP_PROP_INT64_CACHE_STATISTIC_FILE_POS = 20207; public static final int FFP_PROP_INT64_CACHE_STATISTIC_COUNT_BYTES = 20208; public static final int FFP_PROP_INT64_LOGICAL_FILE_SIZE = 20209; public static final int FFP_PROP_INT64_SHARE_CACHE_DATA = 20210; public static final int FFP_PROP_INT64_BIT_RATE = 20100; 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; //---------------------------------------- @AccessedByNative private long mNativeMediaPlayer; @AccessedByNative private long mNativeMediaDataSource; @AccessedByNative private long mNativeAndroidIO; @AccessedByNative private int mNativeSurfaceTexture; @AccessedByNative private int mListenerContext; private SurfaceHolder mSurfaceHolder; private EventHandler mEventHandler; private PowerManager.WakeLock mWakeLock = null; private boolean mScreenOnWhilePlaying; private boolean mStayAwake; private int mVideoWidth; private int mVideoHeight; private int mVideoSarNum; private int mVideoSarDen; private String mDataSource; /** * Default library loader * Load them by yourself, if your libraries are not installed at default place. */ private static final IjkLibLoader sLocalLibLoader = new IjkLibLoader() { @Override public void loadLibrary(String libName) throws UnsatisfiedLinkError, SecurityException { System.loadLibrary(libName); } }; private static volatile boolean mIsLibLoaded = false; public static void loadLibrariesOnce(IjkLibLoader libLoader) { synchronized (IjkMediaPlayer.class) { if (!mIsLibLoaded) { if (libLoader == null) libLoader = sLocalLibLoader; libLoader.loadLibrary("ijkffmpeg"); libLoader.loadLibrary("ijksdl"); libLoader.loadLibrary("ijkplayer"); mIsLibLoaded = true; } } } private static volatile boolean mIsNativeInitialized = false; private static void initNativeOnce() { synchronized (IjkMediaPlayer.class) { if (!mIsNativeInitialized) { native_init(); mIsNativeInitialized = true; } } } /** * Default constructor. Consider using one of the create() methods for * synchronously instantiating a IjkMediaPlayer from a Uri or resource. *

* When done with the IjkMediaPlayer, you should call {@link #release()}, to * free the resources. If not released, too many IjkMediaPlayer instances * may result in an exception. *

*/ public IjkMediaPlayer() { this(sLocalLibLoader); } /** * do not loadLibaray * @param libLoader * custom library loader, can be null. */ public IjkMediaPlayer(IjkLibLoader libLoader) { initPlayer(libLoader); } private void initPlayer(IjkLibLoader libLoader) { loadLibrariesOnce(libLoader); initNativeOnce(); Looper looper; if ((looper = Looper.myLooper()) != null) { mEventHandler = new EventHandler(this, looper); } else if ((looper = Looper.getMainLooper()) != null) { mEventHandler = new EventHandler(this, looper); } else { mEventHandler = null; } /* * Native setup requires a weak reference to our object. It's easier to * create it here than in C++. */ native_setup(new WeakReference(this)); } private native void _setFrameAtTime(String imgCachePath, long startTime, long endTime, int num, int imgDefinition) throws IllegalArgumentException, IllegalStateException; /* * Update the IjkMediaPlayer SurfaceTexture. Call after setting a new * display surface. */ private native void _setVideoSurface(Surface surface); /** * Sets the {@link SurfaceHolder} to use for displaying the video portion of * the media. * * Either a surface holder or surface must be set if a display or video sink * is needed. Not calling this method or {@link #setSurface(Surface)} when * playing back a video will result in only the audio track being played. A * null surface holder or surface will result in only the audio track being * played. * * @param sh * the SurfaceHolder to use for video display */ @Override public void setDisplay(SurfaceHolder sh) { mSurfaceHolder = sh; Surface surface; if (sh != null) { surface = sh.getSurface(); } else { surface = null; } _setVideoSurface(surface); 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 * does not support {@link #setScreenOnWhilePlaying(boolean)}. Setting a * Surface will un-set any Surface or SurfaceHolder that was previously set. * A null surface will result in only the audio track being played. * * If the Surface sends frames to a {@link SurfaceTexture}, the timestamps * returned from {@link SurfaceTexture#getTimestamp()} will have an * unspecified zero point. These timestamps cannot be directly compared * between different media sources, different instances of the same media * source, or multiple runs of the same program. The timestamp is normally * monotonically increasing and is unaffected by time-of-day adjustments, * but it is reset when the position is set. * * @param surface * The {@link Surface} to be used for the video portion of the * media. */ @Override public void setSurface(Surface surface) { if (mScreenOnWhilePlaying && surface != null) { DebugLog.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for Surface"); } mSurfaceHolder = null; _setVideoSurface(surface); updateSurfaceScreenOn(); } /** * Sets the data source as a content Uri. * * @param context the Context to use when resolving the Uri * @param uri the Content URI of the data you want to play * @throws IllegalStateException if it is called in an invalid state */ @Override public void setDataSource(Context context, Uri uri) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { setDataSource(context, uri, null); } /** * Sets the data source as a content Uri. * * @param context the Context to use when resolving the Uri * @param uri the Content URI of the data you want to play * @param headers the headers to be sent together with the request for the data * Note that the cross domain redirection is allowed by default, but that can be * changed with key/value pairs through the headers parameter with * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value * to disallow or allow cross domain redirection. * @throws IllegalStateException if it is called in an invalid state */ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Override public void setDataSource(Context context, Uri uri, Map headers) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { final String scheme = uri.getScheme(); if (ContentResolver.SCHEME_FILE.equals(scheme)) { setDataSource(uri.getPath()); return; } else if (ContentResolver.SCHEME_CONTENT.equals(scheme) && Settings.AUTHORITY.equals(uri.getAuthority())) { // Redirect ringtones to go directly to underlying provider uri = RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.getDefaultType(uri)); if (uri == null) { throw new FileNotFoundException("Failed to resolve default ringtone"); } } AssetFileDescriptor fd = null; try { ContentResolver resolver = context.getContentResolver(); fd = resolver.openAssetFileDescriptor(uri, "r"); if (fd == null) { return; } // Note: using getDeclaredLength so that our behavior is the same // as previous versions when the content provider is returning // a full file. if (fd.getDeclaredLength() < 0) { setDataSource(fd.getFileDescriptor()); } else { setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getDeclaredLength()); } return; } catch (SecurityException ignored) { } catch (IOException ignored) { } finally { if (fd != null) { fd.close(); } } Log.d(TAG, "Couldn't open file on client side, trying server side"); setDataSource(uri.toString(), headers); } /** * Sets the data source (file-path or http/rtsp URL) to use. * * @param path * the path of the file, or the http/rtsp URL of the stream you * want to play * @throws IllegalStateException * if it is called in an invalid state * *

* When path refers to a local file, the file may * actually be opened by a process other than the calling * application. This implies that the pathname should be an * absolute path (as any other process runs with unspecified * current working directory), and that the pathname should * reference a world-readable file. */ @Override public void setDataSource(String path) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { mDataSource = path; _setDataSource(path, null, null); } /** * Sets the data source (file-path or http/rtsp URL) to use. * * @param path the path of the file, or the http/rtsp URL of the stream you want to play * @param headers the headers associated with the http request for the stream you want to play * @throws IllegalStateException if it is called in an invalid state */ public void setDataSource(String path, Map headers) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { if (headers != null && !headers.isEmpty()) { StringBuilder sb = new StringBuilder(); for(Map.Entry entry: headers.entrySet()) { sb.append(entry.getKey()); sb.append(":"); String value = entry.getValue(); if (!TextUtils.isEmpty(value)) sb.append(entry.getValue()); sb.append("\r\n"); setOption(OPT_CATEGORY_FORMAT, "headers", sb.toString()); setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "protocol_whitelist", "async,cache,crypto,file,http,https,ijkhttphook,ijkinject,ijklivehook,ijklongurl,ijksegment,ijktcphook,pipe,rtp,tcp,tls,udp,ijkurlhook,data"); } } setDataSource(path); } /** * Sets the data source (FileDescriptor) to use. It is the caller's responsibility * to close the file descriptor. It is safe to do so as soon as this call returns. * * @param fd the FileDescriptor for the file you want to play * @throws IllegalStateException if it is called in an invalid state */ @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) @Override public void setDataSource(FileDescriptor fd) throws IOException, IllegalArgumentException, IllegalStateException { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1) { int native_fd = -1; try { Field f = fd.getClass().getDeclaredField("descriptor"); //NoSuchFieldException f.setAccessible(true); native_fd = f.getInt(fd); //IllegalAccessException } catch (NoSuchFieldException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } _setDataSourceFd(native_fd); } else { ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(fd); try { _setDataSourceFd(pfd.getFd()); } finally { pfd.close(); } } } /** * Sets the data source (FileDescriptor) to use. The FileDescriptor must be * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility * to close the file descriptor. It is safe to do so as soon as this call returns. * * @param fd the FileDescriptor for the file you want to play * @param offset the offset into the file where the data to be played starts, in bytes * @param length the length in bytes of the data to be played * @throws IllegalStateException if it is called in an invalid state */ private void setDataSource(FileDescriptor fd, long offset, long length) throws IOException, IllegalArgumentException, IllegalStateException { // FIXME: handle offset, length setDataSource(fd); } public void setDataSource(IMediaDataSource mediaDataSource) throws IllegalArgumentException, SecurityException, IllegalStateException { _setDataSource(mediaDataSource); } public void setAndroidIOCallback(IAndroidIO androidIO) throws IllegalArgumentException, SecurityException, IllegalStateException { _setAndroidIOCallback(androidIO); } private native void _setDataSource(String path, String[] keys, String[] values) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException; private native void _setDataSourceFd(int fd) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException; private native void _setDataSource(IMediaDataSource mediaDataSource) throws IllegalArgumentException, SecurityException, IllegalStateException; private native void _setAndroidIOCallback(IAndroidIO androidIO) throws IllegalArgumentException, SecurityException, IllegalStateException; @Override public String getDataSource() { return mDataSource; } @Override public void prepareAsync() throws IllegalStateException { _prepareAsync(); } public native void _prepareAsync() throws IllegalStateException; @Override public void start() throws IllegalStateException { stayAwake(true); _start(); } private native void _start() throws IllegalStateException; @Override public void stop() throws IllegalStateException { stayAwake(false); _stop(); } private native void _stop() throws IllegalStateException; @Override public void pause() throws IllegalStateException { stayAwake(false); _pause(); } private native void _pause() throws IllegalStateException; @SuppressLint("Wakelock") @Override public void setWakeMode(Context context, int mode) { boolean washeld = false; if (mWakeLock != null) { if (mWakeLock.isHeld()) { washeld = true; mWakeLock.release(); } mWakeLock = null; } PowerManager pm = (PowerManager) context .getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(mode | PowerManager.ON_AFTER_RELEASE, IjkMediaPlayer.class.getName()); mWakeLock.setReferenceCounted(false); if (washeld) { mWakeLock.acquire(); } } @Override public void setScreenOnWhilePlaying(boolean screenOn) { if (mScreenOnWhilePlaying != screenOn) { if (screenOn && mSurfaceHolder == null) { DebugLog.w(TAG, "setScreenOnWhilePlaying(true) is ineffective without a SurfaceHolder"); } mScreenOnWhilePlaying = screenOn; updateSurfaceScreenOn(); } } @SuppressLint("Wakelock") private void stayAwake(boolean awake) { if (mWakeLock != null) { if (awake && !mWakeLock.isHeld()) { mWakeLock.acquire(); } else if (!awake && mWakeLock.isHeld()) { mWakeLock.release(); } } mStayAwake = awake; updateSurfaceScreenOn(); } private void updateSurfaceScreenOn() { if (mSurfaceHolder != null) { mSurfaceHolder.setKeepScreenOn(mScreenOnWhilePlaying && mStayAwake); } } @Override public IjkTrackInfo[] getTrackInfo() { Bundle bundle = getMediaMeta(); if (bundle == null) return null; IjkMediaMeta mediaMeta = IjkMediaMeta.parse(bundle); if (mediaMeta == null || mediaMeta.mStreams == null) return null; ArrayList trackInfos = new ArrayList(); for (IjkMediaMeta.IjkStreamMeta streamMeta: mediaMeta.mStreams) { IjkTrackInfo trackInfo = new IjkTrackInfo(streamMeta); if (streamMeta.mType.equalsIgnoreCase(IjkMediaMeta.IJKM_VAL_TYPE__VIDEO)) { trackInfo.setTrackType(ITrackInfo.MEDIA_TRACK_TYPE_VIDEO); } else if (streamMeta.mType.equalsIgnoreCase(IjkMediaMeta.IJKM_VAL_TYPE__AUDIO)) { trackInfo.setTrackType(ITrackInfo.MEDIA_TRACK_TYPE_AUDIO); } else if (streamMeta.mType.equalsIgnoreCase(IjkMediaMeta.IJKM_VAL_TYPE__TIMEDTEXT)) { trackInfo.setTrackType(ITrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT); } trackInfos.add(trackInfo); } return trackInfos.toArray(new IjkTrackInfo[trackInfos.size()]); } // TODO: @Override public int getSelectedTrack(int trackType) { switch (trackType) { case ITrackInfo.MEDIA_TRACK_TYPE_VIDEO: return (int)_getPropertyLong(FFP_PROP_INT64_SELECTED_VIDEO_STREAM, -1); case ITrackInfo.MEDIA_TRACK_TYPE_AUDIO: return (int)_getPropertyLong(FFP_PROP_INT64_SELECTED_AUDIO_STREAM, -1); case ITrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT: return (int)_getPropertyLong(FFP_PROP_INT64_SELECTED_TIMEDTEXT_STREAM, -1); default: return -1; } } // experimental, should set DEFAULT_MIN_FRAMES and MAX_MIN_FRAMES to 25 // TODO: @Override public void selectTrack(int track) { _setStreamSelected(track, true); } // experimental, should set DEFAULT_MIN_FRAMES and MAX_MIN_FRAMES to 25 // TODO: @Override public void deselectTrack(int track) { _setStreamSelected(track, false); } private native void _setStreamSelected(int stream, boolean select); @Override public int getVideoWidth() { return mVideoWidth; } @Override public int getVideoHeight() { return mVideoHeight; } @Override public int getVideoSarNum() { return mVideoSarNum; } @Override public int getVideoSarDen() { return mVideoSarDen; } @Override public native boolean isPlaying(); @Override public native void seekTo(long msec) throws IllegalStateException; @Override public native long getCurrentPosition(); @Override public native long getDuration(); /** * Releases resources associated with this IjkMediaPlayer object. It is * considered good practice to call this method when you're done using the * IjkMediaPlayer. In particular, whenever an Activity of an application is * paused (its onPause() method is called), or stopped (its onStop() method * is called), this method should be invoked to release the IjkMediaPlayer * object, unless the application has a special need to keep the object * around. In addition to unnecessary resources (such as memory and * instances of codecs) being held, failure to call this method immediately * if a IjkMediaPlayer object is no longer needed may also lead to * continuous battery consumption for mobile devices, and playback failure * for other applications if no multiple instances of the same codec are * supported on a device. Even if multiple instances of the same codec are * supported, some performance degradation may be expected when unnecessary * multiple instances are used at the same time. */ @Override public void release() { stayAwake(false); updateSurfaceScreenOn(); resetListeners(); _release(); } private native void _release(); @Override public void reset() { stayAwake(false); _reset(); // make sure none of the listeners get called anymore mEventHandler.removeCallbacksAndMessages(null); mVideoWidth = 0; mVideoHeight = 0; } private native void _reset(); /** * Sets the player to be looping or non-looping. * * @param looping whether to loop or not */ @Override public void setLooping(boolean looping) { int loopCount = looping ? 0 : 1; setOption(OPT_CATEGORY_PLAYER, "loop", loopCount); _setLoopCount(loopCount); } private native void _setLoopCount(int loopCount); /** * Checks whether the MediaPlayer is looping or non-looping. * * @return true if the MediaPlayer is currently looping, false otherwise */ @Override public boolean isLooping() { int loopCount = _getLoopCount(); return loopCount != 1; } private native int _getLoopCount(); public void setSpeed(float speed) { _setPropertyFloat(FFP_PROP_FLOAT_PLAYBACK_RATE, speed); } public float getSpeed(float speed) { return _getPropertyFloat(FFP_PROP_FLOAT_PLAYBACK_RATE, .0f); } public int getVideoDecoder() { return (int)_getPropertyLong(FFP_PROP_INT64_VIDEO_DECODER, FFP_PROPV_DECODER_UNKNOWN); } public float getVideoOutputFramesPerSecond() { return _getPropertyFloat(PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND, 0.0f); } public float getVideoDecodeFramesPerSecond() { return _getPropertyFloat(PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND, 0.0f); } public long getVideoCachedDuration() { return _getPropertyLong(FFP_PROP_INT64_VIDEO_CACHED_DURATION, 0); } public long getAudioCachedDuration() { return _getPropertyLong(FFP_PROP_INT64_AUDIO_CACHED_DURATION, 0); } public long getVideoCachedBytes() { return _getPropertyLong(FFP_PROP_INT64_VIDEO_CACHED_BYTES, 0); } public long getAudioCachedBytes() { return _getPropertyLong(FFP_PROP_INT64_AUDIO_CACHED_BYTES, 0); } public long getVideoCachedPackets() { return _getPropertyLong(FFP_PROP_INT64_VIDEO_CACHED_PACKETS, 0); } public long getAudioCachedPackets() { return _getPropertyLong(FFP_PROP_INT64_AUDIO_CACHED_PACKETS, 0); } public long getAsyncStatisticBufBackwards() { return _getPropertyLong(FFP_PROP_INT64_ASYNC_STATISTIC_BUF_BACKWARDS, 0); } public long getAsyncStatisticBufForwards() { return _getPropertyLong(FFP_PROP_INT64_ASYNC_STATISTIC_BUF_FORWARDS, 0); } public long getAsyncStatisticBufCapacity() { return _getPropertyLong(FFP_PROP_INT64_ASYNC_STATISTIC_BUF_CAPACITY, 0); } public long getTrafficStatisticByteCount() { return _getPropertyLong(FFP_PROP_INT64_TRAFFIC_STATISTIC_BYTE_COUNT, 0); } public long getCacheStatisticPhysicalPos() { return _getPropertyLong(FFP_PROP_INT64_CACHE_STATISTIC_PHYSICAL_POS, 0); } public long getCacheStatisticFileForwards() { return _getPropertyLong(FFP_PROP_INT64_CACHE_STATISTIC_FILE_FORWARDS, 0); } public long getCacheStatisticFilePos() { return _getPropertyLong(FFP_PROP_INT64_CACHE_STATISTIC_FILE_POS, 0); } public long getCacheStatisticCountBytes() { return _getPropertyLong(FFP_PROP_INT64_CACHE_STATISTIC_COUNT_BYTES, 0); } public long getFileSize() { return _getPropertyLong(FFP_PROP_INT64_LOGICAL_FILE_SIZE, 0); } public long getBitRate() { return _getPropertyLong(FFP_PROP_INT64_BIT_RATE, 0); } public long getTcpSpeed() { return _getPropertyLong(FFP_PROP_INT64_TCP_SPEED, 0); } public long getSeekLoadDuration() { return _getPropertyLong(FFP_PROP_INT64_LATEST_SEEK_LOAD_DURATION, 0); } private native float _getPropertyFloat(int property, float defaultValue); private native void _setPropertyFloat(int property, float value); private native long _getPropertyLong(int property, long defaultValue); private native void _setPropertyLong(int property, long value); public float getDropFrameRate() { return _getPropertyFloat(FFP_PROP_FLOAT_DROP_FRAME_RATE, .0f); } @Override public native void setVolume(float leftVolume, float rightVolume); @Override public native int getAudioSessionId(); @Override public MediaInfo getMediaInfo() { MediaInfo mediaInfo = new MediaInfo(); mediaInfo.mMediaPlayerName = "ijkplayer"; String videoCodecInfo = _getVideoCodecInfo(); if (!TextUtils.isEmpty(videoCodecInfo)) { String nodes[] = videoCodecInfo.split(","); if (nodes.length >= 2) { mediaInfo.mVideoDecoder = nodes[0]; mediaInfo.mVideoDecoderImpl = nodes[1]; } else if (nodes.length >= 1) { mediaInfo.mVideoDecoder = nodes[0]; mediaInfo.mVideoDecoderImpl = ""; } } String audioCodecInfo = _getAudioCodecInfo(); if (!TextUtils.isEmpty(audioCodecInfo)) { String nodes[] = audioCodecInfo.split(","); if (nodes.length >= 2) { mediaInfo.mAudioDecoder = nodes[0]; mediaInfo.mAudioDecoderImpl = nodes[1]; } else if (nodes.length >= 1) { mediaInfo.mAudioDecoder = nodes[0]; mediaInfo.mAudioDecoderImpl = ""; } } try { mediaInfo.mMeta = IjkMediaMeta.parse(_getMediaMeta()); } catch (Throwable e) { e.printStackTrace(); } return mediaInfo; } @Override public void setLogEnabled(boolean enable) { // do nothing } @Override public boolean isPlayable() { return true; } private native String _getVideoCodecInfo(); private native String _getAudioCodecInfo(); public void setOption(int category, String name, String value) { _setOption(category, name, value); } public void setOption(int category, String name, long value) { _setOption(category, name, value); } private native void _setOption(int category, String name, String value); private native void _setOption(int category, String name, long value); public Bundle getMediaMeta() { return _getMediaMeta(); } private native Bundle _getMediaMeta(); public static String getColorFormatName(int mediaCodecColorFormat) { return _getColorFormatName(mediaCodecColorFormat); } private static native String _getColorFormatName(int mediaCodecColorFormat); @Override public void setAudioStreamType(int streamtype) { // do nothing } @Override public void setKeepInBackground(boolean keepInBackground) { // do nothing } private static native void native_init(); private native void native_setup(Object IjkMediaPlayer_this); private native void native_finalize(); private native void native_message_loop(Object IjkMediaPlayer_this); protected void finalize() throws Throwable { super.finalize(); native_finalize(); } public void httphookReconnect() { _setPropertyLong(FFP_PROP_INT64_IMMEDIATE_RECONNECT, 1); } public void setCacheShare(int share) { _setPropertyLong(FFP_PROP_INT64_SHARE_CACHE_DATA, (long)share); } private static class EventHandler extends Handler { private final WeakReference mWeakPlayer; public EventHandler(IjkMediaPlayer mp, Looper looper) { super(looper); mWeakPlayer = new WeakReference(mp); } @Override public void handleMessage(Message msg) { IjkMediaPlayer player = mWeakPlayer.get(); if (player == null || player.mNativeMediaPlayer == 0) { DebugLog.w(TAG, "IjkMediaPlayer went away with unhandled events"); return; } switch (msg.what) { case MEDIA_PREPARED: player.notifyOnPrepared(); return; case MEDIA_PLAYBACK_COMPLETE: player.stayAwake(false); player.notifyOnCompletion(); return; case MEDIA_BUFFERING_UPDATE: long bufferPosition = msg.arg1; if (bufferPosition < 0) { bufferPosition = 0; } long percent = 0; long duration = player.getDuration(); if (duration > 0) { percent = bufferPosition * 100 / duration; } if (percent >= 100) { percent = 100; } // DebugLog.efmt(TAG, "Buffer (%d%%) %d/%d", percent, bufferPosition, duration); player.notifyOnBufferingUpdate((int)percent); return; case MEDIA_SEEK_COMPLETE: player.notifyOnSeekComplete(); return; case MEDIA_SET_VIDEO_SIZE: player.mVideoWidth = msg.arg1; player.mVideoHeight = msg.arg2; player.notifyOnVideoSizeChanged(player.mVideoWidth, player.mVideoHeight, player.mVideoSarNum, player.mVideoSarDen); return; case MEDIA_ERROR: DebugLog.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")"); if (!player.notifyOnError(msg.arg1, msg.arg2)) { player.notifyOnCompletion(); } player.stayAwake(false); return; case MEDIA_INFO: switch (msg.arg1) { case MEDIA_INFO_VIDEO_RENDERING_START: DebugLog.i(TAG, "Info: MEDIA_INFO_VIDEO_RENDERING_START\n"); break; } player.notifyOnInfo(msg.arg1, msg.arg2); // No real default action so far. return; case MEDIA_TIMED_TEXT: if (msg.obj == null) { player.notifyOnTimedText(null); } else { IjkTimedText text = new IjkTimedText(new Rect(0, 0, 1, 1), (String)msg.obj); player.notifyOnTimedText(text); } return; case MEDIA_NOP: // interface test message - ignore break; case MEDIA_SET_VIDEO_SAR: player.mVideoSarNum = msg.arg1; player.mVideoSarDen = msg.arg2; player.notifyOnVideoSizeChanged(player.mVideoWidth, player.mVideoHeight, player.mVideoSarNum, player.mVideoSarDen); break; default: DebugLog.e(TAG, "Unknown message type " + msg.what); } } } /* * Called from native code when an interesting event happens. This method * just uses the EventHandler system to post the event back to the main app * thread. We use a weak reference to the original IjkMediaPlayer object so * that the native code is safe from the object disappearing from underneath * it. (This is the cookie passed to native_setup().) */ @CalledByNative private static void postEventFromNative(Object weakThiz, int what, int arg1, int arg2, Object obj) { if (weakThiz == null) return; @SuppressWarnings("rawtypes") IjkMediaPlayer mp = (IjkMediaPlayer) ((WeakReference) weakThiz).get(); if (mp == null) { return; } if (what == MEDIA_INFO && arg1 == MEDIA_INFO_STARTED_AS_NEXT) { // this acquires the wakelock if needed, and sets the client side // state mp.start(); } if (mp.mEventHandler != null) { Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj); mp.mEventHandler.sendMessage(m); } } /* * ControlMessage */ private OnControlMessageListener mOnControlMessageListener; public void setOnControlMessageListener(OnControlMessageListener listener) { mOnControlMessageListener = listener; } public interface OnControlMessageListener { String onControlResolveSegmentUrl(int segment); } /* * NativeInvoke */ private OnNativeInvokeListener mOnNativeInvokeListener; public void setOnNativeInvokeListener(OnNativeInvokeListener listener) { mOnNativeInvokeListener = listener; } public interface OnNativeInvokeListener { int CTRL_WILL_TCP_OPEN = 0x20001; // NO ARGS int CTRL_DID_TCP_OPEN = 0x20002; // ARG_ERROR, ARG_FAMILIY, ARG_IP, ARG_PORT, ARG_FD int CTRL_WILL_HTTP_OPEN = 0x20003; // ARG_URL, ARG_SEGMENT_INDEX, ARG_RETRY_COUNTER int CTRL_WILL_LIVE_OPEN = 0x20005; // ARG_URL, ARG_RETRY_COUNTER int CTRL_WILL_CONCAT_RESOLVE_SEGMENT = 0x20007; // ARG_URL, ARG_SEGMENT_INDEX, ARG_RETRY_COUNTER int EVENT_WILL_HTTP_OPEN = 0x1; // ARG_URL int EVENT_DID_HTTP_OPEN = 0x2; // ARG_URL, ARG_ERROR, ARG_HTTP_CODE int EVENT_WILL_HTTP_SEEK = 0x3; // ARG_URL, ARG_OFFSET int EVENT_DID_HTTP_SEEK = 0x4; // ARG_URL, ARG_OFFSET, ARG_ERROR, ARG_HTTP_CODE, ARG_FILE_SIZE String ARG_URL = "url"; String ARG_SEGMENT_INDEX = "segment_index"; String ARG_RETRY_COUNTER = "retry_counter"; String ARG_ERROR = "error"; String ARG_FAMILIY = "family"; String ARG_IP = "ip"; String ARG_PORT = "port"; String ARG_FD = "fd"; String ARG_OFFSET = "offset"; String ARG_HTTP_CODE = "http_code"; String ARG_FILE_SIZE = "file_size"; /* * @return true if invoke is handled * @throws Exception on any error */ boolean onNativeInvoke(int what, Bundle args); } @CalledByNative private static boolean onNativeInvoke(Object weakThiz, int what, Bundle args) { DebugLog.ifmt(TAG, "onNativeInvoke %d", what); if (weakThiz == null || !(weakThiz instanceof WeakReference)) throw new IllegalStateException(".onNativeInvoke()"); @SuppressWarnings("unchecked") WeakReference weakPlayer = (WeakReference) weakThiz; IjkMediaPlayer player = weakPlayer.get(); if (player == null) throw new IllegalStateException(".onNativeInvoke()"); OnNativeInvokeListener listener = player.mOnNativeInvokeListener; if (listener != null && listener.onNativeInvoke(what, args)) return true; switch (what) { case OnNativeInvokeListener.CTRL_WILL_CONCAT_RESOLVE_SEGMENT: { OnControlMessageListener onControlMessageListener = player.mOnControlMessageListener; if (onControlMessageListener == null) return false; int segmentIndex = args.getInt(OnNativeInvokeListener.ARG_SEGMENT_INDEX, -1); if (segmentIndex < 0) throw new InvalidParameterException("onNativeInvoke(invalid segment index)"); String newUrl = onControlMessageListener.onControlResolveSegmentUrl(segmentIndex); if (newUrl == null) throw new RuntimeException(new IOException("onNativeInvoke() = ")); args.putString(OnNativeInvokeListener.ARG_URL, newUrl); return true; } default: return false; } } /* * MediaCodec select */ public interface OnMediaCodecSelectListener { String onMediaCodecSelect(IMediaPlayer mp, String mimeType, int profile, int level); } private OnMediaCodecSelectListener mOnMediaCodecSelectListener; public void setOnMediaCodecSelectListener(OnMediaCodecSelectListener listener) { mOnMediaCodecSelectListener = listener; } public void resetListeners() { super.resetListeners(); mOnMediaCodecSelectListener = null; } @CalledByNative private static String onSelectCodec(Object weakThiz, String mimeType, int profile, int level) { if (weakThiz == null || !(weakThiz instanceof WeakReference)) return null; @SuppressWarnings("unchecked") WeakReference weakPlayer = (WeakReference) weakThiz; IjkMediaPlayer player = weakPlayer.get(); if (player == null) return null; OnMediaCodecSelectListener listener = player.mOnMediaCodecSelectListener; if (listener == null) listener = DefaultMediaCodecSelector.sInstance; return listener.onMediaCodecSelect(player, mimeType, profile, level); } public static class DefaultMediaCodecSelector implements OnMediaCodecSelectListener { public static final DefaultMediaCodecSelector sInstance = new DefaultMediaCodecSelector(); @SuppressWarnings("deprecation") @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public String onMediaCodecSelect(IMediaPlayer mp, String mimeType, int profile, int level) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) return null; if (TextUtils.isEmpty(mimeType)) return null; Log.i(TAG, String.format(Locale.US, "onSelectCodec: mime=%s, profile=%d, level=%d", mimeType, profile, level)); ArrayList candidateCodecList = new ArrayList(); int numCodecs = MediaCodecList.getCodecCount(); for (int i = 0; i < numCodecs; i++) { MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); Log.d(TAG, String.format(Locale.US, " found codec: %s", codecInfo.getName())); if (codecInfo.isEncoder()) continue; String[] types = codecInfo.getSupportedTypes(); if (types == null) continue; for(String type: types) { if (TextUtils.isEmpty(type)) continue; Log.d(TAG, String.format(Locale.US, " mime: %s", type)); if (!type.equalsIgnoreCase(mimeType)) continue; IjkMediaCodecInfo candidate = IjkMediaCodecInfo.setupCandidate(codecInfo, mimeType); if (candidate == null) continue; candidateCodecList.add(candidate); Log.i(TAG, String.format(Locale.US, "candidate codec: %s rank=%d", codecInfo.getName(), candidate.mRank)); candidate.dumpProfileLevels(mimeType); } } if (candidateCodecList.isEmpty()) { return null; } IjkMediaCodecInfo bestCodec = candidateCodecList.get(0); for (IjkMediaCodecInfo codec : candidateCodecList) { if (codec.mRank > bestCodec.mRank) { bestCodec = codec; } } if (bestCodec.mRank < IjkMediaCodecInfo.RANK_LAST_CHANCE) { Log.w(TAG, String.format(Locale.US, "unaccetable codec: %s", bestCodec.mCodecInfo.getName())); return null; } Log.i(TAG, String.format(Locale.US, "selected codec: %s rank=%d", bestCodec.mCodecInfo.getName(), bestCodec.mRank)); return bestCodec.mCodecInfo.getName(); } } public static native void native_profileBegin(String libName); public static native void native_profileEnd(); public static native void native_setLogLevel(int level); } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkTimedText.java ================================================ /* * Copyright (C) 2016 Zheng Yuan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player; import android.graphics.Rect; import java.lang.String; public final class IjkTimedText { private Rect mTextBounds = null; private String mTextChars = null; public IjkTimedText(Rect bounds, String text) { mTextBounds = bounds; mTextChars = text; } public Rect getBounds() { return mTextBounds; } public String getText() { return mTextChars; } } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/MediaInfo.java ================================================ /* * Copyright (C) 2013-2014 Bilibili * Copyright (C) 2013-2014 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player; public class MediaInfo { public String mMediaPlayerName; public String mVideoDecoder; public String mVideoDecoderImpl; public String mAudioDecoder; public String mAudioDecoderImpl; public IjkMediaMeta mMeta; } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/MediaPlayerProxy.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player; import android.annotation.TargetApi; import android.content.Context; import android.net.Uri; import android.os.Build; import android.view.Surface; import android.view.SurfaceHolder; import java.io.FileDescriptor; import java.io.IOException; import java.util.Map; import tv.danmaku.ijk.media.player.misc.IMediaDataSource; import tv.danmaku.ijk.media.player.misc.ITrackInfo; public class MediaPlayerProxy implements IMediaPlayer { protected final IMediaPlayer mBackEndMediaPlayer; public MediaPlayerProxy(IMediaPlayer backEndMediaPlayer) { mBackEndMediaPlayer = backEndMediaPlayer; } public IMediaPlayer getInternalMediaPlayer() { return mBackEndMediaPlayer; } @Override public void setDisplay(SurfaceHolder sh) { mBackEndMediaPlayer.setDisplay(sh); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Override public void setSurface(Surface surface) { mBackEndMediaPlayer.setSurface(surface); } @Override public void setDataSource(Context context, Uri uri) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { mBackEndMediaPlayer.setDataSource(context, uri); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Override public void setDataSource(Context context, Uri uri, Map headers) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { mBackEndMediaPlayer.setDataSource(context, uri, headers); } @Override public void setDataSource(FileDescriptor fd) throws IOException, IllegalArgumentException, IllegalStateException { mBackEndMediaPlayer.setDataSource(fd); } @Override public void setDataSource(String path) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { mBackEndMediaPlayer.setDataSource(path); } @Override public void setDataSource(IMediaDataSource mediaDataSource) { mBackEndMediaPlayer.setDataSource(mediaDataSource); } @Override public String getDataSource() { return mBackEndMediaPlayer.getDataSource(); } @Override public void prepareAsync() throws IllegalStateException { mBackEndMediaPlayer.prepareAsync(); } @Override public void start() throws IllegalStateException { mBackEndMediaPlayer.start(); } @Override public void stop() throws IllegalStateException { mBackEndMediaPlayer.stop(); } @Override public void pause() throws IllegalStateException { mBackEndMediaPlayer.pause(); } @Override public void setScreenOnWhilePlaying(boolean screenOn) { mBackEndMediaPlayer.setScreenOnWhilePlaying(screenOn); } @Override public int getVideoWidth() { return mBackEndMediaPlayer.getVideoWidth(); } @Override public int getVideoHeight() { return mBackEndMediaPlayer.getVideoHeight(); } @Override public boolean isPlaying() { return mBackEndMediaPlayer.isPlaying(); } @Override public void seekTo(long msec) throws IllegalStateException { mBackEndMediaPlayer.seekTo(msec); } @Override public long getCurrentPosition() { return mBackEndMediaPlayer.getCurrentPosition(); } @Override public long getDuration() { return mBackEndMediaPlayer.getDuration(); } @Override public void release() { mBackEndMediaPlayer.release(); } @Override public void reset() { mBackEndMediaPlayer.reset(); } @Override public void setVolume(float leftVolume, float rightVolume) { mBackEndMediaPlayer.setVolume(leftVolume, rightVolume); } @Override public int getAudioSessionId() { return mBackEndMediaPlayer.getAudioSessionId(); } @Override public MediaInfo getMediaInfo() { return mBackEndMediaPlayer.getMediaInfo(); } @Override public void setLogEnabled(boolean enable) { } @Override public boolean isPlayable() { return false; } @Override public void setOnPreparedListener(OnPreparedListener listener) { if (listener != null) { final OnPreparedListener finalListener = listener; mBackEndMediaPlayer.setOnPreparedListener(new OnPreparedListener() { @Override public void onPrepared(IMediaPlayer mp) { finalListener.onPrepared(MediaPlayerProxy.this); } }); } else { mBackEndMediaPlayer.setOnPreparedListener(null); } } @Override public void setOnCompletionListener(OnCompletionListener listener) { if (listener != null) { final OnCompletionListener finalListener = listener; mBackEndMediaPlayer.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(IMediaPlayer mp) { finalListener.onCompletion(MediaPlayerProxy.this); } }); } else { mBackEndMediaPlayer.setOnCompletionListener(null); } } @Override public void setOnBufferingUpdateListener(OnBufferingUpdateListener listener) { if (listener != null) { final OnBufferingUpdateListener finalListener = listener; mBackEndMediaPlayer.setOnBufferingUpdateListener(new OnBufferingUpdateListener() { @Override public void onBufferingUpdate(IMediaPlayer mp, int percent) { finalListener.onBufferingUpdate(MediaPlayerProxy.this, percent); } }); } else { mBackEndMediaPlayer.setOnBufferingUpdateListener(null); } } @Override public void setOnSeekCompleteListener(OnSeekCompleteListener listener) { if (listener != null) { final OnSeekCompleteListener finalListener = listener; mBackEndMediaPlayer.setOnSeekCompleteListener(new OnSeekCompleteListener() { @Override public void onSeekComplete(IMediaPlayer mp) { finalListener.onSeekComplete(MediaPlayerProxy.this); } }); } else { mBackEndMediaPlayer.setOnSeekCompleteListener(null); } } @Override public void setOnVideoSizeChangedListener(OnVideoSizeChangedListener listener) { if (listener != null) { final OnVideoSizeChangedListener finalListener = listener; mBackEndMediaPlayer.setOnVideoSizeChangedListener(new OnVideoSizeChangedListener() { @Override public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sar_num, int sar_den) { finalListener.onVideoSizeChanged(MediaPlayerProxy.this, width, height, sar_num, sar_den); } }); } else { mBackEndMediaPlayer.setOnVideoSizeChangedListener(null); } } @Override public void setOnErrorListener(OnErrorListener listener) { if (listener != null) { final OnErrorListener finalListener = listener; mBackEndMediaPlayer.setOnErrorListener(new OnErrorListener() { @Override public boolean onError(IMediaPlayer mp, int what, int extra) { return finalListener.onError(MediaPlayerProxy.this, what, extra); } }); } else { mBackEndMediaPlayer.setOnErrorListener(null); } } @Override public void setOnInfoListener(OnInfoListener listener) { if (listener != null) { final OnInfoListener finalListener = listener; mBackEndMediaPlayer.setOnInfoListener(new OnInfoListener() { @Override public boolean onInfo(IMediaPlayer mp, int what, int extra) { return finalListener.onInfo(MediaPlayerProxy.this, what, extra); } }); } else { mBackEndMediaPlayer.setOnInfoListener(null); } } @Override public void setOnTimedTextListener(OnTimedTextListener listener) { if (listener != null) { final OnTimedTextListener finalListener = listener; mBackEndMediaPlayer.setOnTimedTextListener(new OnTimedTextListener() { @Override public void onTimedText(IMediaPlayer mp, IjkTimedText text) { finalListener.onTimedText(MediaPlayerProxy.this, text); } }); } else { mBackEndMediaPlayer.setOnTimedTextListener(null); } } @Override public void setAudioStreamType(int streamtype) { mBackEndMediaPlayer.setAudioStreamType(streamtype); } @Override public void setKeepInBackground(boolean keepInBackground) { mBackEndMediaPlayer.setKeepInBackground(keepInBackground); } @Override public int getVideoSarNum() { return mBackEndMediaPlayer.getVideoSarNum(); } @Override public int getVideoSarDen() { return mBackEndMediaPlayer.getVideoSarDen(); } @Override public void setWakeMode(Context context, int mode) { mBackEndMediaPlayer.setWakeMode(context, mode); } @Override public ITrackInfo[] getTrackInfo() { return mBackEndMediaPlayer.getTrackInfo(); } @Override public void setLooping(boolean looping) { mBackEndMediaPlayer.setLooping(looping); } @Override public boolean isLooping() { return mBackEndMediaPlayer.isLooping(); } } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/TextureMediaPlayer.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player; import android.annotation.TargetApi; import android.graphics.SurfaceTexture; import android.os.Build; import android.view.Surface; import android.view.SurfaceHolder; @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public class TextureMediaPlayer extends MediaPlayerProxy implements IMediaPlayer, ISurfaceTextureHolder { private SurfaceTexture mSurfaceTexture; private ISurfaceTextureHost mSurfaceTextureHost; public TextureMediaPlayer(IMediaPlayer backEndMediaPlayer) { super(backEndMediaPlayer); } public void releaseSurfaceTexture() { if (mSurfaceTexture != null) { if (mSurfaceTextureHost != null) { mSurfaceTextureHost.releaseSurfaceTexture(mSurfaceTexture); } else { mSurfaceTexture.release(); } mSurfaceTexture = null; } } //-------------------- // IMediaPlayer //-------------------- @Override public void reset() { super.reset(); releaseSurfaceTexture(); } @Override public void release() { super.release(); releaseSurfaceTexture(); } @Override public void setDisplay(SurfaceHolder sh) { if (mSurfaceTexture == null) super.setDisplay(sh); } @Override public void setSurface(Surface surface) { if (mSurfaceTexture == null) super.setSurface(surface); } //-------------------- // ISurfaceTextureHolder //-------------------- @Override public void setSurfaceTexture(SurfaceTexture surfaceTexture) { if (mSurfaceTexture == surfaceTexture) return; releaseSurfaceTexture(); mSurfaceTexture = surfaceTexture; if (surfaceTexture == null) { super.setSurface(null); } else { super.setSurface(new Surface(surfaceTexture)); } } @Override public SurfaceTexture getSurfaceTexture() { return mSurfaceTexture; } @Override public void setSurfaceTextureHost(ISurfaceTextureHost surfaceTextureHost) { mSurfaceTextureHost = surfaceTextureHost; } } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/annotations/AccessedByNative.java ================================================ /* * Copyright (C) 2013-2014 Bilibili * Copyright (C) 2013-2014 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * is used by the JNI generator to create the necessary JNI * bindings and expose this method to native code. */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.CLASS) public @interface AccessedByNative { } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/annotations/CalledByNative.java ================================================ /* * Copyright (C) 2013-2014 Bilibili * Copyright (C) 2013-2014 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * is used by the JNI generator to create the necessary JNI * bindings and expose this method to native code. */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.CLASS) public @interface CalledByNative { /* * If present, tells which inner class the method belongs to. */ String value() default ""; } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/exceptions/IjkMediaException.java ================================================ /* * Copyright (C) 2013-2014 Bilibili * Copyright (C) 2013-2014 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player.exceptions; public class IjkMediaException extends Exception { private static final long serialVersionUID = 7234796519009099506L; } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ffmpeg/FFmpegApi.java ================================================ package tv.danmaku.ijk.media.player.ffmpeg; public class FFmpegApi { public static native String av_base64_encode(byte in[]); } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/AndroidMediaFormat.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player.misc; import android.annotation.TargetApi; import android.media.MediaFormat; import android.os.Build; public class AndroidMediaFormat implements IMediaFormat { private final MediaFormat mMediaFormat; public AndroidMediaFormat(MediaFormat mediaFormat) { mMediaFormat = mediaFormat; } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override public int getInteger(String name) { if (mMediaFormat == null) return 0; return mMediaFormat.getInteger(name); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override public String getString(String name) { if (mMediaFormat == null) return null; return mMediaFormat.getString(name); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override public String toString() { StringBuilder out = new StringBuilder(128); out.append(getClass().getName()); out.append('{'); if (mMediaFormat != null) { out.append(mMediaFormat.toString()); } else { out.append("null"); } out.append('}'); return out.toString(); } } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/AndroidTrackInfo.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player.misc; import android.annotation.TargetApi; import android.media.MediaFormat; import android.media.MediaPlayer; import android.os.Build; public class AndroidTrackInfo implements ITrackInfo { private final MediaPlayer.TrackInfo mTrackInfo; public static AndroidTrackInfo[] fromMediaPlayer(MediaPlayer mp) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) return fromTrackInfo(mp.getTrackInfo()); return null; } private static AndroidTrackInfo[] fromTrackInfo(MediaPlayer.TrackInfo[] trackInfos) { if (trackInfos == null) return null; AndroidTrackInfo androidTrackInfo[] = new AndroidTrackInfo[trackInfos.length]; for (int i = 0; i < trackInfos.length; ++i) { androidTrackInfo[i] = new AndroidTrackInfo(trackInfos[i]); } return androidTrackInfo; } private AndroidTrackInfo(MediaPlayer.TrackInfo trackInfo) { mTrackInfo = trackInfo; } @TargetApi(Build.VERSION_CODES.KITKAT) @Override public IMediaFormat getFormat() { if (mTrackInfo == null) return null; if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return null; MediaFormat mediaFormat = mTrackInfo.getFormat(); if (mediaFormat == null) return null; return new AndroidMediaFormat(mediaFormat); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override public String getLanguage() { if (mTrackInfo == null) return "und"; return mTrackInfo.getLanguage(); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override public int getTrackType() { if (mTrackInfo == null) return MEDIA_TRACK_TYPE_UNKNOWN; return mTrackInfo.getTrackType(); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override public String toString() { StringBuilder out = new StringBuilder(128); out.append(getClass().getSimpleName()); out.append('{'); if (mTrackInfo != null) { out.append(mTrackInfo.toString()); } else { out.append("null"); } out.append('}'); return out.toString(); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override public String getInfoInline() { if (mTrackInfo != null) { return mTrackInfo.toString(); } else { return "null"; } } } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IAndroidIO.java ================================================ /* * Copyright (C) 2016 Bilibili * Copyright (C) 2016 Raymond Zheng * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player.misc; import java.io.IOException; @SuppressWarnings("RedundantThrows") public interface IAndroidIO { int open(String url) throws IOException; int read(byte[] buffer, int size) throws IOException; long seek(long offset, int whence) throws IOException; int close() throws IOException; } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IMediaDataSource.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player.misc; import java.io.IOException; @SuppressWarnings("RedundantThrows") public interface IMediaDataSource { int readAt(long position, byte[] buffer, int offset, int size) throws IOException; long getSize() throws IOException; void close() throws IOException; } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IMediaFormat.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player.misc; public interface IMediaFormat { // Common keys String KEY_MIME = "mime"; // Video Keys String KEY_WIDTH = "width"; String KEY_HEIGHT = "height"; String getString(String name); int getInteger(String name); } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/ITrackInfo.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player.misc; public interface ITrackInfo { int MEDIA_TRACK_TYPE_AUDIO = 2; int MEDIA_TRACK_TYPE_METADATA = 5; int MEDIA_TRACK_TYPE_SUBTITLE = 4; int MEDIA_TRACK_TYPE_TIMEDTEXT = 3; int MEDIA_TRACK_TYPE_UNKNOWN = 0; int MEDIA_TRACK_TYPE_VIDEO = 1; IMediaFormat getFormat(); String getLanguage(); int getTrackType(); String getInfoInline(); } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IjkMediaFormat.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player.misc; import android.annotation.TargetApi; import android.os.Build; import android.text.TextUtils; import java.util.HashMap; import java.util.Locale; import java.util.Map; import tv.danmaku.ijk.media.player.IjkMediaMeta; public class IjkMediaFormat implements IMediaFormat { // Common public static final String KEY_IJK_CODEC_LONG_NAME_UI = "ijk-codec-long-name-ui"; public static final String KEY_IJK_CODEC_NAME_UI = "ijk-codec-name-ui"; public static final String KEY_IJK_BIT_RATE_UI = "ijk-bit-rate-ui"; // Video public static final String KEY_IJK_CODEC_PROFILE_LEVEL_UI = "ijk-profile-level-ui"; public static final String KEY_IJK_CODEC_PIXEL_FORMAT_UI = "ijk-pixel-format-ui"; public static final String KEY_IJK_RESOLUTION_UI = "ijk-resolution-ui"; public static final String KEY_IJK_FRAME_RATE_UI = "ijk-frame-rate-ui"; // Audio public static final String KEY_IJK_SAMPLE_RATE_UI = "ijk-sample-rate-ui"; public static final String KEY_IJK_CHANNEL_UI = "ijk-channel-ui"; // Codec public static final String CODEC_NAME_H264 = "h264"; public final IjkMediaMeta.IjkStreamMeta mMediaFormat; public IjkMediaFormat(IjkMediaMeta.IjkStreamMeta streamMeta) { mMediaFormat = streamMeta; } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override public int getInteger(String name) { if (mMediaFormat == null) return 0; return mMediaFormat.getInt(name); } @Override public String getString(String name) { if (mMediaFormat == null) return null; if (sFormatterMap.containsKey(name)) { Formatter formatter = sFormatterMap.get(name); return formatter.format(this); } return mMediaFormat.getString(name); } //------------------------- // Formatter //------------------------- private static abstract class Formatter { public String format(IjkMediaFormat mediaFormat) { String value = doFormat(mediaFormat); if (TextUtils.isEmpty(value)) return getDefaultString(); return value; } protected abstract String doFormat(IjkMediaFormat mediaFormat); @SuppressWarnings("SameReturnValue") protected String getDefaultString() { return "N/A"; } } private static final Map sFormatterMap = new HashMap(); { sFormatterMap.put(KEY_IJK_CODEC_LONG_NAME_UI, new Formatter() { @Override public String doFormat(IjkMediaFormat mediaFormat) { return mMediaFormat.getString(IjkMediaMeta.IJKM_KEY_CODEC_LONG_NAME); } }); sFormatterMap.put(KEY_IJK_CODEC_NAME_UI, new Formatter() { @Override public String doFormat(IjkMediaFormat mediaFormat) { return mMediaFormat.getString(IjkMediaMeta.IJKM_KEY_CODEC_NAME); } }); sFormatterMap.put(KEY_IJK_BIT_RATE_UI, new Formatter() { @Override protected String doFormat(IjkMediaFormat mediaFormat) { int bitRate = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_BITRATE); if (bitRate <= 0) { return null; } else if (bitRate < 1000) { return String.format(Locale.US, "%d bit/s", bitRate); } else { return String.format(Locale.US, "%d kb/s", bitRate / 1000); } } }); sFormatterMap.put(KEY_IJK_CODEC_PROFILE_LEVEL_UI, new Formatter() { @Override protected String doFormat(IjkMediaFormat mediaFormat) { int profileIndex = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_CODEC_PROFILE_ID); String profile; switch (profileIndex) { case IjkMediaMeta.FF_PROFILE_H264_BASELINE: profile = "Baseline"; break; case IjkMediaMeta.FF_PROFILE_H264_CONSTRAINED_BASELINE: profile = "Constrained Baseline"; break; case IjkMediaMeta.FF_PROFILE_H264_MAIN: profile = "Main"; break; case IjkMediaMeta.FF_PROFILE_H264_EXTENDED: profile = "Extended"; break; case IjkMediaMeta.FF_PROFILE_H264_HIGH: profile = "High"; break; case IjkMediaMeta.FF_PROFILE_H264_HIGH_10: profile = "High 10"; break; case IjkMediaMeta.FF_PROFILE_H264_HIGH_10_INTRA: profile = "High 10 Intra"; break; case IjkMediaMeta.FF_PROFILE_H264_HIGH_422: profile = "High 4:2:2"; break; case IjkMediaMeta.FF_PROFILE_H264_HIGH_422_INTRA: profile = "High 4:2:2 Intra"; break; case IjkMediaMeta.FF_PROFILE_H264_HIGH_444: profile = "High 4:4:4"; break; case IjkMediaMeta.FF_PROFILE_H264_HIGH_444_PREDICTIVE: profile = "High 4:4:4 Predictive"; break; case IjkMediaMeta.FF_PROFILE_H264_HIGH_444_INTRA: profile = "High 4:4:4 Intra"; break; case IjkMediaMeta.FF_PROFILE_H264_CAVLC_444: profile = "CAVLC 4:4:4"; break; default: return null; } StringBuilder sb = new StringBuilder(); sb.append(profile); String codecName = mediaFormat.getString(IjkMediaMeta.IJKM_KEY_CODEC_NAME); if (!TextUtils.isEmpty(codecName) && codecName.equalsIgnoreCase(CODEC_NAME_H264)) { int level = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_CODEC_LEVEL); if (level < 10) return sb.toString(); sb.append(" Profile Level "); sb.append((level / 10) % 10); if ((level % 10) != 0) { sb.append("."); sb.append(level % 10); } } return sb.toString(); } }); sFormatterMap.put(KEY_IJK_CODEC_PIXEL_FORMAT_UI, new Formatter() { @Override protected String doFormat(IjkMediaFormat mediaFormat) { return mediaFormat.getString(IjkMediaMeta.IJKM_KEY_CODEC_PIXEL_FORMAT); } }); sFormatterMap.put(KEY_IJK_RESOLUTION_UI, new Formatter() { @Override protected String doFormat(IjkMediaFormat mediaFormat) { int width = mediaFormat.getInteger(KEY_WIDTH); int height = mediaFormat.getInteger(KEY_HEIGHT); int sarNum = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_SAR_NUM); int sarDen = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_SAR_DEN); if (width <= 0 || height <= 0) { return null; } else if (sarNum <= 0 || sarDen <= 0) { return String.format(Locale.US, "%d x %d", width, height); } else { return String.format(Locale.US, "%d x %d [SAR %d:%d]", width, height, sarNum, sarDen); } } }); sFormatterMap.put(KEY_IJK_FRAME_RATE_UI, new Formatter() { @Override protected String doFormat(IjkMediaFormat mediaFormat) { int fpsNum = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_FPS_NUM); int fpsDen = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_FPS_DEN); if (fpsNum <= 0 || fpsDen <= 0) { return null; } else { return String.valueOf(((float) (fpsNum)) / fpsDen); } } }); sFormatterMap.put(KEY_IJK_SAMPLE_RATE_UI, new Formatter() { @Override protected String doFormat(IjkMediaFormat mediaFormat) { int sampleRate = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_SAMPLE_RATE); if (sampleRate <= 0) { return null; } else { return String.format(Locale.US, "%d Hz", sampleRate); } } }); sFormatterMap.put(KEY_IJK_CHANNEL_UI, new Formatter() { @Override protected String doFormat(IjkMediaFormat mediaFormat) { int channelLayout = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_CHANNEL_LAYOUT); if (channelLayout <= 0) { return null; } else { if (channelLayout == IjkMediaMeta.AV_CH_LAYOUT_MONO) { return "mono"; } else if (channelLayout == IjkMediaMeta.AV_CH_LAYOUT_STEREO) { return "stereo"; } else { return String.format(Locale.US, "%x", channelLayout); } } } }); } } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IjkTrackInfo.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player.misc; import android.text.TextUtils; import tv.danmaku.ijk.media.player.IjkMediaMeta; public class IjkTrackInfo implements ITrackInfo { private int mTrackType = MEDIA_TRACK_TYPE_UNKNOWN; private IjkMediaMeta.IjkStreamMeta mStreamMeta; public IjkTrackInfo(IjkMediaMeta.IjkStreamMeta streamMeta) { mStreamMeta = streamMeta; } public void setMediaMeta(IjkMediaMeta.IjkStreamMeta streamMeta) { mStreamMeta = streamMeta; } @Override public IMediaFormat getFormat() { return new IjkMediaFormat(mStreamMeta); } @Override public String getLanguage() { if (mStreamMeta == null || TextUtils.isEmpty(mStreamMeta.mLanguage)) return "und"; return mStreamMeta.mLanguage; } @Override public int getTrackType() { return mTrackType; } public void setTrackType(int trackType) { mTrackType = trackType; } @Override public String toString() { return getClass().getSimpleName() + '{' + getInfoInline() + "}"; } @Override public String getInfoInline() { StringBuilder out = new StringBuilder(128); switch (mTrackType) { case MEDIA_TRACK_TYPE_VIDEO: out.append("VIDEO"); out.append(", "); out.append(mStreamMeta.getCodecShortNameInline()); out.append(", "); out.append(mStreamMeta.getBitrateInline()); out.append(", "); out.append(mStreamMeta.getResolutionInline()); break; case MEDIA_TRACK_TYPE_AUDIO: out.append("AUDIO"); out.append(", "); out.append(mStreamMeta.getCodecShortNameInline()); out.append(", "); out.append(mStreamMeta.getBitrateInline()); out.append(", "); out.append(mStreamMeta.getSampleRateInline()); break; case MEDIA_TRACK_TYPE_TIMEDTEXT: out.append("TIMEDTEXT"); out.append(", "); out.append(mStreamMeta.mLanguage); break; case MEDIA_TRACK_TYPE_SUBTITLE: out.append("SUBTITLE"); break; default: out.append("UNKNOWN"); break; } return out.toString(); } } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/pragma/DebugLog.java ================================================ /* * Copyright (C) 2013 Bilibili * Copyright (C) 2013 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player.pragma; import java.util.Locale; import android.util.Log; @SuppressWarnings({"SameParameterValue", "WeakerAccess"}) public class DebugLog { public static final boolean ENABLE_ERROR = Pragma.ENABLE_VERBOSE; public static final boolean ENABLE_INFO = Pragma.ENABLE_VERBOSE; public static final boolean ENABLE_WARN = Pragma.ENABLE_VERBOSE; public static final boolean ENABLE_DEBUG = Pragma.ENABLE_VERBOSE; public static final boolean ENABLE_VERBOSE = Pragma.ENABLE_VERBOSE; public static void e(String tag, String msg) { if (ENABLE_ERROR) { Log.e(tag, msg); } } public static void e(String tag, String msg, Throwable tr) { if (ENABLE_ERROR) { Log.e(tag, msg, tr); } } public static void efmt(String tag, String fmt, Object... args) { if (ENABLE_ERROR) { String msg = String.format(Locale.US, fmt, args); Log.e(tag, msg); } } public static void i(String tag, String msg) { if (ENABLE_INFO) { Log.i(tag, msg); } } public static void i(String tag, String msg, Throwable tr) { if (ENABLE_INFO) { Log.i(tag, msg, tr); } } public static void ifmt(String tag, String fmt, Object... args) { if (ENABLE_INFO) { String msg = String.format(Locale.US, fmt, args); Log.i(tag, msg); } } public static void w(String tag, String msg) { if (ENABLE_WARN) { Log.w(tag, msg); } } public static void w(String tag, String msg, Throwable tr) { if (ENABLE_WARN) { Log.w(tag, msg, tr); } } public static void wfmt(String tag, String fmt, Object... args) { if (ENABLE_WARN) { String msg = String.format(Locale.US, fmt, args); Log.w(tag, msg); } } public static void d(String tag, String msg) { if (ENABLE_DEBUG) { Log.d(tag, msg); } } public static void d(String tag, String msg, Throwable tr) { if (ENABLE_DEBUG) { Log.d(tag, msg, tr); } } public static void dfmt(String tag, String fmt, Object... args) { if (ENABLE_DEBUG) { String msg = String.format(Locale.US, fmt, args); Log.d(tag, msg); } } public static void v(String tag, String msg) { if (ENABLE_VERBOSE) { Log.v(tag, msg); } } public static void v(String tag, String msg, Throwable tr) { if (ENABLE_VERBOSE) { Log.v(tag, msg, tr); } } public static void vfmt(String tag, String fmt, Object... args) { if (ENABLE_VERBOSE) { String msg = String.format(Locale.US, fmt, args); Log.v(tag, msg); } } public static void printStackTrace(Throwable e) { if (ENABLE_WARN) { e.printStackTrace(); } } public static void printCause(Throwable e) { if (ENABLE_WARN) { Throwable cause = e.getCause(); if (cause != null) e = cause; printStackTrace(e); } } } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/pragma/Pragma.java ================================================ /* * Copyright (C) 2013 Bilibili * Copyright (C) 2013 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player.pragma; /*- * configurated by app project */ public class Pragma { public static final boolean ENABLE_VERBOSE = true; } ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/project.properties ================================================ # This file is automatically generated by Android Tools. # Do not modify this file -- YOUR CHANGES WILL BE ERASED! # # This file must be checked in Version Control Systems. # # To customize properties used by the Ant build system edit # "ant.properties", and override values to adapt the script to your # project structure. # # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. target=android-22 android.library=true ================================================ FILE: android/ijkplayer/ijkplayer-java/src/main/res/values/strings.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-x86/.gitignore ================================================ /build ================================================ FILE: android/ijkplayer/ijkplayer-x86/build.gradle ================================================ apply plugin: 'com.android.library' android { // http://tools.android.com/tech-docs/new-build-system/tips //noinspection GroovyAssignabilityCheck compileSdkVersion rootProject.ext.compileSdkVersion //noinspection GroovyAssignabilityCheck buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { minSdkVersion 9 targetSdkVersion rootProject.ext.targetSdkVersion } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets.main { jniLibs.srcDirs 'src/main/libs' jni.srcDirs = [] // This prevents the auto generation of Android.mk } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) } apply from: new File(rootProject.projectDir, "tools/gradle-on-demand.gradle"); ================================================ FILE: android/ijkplayer/ijkplayer-x86/gradle.properties ================================================ POM_NAME=ijkplayer-x86 POM_ARTIFACT_ID=ijkplayer-x86 POM_PACKAGING=aar ================================================ FILE: android/ijkplayer/ijkplayer-x86/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /opt/android/ADK/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: android/ijkplayer/ijkplayer-x86/src/androidTest/java/tv/danmaku/ijk/media/ijkplayer/ApplicationTest.java ================================================ package tv.danmaku.ijk.media.ijkplayer; import android.app.Application; import android.test.ApplicationTestCase; /** * Testing Fundamentals */ public class ApplicationTest extends ApplicationTestCase { public ApplicationTest() { super(Application.class); } } ================================================ FILE: android/ijkplayer/ijkplayer-x86/src/main/.classpath ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-x86/src/main/.project ================================================ ijkplayer-x86 com.android.ide.eclipse.adt.ResourceManagerBuilder com.android.ide.eclipse.adt.PreCompilerBuilder org.eclipse.jdt.core.javabuilder com.android.ide.eclipse.adt.ApkBuilder com.android.ide.eclipse.adt.AndroidNature org.eclipse.jdt.core.javanature ================================================ FILE: android/ijkplayer/ijkplayer-x86/src/main/.settings/org.eclipse.jdt.core.prefs ================================================ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.compliance=1.6 org.eclipse.jdt.core.compiler.source=1.6 ================================================ FILE: android/ijkplayer/ijkplayer-x86/src/main/AndroidManifest.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-x86/src/main/java/tv/danmaku/ijk/media/player_x86/Pragma.java ================================================ /* * Copyright (C) 2015 Bilibili * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package tv.danmaku.ijk.media.player_x86; public class Pragma { } ================================================ FILE: android/ijkplayer/ijkplayer-x86/src/main/jni/Application.mk ================================================ # Copyright (c) 2013-2014 Bilibili # copyright (c) 2013-2014 Zhang Rui # # This file is part of ijkPlayer. # # ijkPlayer 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. # # ijkPlayer 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 ijkPlayer; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA APP_OPTIM := release APP_PLATFORM := android-9 APP_ABI := x86 NDK_TOOLCHAIN_VERSION=4.9 APP_PIE := false APP_STL := stlport_static APP_CFLAGS := -O3 -Wall -pipe \ -ffast-math \ -fstrict-aliasing -Werror=strict-aliasing \ -Wno-psabi -Wa,--noexecstack \ -DANDROID -DNDEBUG ================================================ FILE: android/ijkplayer/ijkplayer-x86/src/main/jni/ffmpeg/Android.mk ================================================ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := ijkffmpeg LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/libijkffmpeg.so include $(PREBUILT_SHARED_LIBRARY) ================================================ FILE: android/ijkplayer/ijkplayer-x86/src/main/project.properties ================================================ # This file is automatically generated by Android Tools. # Do not modify this file -- YOUR CHANGES WILL BE ERASED! # # This file must be checked in Version Control Systems. # # To customize properties used by the Ant build system edit # "ant.properties", and override values to adapt the script to your # project structure. # # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. target=android-22 android.library=true ================================================ FILE: android/ijkplayer/ijkplayer-x86/src/main/res/values/strings.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-x86_64/.gitignore ================================================ /build ================================================ FILE: android/ijkplayer/ijkplayer-x86_64/build.gradle ================================================ apply plugin: 'com.android.library' android { // http://tools.android.com/tech-docs/new-build-system/tips //noinspection GroovyAssignabilityCheck compileSdkVersion rootProject.ext.compileSdkVersion //noinspection GroovyAssignabilityCheck buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { minSdkVersion 21 targetSdkVersion rootProject.ext.targetSdkVersion } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets.main { jniLibs.srcDirs 'src/main/libs' jni.srcDirs = [] // This prevents the auto generation of Android.mk } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) } apply from: new File(rootProject.projectDir, "tools/gradle-on-demand.gradle"); ================================================ FILE: android/ijkplayer/ijkplayer-x86_64/gradle.properties ================================================ POM_NAME=ijkplayer-x86_64 POM_ARTIFACT_ID=ijkplayer-x86_64 POM_PACKAGING=aar ================================================ FILE: android/ijkplayer/ijkplayer-x86_64/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /opt/android/ADK/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: android/ijkplayer/ijkplayer-x86_64/src/androidTest/java/com/example/ijkplayer_x86_64/ApplicationTest.java ================================================ package com.example.ijkplayer_x86_64; import android.app.Application; import android.test.ApplicationTestCase; /** * Testing Fundamentals */ public class ApplicationTest extends ApplicationTestCase { public ApplicationTest() { super(Application.class); } } ================================================ FILE: android/ijkplayer/ijkplayer-x86_64/src/main/AndroidManifest.xml ================================================ ================================================ FILE: android/ijkplayer/ijkplayer-x86_64/src/main/jni/Application.mk ================================================ # Copyright (c) 2013-2014 Bilibili # copyright (c) 2013-2014 Zhang Rui # # This file is part of ijkPlayer. # # ijkPlayer 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. # # ijkPlayer 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 ijkPlayer; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA APP_OPTIM := release APP_PLATFORM := android-21 APP_ABI := x86_64 NDK_TOOLCHAIN_VERSION=4.9 APP_PIE := false APP_STL := stlport_static APP_CFLAGS := -O3 -Wall -pipe \ -ffast-math \ -fstrict-aliasing -Werror=strict-aliasing \ -Wno-psabi -Wa,--noexecstack \ -DANDROID -DNDEBUG ================================================ FILE: android/ijkplayer/ijkplayer-x86_64/src/main/jni/ffmpeg/Android.mk ================================================ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := ijkffmpeg LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/libijkffmpeg.so include $(PREBUILT_SHARED_LIBRARY) ================================================ FILE: android/ijkplayer/ijkplayer-x86_64/src/main/res/values/strings.xml ================================================ ijkplayer-x86_64 ================================================ FILE: android/ijkplayer/settings.gradle ================================================ include ':ijkplayer-armv5', ':ijkplayer-x86_64' include ':ijkplayer-armv7a' include ':ijkplayer-arm64' include ':ijkplayer-x86' include ':ijkplayer-java' include ':ijkplayer-exo' include ':ijkplayer-example' ================================================ FILE: android/ijkplayer/tools/gradle-bintray-upload.gradle ================================================ /* * Copyright 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.jfrog.bintray' group = GROUP version = VERSION_NAME bintray { user = project.hasProperty('BINTRAY_USER') ? BINTRAY_USER : System.getenv('BINTRAY_USER') key = project.hasProperty('BINTRAY_APIKEY') ? BINTRAY_APIKEY : System.getenv('BINTRAY_APIKEY') configurations = ['archives'] dryRun = false publish = true pkg { repo = 'maven' name = POM_NAME userOrg = POM_USER_ORG desc = POM_DESCRIPTION websiteUrl = POM_URL vcsUrl = POM_SCM_URL licenses = [POM_LICENSE_NAME] labels = ['FFmpeg', 'Android', 'player'] publicDownloadNumbers = true version { name = VERSION_NAME gpg { sign = true passphrase = project.hasProperty('GPG_PASSWORD') ? GPG_PASSWORD : System.getenv('GPG_PASSWORD') } } } } install { repositories.mavenInstaller { pom.project { name POM_NAME packaging POM_PACKAGING description POM_DESCRIPTION url POM_URL licenses { license { name POM_LICENSE_NAME url POM_LICENSE_URL distribution POM_LICENSE_DIST } } scm { url POM_SCM_URL connection POM_SCM_CONNECTION developerConnection POM_SCM_DEV_CONNECTION } developers { developer { id POM_DEVELOPER_ID name POM_DEVELOPER_NAME email POM_DEVELOPER_EMAIL } } } } } ================================================ FILE: android/ijkplayer/tools/gradle-mvn-push.gradle ================================================ /* * Copyright 2013 Chris Banes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ apply plugin: 'maven' apply plugin: 'signing' def isReleaseBuild() { return VERSION_NAME.contains("SNAPSHOT") == false } def getReleaseRepositoryUrl() { return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" } def getSnapshotRepositoryUrl() { return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL : "https://oss.sonatype.org/content/repositories/snapshots/" } def getRepositoryUsername() { return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "" } def getRepositoryPassword() { return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "" } afterEvaluate { project -> uploadArchives { repositories { mavenDeployer { beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } pom.groupId = GROUP pom.artifactId = POM_ARTIFACT_ID pom.version = VERSION_NAME repository(url: getReleaseRepositoryUrl()) { authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) } snapshotRepository(url: getSnapshotRepositoryUrl()) { authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) } pom.project { name POM_NAME packaging POM_PACKAGING description POM_DESCRIPTION url POM_URL licenses { license { name POM_LICENSE_NAME url POM_LICENSE_URL distribution POM_LICENSE_DIST } } scm { url POM_SCM_URL connection POM_SCM_CONNECTION developerConnection POM_SCM_DEV_CONNECTION } developers { developer { id POM_DEVELOPER_ID name POM_DEVELOPER_NAME email POM_DEVELOPER_EMAIL } } } } } } android.libraryVariants.all { variant -> if(variant.buildType.name.equals("release")) { def jarTask = project.tasks.create(name: "jar${variant.name.capitalize()}", type: Jar) { from variant.javaCompile.destinationDir exclude "**/R.class" exclude "**/R\$**.class" exclude "**/BuildConfig.class" } jarTask.dependsOn variant.javaCompile } } signing { required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } sign configurations.archives } task androidJavadocs(type: Javadoc) { failOnError false source = android.sourceSets.main.java.srcDirs classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) } task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { classifier = 'javadoc' from androidJavadocs.destinationDir } task androidSourcesJar(type: Jar) { classifier = 'sources' from android.sourceSets.main.java.sourceFiles } artifacts { archives androidSourcesJar archives androidJavadocsJar archives jarRelease } } ================================================ FILE: android/ijkplayer/tools/gradle-on-demand.gradle ================================================ /* * Copyright 2016 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ gradle.startParameter.taskNames.each { task -> def taskName = task.split(":").last() switch (taskName) { case "uploadArchives": apply from: new File(rootProject.projectDir, 'tools/gradle-mvn-push.gradle') break; case "bintrayUpload": apply from: new File(rootProject.projectDir, 'tools/gradle-bintray-upload.gradle') break; default: // do nothing break; } } ================================================ FILE: android/patch-debugging-with-lldb.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2014 Chen Hui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # patch_enable () { PARAM_TARGET=$1 case "$PARAM_TARGET" in armv5|armv7a|arm64|x86|x86_64) git apply -- android/patches/0001-gitignore-ignore-.externalNativeBuild.patch echo "git apply ==> patches/0001-gitignore-ignore-.externalNativeBuild.patch" git apply -- android/patches/0002-gradle-upgrade-build-tool-to-2.2.0-beta2.patch echo "git apply ==> patches/0002-gradle-upgrade-build-tool-to-2.2.0-beta2.patch" git apply -- android/patches/0003-$PARAM_TARGET-enable-debugging-with-LLDB.patch echo "git apply ==> patches/0003-$PARAM_TARGET-enable-debugging-with-LLDB.patch" git apply -- android/patches/0004-$PARAM_TARGET-link-prebuilt-staic-libraries-of-ffmepg.patch echo "git apply ==> patches/0004-$PARAM_TARGET-link-prebuilt-staic-libraries-of-ffmepg.patch" ;; esac } patch_disable () { PARAM_TARGET=$1 case "$PARAM_TARGET" in armv5|armv7a|arm64|x86|x86_64) git apply -R android/patches/0004-$PARAM_TARGET-link-prebuilt-staic-libraries-of-ffmepg.patch echo "git apply reverse ==> patches/0004-$PARAM_TARGET-link-prebuilt-staic-libraries-of-ffmepg.patch" git checkout android/ijkplayer/ijkplayer-$PARAM_TARGET/src/main/jni/Android.mk git checkout android/ijkplayer/ijkplayer-example/build.gradle git checkout android/ijkplayer/ijkplayer-$PARAM_TARGET/build.gradle git checkout android/ijkplayer/settings.gradle # git apply -R android/patches/0003-$PARAM_TARGET-enable-debugging-with-LLDB.patch echo "git apply reverse ==> patches/0003-$PARAM_TARGET-enable-debugging-with-LLDB.patch" git apply -R android/patches/0002-gradle-upgrade-build-tool-to-2.2.0-beta2.patch echo "git apply reverse ==> patches/0002-gradle-upgrade-build-tool-to-2.2.0-beta2.patch" git apply -R android/patches/0001-gitignore-ignore-.externalNativeBuild.patch echo "git apply reverse ==> patches/0001-gitignore-ignore-.externalNativeBuild.patch" ;; esac } case "$1" in armv5|armv7a|arm64|x86|x86_64) # patch_enable $1 echo "patch apply ==> $1" patch_enable $1 ;; reverse) case "$2" in armv5|armv7a|arm64|x86|x86_64) echo "patch reverse ==> $2" patch_disable $2 ;; *) echo "Usage:" echo " patch-debugging-with-lldb.sh armv5|armv7a|arm64|x86|x86_64" echo " patch-debugging-with-lldb.sh reverse armv5|armv7a|arm64|x86|x86_64" ;; esac ;; *) echo "Usage:" echo " patch-debugging-with-lldb.sh armv5|armv7a|arm64|x86|x86_64" echo " patch-debugging-with-lldb.sh reverse armv5|armv7a|arm64|x86|x86_64" ;; esac ================================================ FILE: android/patches/0001-gitignore-ignore-.externalNativeBuild.patch ================================================ From dc4847b1e8ff5d35576f840db59aec0a3d3fc72b Mon Sep 17 00:00:00 2001 From: ctiao Date: Mon, 29 Aug 2016 14:48:08 +0800 Subject: [PATCH 1/2] gitignore: ignore ".externalNativeBuild" --- android/ijkplayer/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/android/ijkplayer/.gitignore b/android/ijkplayer/.gitignore index eac8754..2a3badc 100644 --- a/android/ijkplayer/.gitignore +++ b/android/ijkplayer/.gitignore @@ -6,3 +6,4 @@ /build /captures android-ndk-prof +.externalNativeBuild \ No newline at end of file -- 2.7.4 (Apple Git-66) ================================================ FILE: android/patches/0002-gradle-upgrade-build-tool-to-2.2.0-beta2.patch ================================================ From 5d70fa0496f9ebfbcfa3786d85c74c690d66781e Mon Sep 17 00:00:00 2001 From: ctiao Date: Mon, 29 Aug 2016 14:50:34 +0800 Subject: [PATCH 2/2] gradle: upgrade build-tool to 2.2.0-rc1 --- android/ijkplayer/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/ijkplayer/build.gradle b/android/ijkplayer/build.gradle index 0de03ec..6132c1d 100644 --- a/android/ijkplayer/build.gradle +++ b/android/ijkplayer/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.1.3' + classpath 'com.android.tools.build:gradle:2.2.0-rc1' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7' -- 2.7.4 (Apple Git-66) ================================================ FILE: android/patches/0003-arm64-enable-debugging-with-LLDB.patch ================================================ From 8f72e4cdcc3c3ef2d5290be4a755943b972d7239 Mon Sep 17 00:00:00 2001 From: ctiao Date: Mon, 29 Aug 2016 17:06:00 +0800 Subject: [PATCH] arm64: enable debugging with LLDB --- android/ijkplayer/ijkplayer-arm64/build.gradle | 20 ++++++++++++--- .../ijkplayer-arm64/src/main/jni/Android.mk | 29 +++++++++++++++++++++- android/ijkplayer/ijkplayer-example/build.gradle | 16 ++++++------ android/ijkplayer/settings.gradle | 6 ++--- 4 files changed, 56 insertions(+), 15 deletions(-) mode change 120000 => 100644 android/ijkplayer/ijkplayer-arm64/src/main/jni/Android.mk diff --git a/android/ijkplayer/ijkplayer-arm64/build.gradle b/android/ijkplayer/ijkplayer-arm64/build.gradle index a8cbe0c..ccd04e0 100644 --- a/android/ijkplayer/ijkplayer-arm64/build.gradle +++ b/android/ijkplayer/ijkplayer-arm64/build.gradle @@ -10,16 +10,30 @@ android { defaultConfig { minSdkVersion 21 targetSdkVersion rootProject.ext.targetSdkVersion + externalNativeBuild { + ndkBuild { + arguments "NDK_APPLICATION_MK:=src/main/jni/Application.mk" + abiFilters "arm64-v8a" + } + } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } + debug { + debuggable true + jniDebuggable true + ndk { + debuggable true + } + } } - sourceSets.main { - jniLibs.srcDirs 'src/main/libs' - jni.srcDirs = [] // This prevents the auto generation of Android.mk + externalNativeBuild { + ndkBuild { + path 'src/main/jni/Android.mk' + } } } diff --git a/android/ijkplayer/ijkplayer-arm64/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-arm64/src/main/jni/Android.mk deleted file mode 120000 index fb30867..0000000 --- a/android/ijkplayer/ijkplayer-arm64/src/main/jni/Android.mk +++ /dev/null @@ -1 +0,0 @@ -../../../../ijkplayer-armv7a/src/main/jni/Android.mk \ No newline at end of file diff --git a/android/ijkplayer/ijkplayer-arm64/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-arm64/src/main/jni/Android.mk new file mode 100644 index 0000000..6b53c1f --- /dev/null +++ b/android/ijkplayer/ijkplayer-arm64/src/main/jni/Android.mk @@ -0,0 +1,28 @@ +# copyright (c) 2013 Zhang Rui +# +# This file is part of ijkPlayer. +# +# ijkPlayer 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. +# +# ijkPlayer 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 ijkPlayer; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +LOCAL_PATH := $(call my-dir) + +MY_APP_JNI_ROOT := $(realpath $(LOCAL_PATH)) +MY_APP_PRJ_ROOT := $(realpath $(MY_APP_JNI_ROOT)/..) +MY_APP_ANDROID_ROOT := $(realpath $(MY_APP_PRJ_ROOT)/../../../..) + +MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-arm64/output) +MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include) + +include $(call all-subdir-makefiles) diff --git a/android/ijkplayer/ijkplayer-example/build.gradle b/android/ijkplayer/ijkplayer-example/build.gradle index 9afe650..77df829 100644 --- a/android/ijkplayer/ijkplayer-example/build.gradle +++ b/android/ijkplayer/ijkplayer-example/build.gradle @@ -44,15 +44,15 @@ dependencies { compile project(':ijkplayer-java') compile project(':ijkplayer-exo') - all32Compile project(':ijkplayer-armv5') - all32Compile project(':ijkplayer-armv7a') - all32Compile project(':ijkplayer-x86') - - all64Compile project(':ijkplayer-armv5') - all64Compile project(':ijkplayer-armv7a') +// all32Compile project(':ijkplayer-armv5') +// all32Compile project(':ijkplayer-armv7a') +// all32Compile project(':ijkplayer-x86') +// +// all64Compile project(':ijkplayer-armv5') +// all64Compile project(':ijkplayer-armv7a') all64Compile project(':ijkplayer-arm64') - all64Compile project(':ijkplayer-x86') - all64Compile project(':ijkplayer-x86_64') +// all64Compile project(':ijkplayer-x86') +// all64Compile project(':ijkplayer-x86_64') // armv5Compile project(':player-armv5') // armv7aCompile project(':player-armv7a') diff --git a/android/ijkplayer/settings.gradle b/android/ijkplayer/settings.gradle index 758234a..c9e72d9 100644 --- a/android/ijkplayer/settings.gradle +++ b/android/ijkplayer/settings.gradle @@ -1,7 +1,7 @@ -include ':ijkplayer-armv5', ':ijkplayer-x86_64' -include ':ijkplayer-armv7a' +//include ':ijkplayer-armv5', ':ijkplayer-x86_64' +//include ':ijkplayer-armv7a' include ':ijkplayer-arm64' -include ':ijkplayer-x86' +//include ':ijkplayer-x86' include ':ijkplayer-java' include ':ijkplayer-exo' -- 2.7.4 (Apple Git-66) ================================================ FILE: android/patches/0003-armv5-enable-debugging-with-LLDB.patch ================================================ From e7a63003b2f3d15f795128b95085da57dd838945 Mon Sep 17 00:00:00 2001 From: ctiao Date: Mon, 29 Aug 2016 16:23:52 +0800 Subject: [PATCH] armv5: enable debugging with LLDB --- android/ijkplayer/ijkplayer-armv5/build.gradle | 20 ++++++++++++--- .../ijkplayer-armv5/src/main/jni/Android.mk | 29 +++++++++++++++++++++- android/ijkplayer/ijkplayer-example/build.gradle | 14 +++++------ android/ijkplayer/settings.gradle | 8 +++--- 4 files changed, 56 insertions(+), 15 deletions(-) mode change 120000 => 100644 android/ijkplayer/ijkplayer-armv5/src/main/jni/Android.mk diff --git a/android/ijkplayer/ijkplayer-armv5/build.gradle b/android/ijkplayer/ijkplayer-armv5/build.gradle index b3b7b3a..d05f33e 100644 --- a/android/ijkplayer/ijkplayer-armv5/build.gradle +++ b/android/ijkplayer/ijkplayer-armv5/build.gradle @@ -10,16 +10,30 @@ android { defaultConfig { minSdkVersion 9 targetSdkVersion rootProject.ext.targetSdkVersion + externalNativeBuild { + ndkBuild { + arguments "NDK_APPLICATION_MK:=src/main/jni/Application.mk" + abiFilters "armeabi" + } + } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } + debug { + debuggable true + jniDebuggable true + ndk { + debuggable true + } + } } - sourceSets.main { - jniLibs.srcDirs 'src/main/libs' - jni.srcDirs = [] // This prevents the auto generation of Android.mk + externalNativeBuild { + ndkBuild { + path 'src/main/jni/Android.mk' + } } } diff --git a/android/ijkplayer/ijkplayer-armv5/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-armv5/src/main/jni/Android.mk deleted file mode 120000 index fb30867..0000000 --- a/android/ijkplayer/ijkplayer-armv5/src/main/jni/Android.mk +++ /dev/null @@ -1 +0,0 @@ -../../../../ijkplayer-armv7a/src/main/jni/Android.mk \ No newline at end of file diff --git a/android/ijkplayer/ijkplayer-armv5/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-armv5/src/main/jni/Android.mk new file mode 100644 index 0000000..47d400e --- /dev/null +++ b/android/ijkplayer/ijkplayer-armv5/src/main/jni/Android.mk @@ -0,0 +1,28 @@ +# copyright (c) 2013 Zhang Rui +# +# This file is part of ijkPlayer. +# +# ijkPlayer 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. +# +# ijkPlayer 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 ijkPlayer; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +LOCAL_PATH := $(call my-dir) + +MY_APP_JNI_ROOT := $(realpath $(LOCAL_PATH)) +MY_APP_PRJ_ROOT := $(realpath $(MY_APP_JNI_ROOT)/..) +MY_APP_ANDROID_ROOT := $(realpath $(MY_APP_PRJ_ROOT)/../../../..) + +MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-armv5/output) +MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include) + +include $(call all-subdir-makefiles) diff --git a/android/ijkplayer/ijkplayer-example/build.gradle b/android/ijkplayer/ijkplayer-example/build.gradle index 9afe650..3c5c819 100644 --- a/android/ijkplayer/ijkplayer-example/build.gradle +++ b/android/ijkplayer/ijkplayer-example/build.gradle @@ -45,14 +45,14 @@ dependencies { compile project(':ijkplayer-exo') all32Compile project(':ijkplayer-armv5') - all32Compile project(':ijkplayer-armv7a') - all32Compile project(':ijkplayer-x86') - +// all32Compile project(':ijkplayer-armv7a') +// all32Compile project(':ijkplayer-x86') +// all64Compile project(':ijkplayer-armv5') - all64Compile project(':ijkplayer-armv7a') - all64Compile project(':ijkplayer-arm64') - all64Compile project(':ijkplayer-x86') - all64Compile project(':ijkplayer-x86_64') +// all64Compile project(':ijkplayer-armv7a') +// all64Compile project(':ijkplayer-arm64') +// all64Compile project(':ijkplayer-x86') +// all64Compile project(':ijkplayer-x86_64') // armv5Compile project(':player-armv5') // armv7aCompile project(':player-armv7a') diff --git a/android/ijkplayer/settings.gradle b/android/ijkplayer/settings.gradle index 758234a..b0873e0 100644 --- a/android/ijkplayer/settings.gradle +++ b/android/ijkplayer/settings.gradle @@ -1,7 +1,7 @@ -include ':ijkplayer-armv5', ':ijkplayer-x86_64' -include ':ijkplayer-armv7a' -include ':ijkplayer-arm64' -include ':ijkplayer-x86' +include ':ijkplayer-armv5'//, ':ijkplayer-x86_64' +//include ':ijkplayer-armv7a' +//include ':ijkplayer-arm64' +//include ':ijkplayer-x86' include ':ijkplayer-java' include ':ijkplayer-exo' -- 2.7.4 (Apple Git-66) ================================================ FILE: android/patches/0003-armv7a-enable-debugging-with-LLDB.patch ================================================ From 69f62140cc4062f433cbd093301a1fc84ff61305 Mon Sep 17 00:00:00 2001 From: ctiao Date: Mon, 29 Aug 2016 16:15:00 +0800 Subject: [PATCH] armv7a: enable debugging with LLDB --- android/ijkplayer/ijkplayer-armv7a/build.gradle | 23 +++++++++++++++++++--- .../ijkplayer-armv7a/src/main/jni/Android.mk | 18 ----------------- android/ijkplayer/ijkplayer-example/build.gradle | 14 ++++++------- android/ijkplayer/settings.gradle | 6 +++--- 4 files changed, 30 insertions(+), 31 deletions(-) diff --git a/android/ijkplayer/ijkplayer-armv7a/build.gradle b/android/ijkplayer/ijkplayer-armv7a/build.gradle index b3b7b3a..9cc99b5 100644 --- a/android/ijkplayer/ijkplayer-armv7a/build.gradle +++ b/android/ijkplayer/ijkplayer-armv7a/build.gradle @@ -10,16 +10,33 @@ android { defaultConfig { minSdkVersion 9 targetSdkVersion rootProject.ext.targetSdkVersion + externalNativeBuild { + ndkBuild { + arguments "NDK_APPLICATION_MK:=src/main/jni/Application.mk"//,"APP_ABI=armeabi-v7a","NDK_ALL_ABIS=armeabi-v7a"//,"NDK_LIBS_OUT:=src/main/libs" +// cFlags "-DTEST_C_FLAG1", "-DTEST_C_FLAG2" // output dir -> 'src/main/libs' +// cppFlags "-DTEST_CPP_FLAG2", "-DTEST_CPP_FLAG2" + abiFilters "armeabi-v7a" + } + } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } + debug { + debuggable true + jniDebuggable true + ndk { + debuggable true + } + } } - sourceSets.main { - jniLibs.srcDirs 'src/main/libs' - jni.srcDirs = [] // This prevents the auto generation of Android.mk + + externalNativeBuild { + ndkBuild { + path 'src/main/jni/Android.mk' + } } } diff --git a/android/ijkplayer/ijkplayer-armv7a/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-armv7a/src/main/jni/Android.mk index ba2db29..a126226 100644 --- a/android/ijkplayer/ijkplayer-armv7a/src/main/jni/Android.mk +++ b/android/ijkplayer/ijkplayer-armv7a/src/main/jni/Android.mk @@ -22,25 +22,7 @@ MY_APP_JNI_ROOT := $(realpath $(LOCAL_PATH)) MY_APP_PRJ_ROOT := $(realpath $(MY_APP_JNI_ROOT)/..) MY_APP_ANDROID_ROOT := $(realpath $(MY_APP_PRJ_ROOT)/../../../..) -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-armv7a/output) MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include) -endif -ifeq ($(TARGET_ARCH_ABI),armeabi) -MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-armv5/output) -MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include) -endif -ifeq ($(TARGET_ARCH_ABI),arm64-v8a) -MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-arm64/output) -MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include) -endif -ifeq ($(TARGET_ARCH_ABI),x86) -MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-x86/output) -MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include) -endif -ifeq ($(TARGET_ARCH_ABI),x86_64) -MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-x86_64/output) -MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include) -endif include $(call all-subdir-makefiles) diff --git a/android/ijkplayer/ijkplayer-example/build.gradle b/android/ijkplayer/ijkplayer-example/build.gradle index 9afe650..3d6df0f 100644 --- a/android/ijkplayer/ijkplayer-example/build.gradle +++ b/android/ijkplayer/ijkplayer-example/build.gradle @@ -44,15 +44,15 @@ dependencies { compile project(':ijkplayer-java') compile project(':ijkplayer-exo') - all32Compile project(':ijkplayer-armv5') +// all32Compile project(':ijkplayer-armv5') all32Compile project(':ijkplayer-armv7a') - all32Compile project(':ijkplayer-x86') - - all64Compile project(':ijkplayer-armv5') +// all32Compile project(':ijkplayer-x86') +// +// all64Compile project(':ijkplayer-armv5') all64Compile project(':ijkplayer-armv7a') - all64Compile project(':ijkplayer-arm64') - all64Compile project(':ijkplayer-x86') - all64Compile project(':ijkplayer-x86_64') +// all64Compile project(':ijkplayer-arm64') +// all64Compile project(':ijkplayer-x86') +// all64Compile project(':ijkplayer-x86_64') // armv5Compile project(':player-armv5') // armv7aCompile project(':player-armv7a') diff --git a/android/ijkplayer/settings.gradle b/android/ijkplayer/settings.gradle index 758234a..b51e5d3 100644 --- a/android/ijkplayer/settings.gradle +++ b/android/ijkplayer/settings.gradle @@ -1,7 +1,7 @@ -include ':ijkplayer-armv5', ':ijkplayer-x86_64' +//include ':ijkplayer-armv5', ':ijkplayer-x86_64' include ':ijkplayer-armv7a' -include ':ijkplayer-arm64' -include ':ijkplayer-x86' +//include ':ijkplayer-arm64' +//include ':ijkplayer-x86' include ':ijkplayer-java' include ':ijkplayer-exo' -- 2.7.4 (Apple Git-66) ================================================ FILE: android/patches/0003-x86-enable-debugging-with-LLDB.patch ================================================ From 9d779640e6e71181e9432d21eec11e79d53451df Mon Sep 17 00:00:00 2001 From: ctiao Date: Mon, 29 Aug 2016 17:36:42 +0800 Subject: [PATCH] x86: enable debugging with LLDB --- android/ijkplayer/ijkplayer-example/build.gradle | 14 +++++------ android/ijkplayer/ijkplayer-x86/build.gradle | 20 ++++++++++++--- .../ijkplayer-x86/src/main/jni/Android.mk | 29 +++++++++++++++++++++- android/ijkplayer/settings.gradle | 6 ++--- 4 files changed, 55 insertions(+), 14 deletions(-) mode change 120000 => 100644 android/ijkplayer/ijkplayer-x86/src/main/jni/Android.mk diff --git a/android/ijkplayer/ijkplayer-example/build.gradle b/android/ijkplayer/ijkplayer-example/build.gradle index 9afe650..4f428b3 100644 --- a/android/ijkplayer/ijkplayer-example/build.gradle +++ b/android/ijkplayer/ijkplayer-example/build.gradle @@ -44,15 +44,15 @@ dependencies { compile project(':ijkplayer-java') compile project(':ijkplayer-exo') - all32Compile project(':ijkplayer-armv5') - all32Compile project(':ijkplayer-armv7a') +// all32Compile project(':ijkplayer-armv5') +// all32Compile project(':ijkplayer-armv7a') all32Compile project(':ijkplayer-x86') - - all64Compile project(':ijkplayer-armv5') - all64Compile project(':ijkplayer-armv7a') - all64Compile project(':ijkplayer-arm64') +// +// all64Compile project(':ijkplayer-armv5') +// all64Compile project(':ijkplayer-armv7a') +// all64Compile project(':ijkplayer-arm64') all64Compile project(':ijkplayer-x86') - all64Compile project(':ijkplayer-x86_64') +// all64Compile project(':ijkplayer-x86_64') // armv5Compile project(':player-armv5') // armv7aCompile project(':player-armv7a') diff --git a/android/ijkplayer/ijkplayer-x86/build.gradle b/android/ijkplayer/ijkplayer-x86/build.gradle index b3b7b3a..75fa48a 100644 --- a/android/ijkplayer/ijkplayer-x86/build.gradle +++ b/android/ijkplayer/ijkplayer-x86/build.gradle @@ -10,16 +10,30 @@ android { defaultConfig { minSdkVersion 9 targetSdkVersion rootProject.ext.targetSdkVersion + externalNativeBuild { + ndkBuild { + arguments "NDK_APPLICATION_MK:=src/main/jni/Application.mk" + abiFilters "x86" + } + } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } + debug { + debuggable true + jniDebuggable true + ndk { + debuggable true + } + } } - sourceSets.main { - jniLibs.srcDirs 'src/main/libs' - jni.srcDirs = [] // This prevents the auto generation of Android.mk + externalNativeBuild { + ndkBuild { + path 'src/main/jni/Android.mk' + } } } diff --git a/android/ijkplayer/ijkplayer-x86/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-x86/src/main/jni/Android.mk deleted file mode 120000 index fb30867..0000000 --- a/android/ijkplayer/ijkplayer-x86/src/main/jni/Android.mk +++ /dev/null @@ -1 +0,0 @@ -../../../../ijkplayer-armv7a/src/main/jni/Android.mk \ No newline at end of file diff --git a/android/ijkplayer/ijkplayer-x86/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-x86/src/main/jni/Android.mk new file mode 100644 index 0000000..a126226 --- /dev/null +++ b/android/ijkplayer/ijkplayer-x86/src/main/jni/Android.mk @@ -0,0 +1,28 @@ +# copyright (c) 2013 Zhang Rui +# +# This file is part of ijkPlayer. +# +# ijkPlayer 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. +# +# ijkPlayer 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 ijkPlayer; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +LOCAL_PATH := $(call my-dir) + +MY_APP_JNI_ROOT := $(realpath $(LOCAL_PATH)) +MY_APP_PRJ_ROOT := $(realpath $(MY_APP_JNI_ROOT)/..) +MY_APP_ANDROID_ROOT := $(realpath $(MY_APP_PRJ_ROOT)/../../../..) + +MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-armv7a/output) +MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include) + +include $(call all-subdir-makefiles) diff --git a/android/ijkplayer/settings.gradle b/android/ijkplayer/settings.gradle index 758234a..a3c9164 100644 --- a/android/ijkplayer/settings.gradle +++ b/android/ijkplayer/settings.gradle @@ -1,6 +1,6 @@ -include ':ijkplayer-armv5', ':ijkplayer-x86_64' -include ':ijkplayer-armv7a' -include ':ijkplayer-arm64' +//include ':ijkplayer-armv5', ':ijkplayer-x86_64' +//include ':ijkplayer-armv7a' +//include ':ijkplayer-arm64' include ':ijkplayer-x86' include ':ijkplayer-java' -- 2.7.4 (Apple Git-66) ================================================ FILE: android/patches/0003-x86_64-enable-debugging-with-LLDB.patch ================================================ From 7797e3b03276d391746e47e0e81eedfe3ddfec66 Mon Sep 17 00:00:00 2001 From: ctiao Date: Mon, 29 Aug 2016 17:01:10 +0800 Subject: [PATCH] x86_64: enable debugging with LLDB --- android/ijkplayer/ijkplayer-example/build.gradle | 16 ++++++------ android/ijkplayer/ijkplayer-x86_64/build.gradle | 20 ++++++++++++--- .../ijkplayer-x86_64/src/main/jni/Android.mk | 29 +++++++++++++++++++++- android/ijkplayer/settings.gradle | 8 +++--- 4 files changed, 57 insertions(+), 16 deletions(-) mode change 120000 => 100644 android/ijkplayer/ijkplayer-x86_64/src/main/jni/Android.mk diff --git a/android/ijkplayer/ijkplayer-example/build.gradle b/android/ijkplayer/ijkplayer-example/build.gradle index 9afe650..9f169ad 100644 --- a/android/ijkplayer/ijkplayer-example/build.gradle +++ b/android/ijkplayer/ijkplayer-example/build.gradle @@ -44,14 +44,14 @@ dependencies { compile project(':ijkplayer-java') compile project(':ijkplayer-exo') - all32Compile project(':ijkplayer-armv5') - all32Compile project(':ijkplayer-armv7a') - all32Compile project(':ijkplayer-x86') - - all64Compile project(':ijkplayer-armv5') - all64Compile project(':ijkplayer-armv7a') - all64Compile project(':ijkplayer-arm64') - all64Compile project(':ijkplayer-x86') +// all32Compile project(':ijkplayer-armv5') +// all32Compile project(':ijkplayer-armv7a') +// all32Compile project(':ijkplayer-x86') +// +// all64Compile project(':ijkplayer-armv5') +// all64Compile project(':ijkplayer-armv7a') +// all64Compile project(':ijkplayer-arm64') +// all64Compile project(':ijkplayer-x86') all64Compile project(':ijkplayer-x86_64') // armv5Compile project(':player-armv5') diff --git a/android/ijkplayer/ijkplayer-x86_64/build.gradle b/android/ijkplayer/ijkplayer-x86_64/build.gradle index a8cbe0c..b4a6673 100644 --- a/android/ijkplayer/ijkplayer-x86_64/build.gradle +++ b/android/ijkplayer/ijkplayer-x86_64/build.gradle @@ -10,16 +10,30 @@ android { defaultConfig { minSdkVersion 21 targetSdkVersion rootProject.ext.targetSdkVersion + externalNativeBuild { + ndkBuild { + arguments "NDK_APPLICATION_MK:=src/main/jni/Application.mk" + abiFilters "x86_64" + } + } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } + debug { + debuggable true + jniDebuggable true + ndk { + debuggable true + } + } } - sourceSets.main { - jniLibs.srcDirs 'src/main/libs' - jni.srcDirs = [] // This prevents the auto generation of Android.mk + externalNativeBuild { + ndkBuild { + path 'src/main/jni/Android.mk' + } } } diff --git a/android/ijkplayer/ijkplayer-x86_64/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-x86_64/src/main/jni/Android.mk deleted file mode 120000 index fb30867..0000000 --- a/android/ijkplayer/ijkplayer-x86_64/src/main/jni/Android.mk +++ /dev/null @@ -1 +0,0 @@ -../../../../ijkplayer-armv7a/src/main/jni/Android.mk \ No newline at end of file diff --git a/android/ijkplayer/ijkplayer-x86_64/src/main/jni/Android.mk b/android/ijkplayer/ijkplayer-x86_64/src/main/jni/Android.mk new file mode 100644 index 0000000..273aa7b --- /dev/null +++ b/android/ijkplayer/ijkplayer-x86_64/src/main/jni/Android.mk @@ -0,0 +1,28 @@ +# copyright (c) 2013 Zhang Rui +# +# This file is part of ijkPlayer. +# +# ijkPlayer 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. +# +# ijkPlayer 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 ijkPlayer; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +LOCAL_PATH := $(call my-dir) + +MY_APP_JNI_ROOT := $(realpath $(LOCAL_PATH)) +MY_APP_PRJ_ROOT := $(realpath $(MY_APP_JNI_ROOT)/..) +MY_APP_ANDROID_ROOT := $(realpath $(MY_APP_PRJ_ROOT)/../../../..) + +MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-x86_64/output) +MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include) + +include $(call all-subdir-makefiles) diff --git a/android/ijkplayer/settings.gradle b/android/ijkplayer/settings.gradle index 758234a..f1f857f 100644 --- a/android/ijkplayer/settings.gradle +++ b/android/ijkplayer/settings.gradle @@ -1,7 +1,7 @@ -include ':ijkplayer-armv5', ':ijkplayer-x86_64' -include ':ijkplayer-armv7a' -include ':ijkplayer-arm64' -include ':ijkplayer-x86' +include ':ijkplayer-x86_64' +//include ':ijkplayer-armv7a' +//include ':ijkplayer-arm64' +//include ':ijkplayer-x86' include ':ijkplayer-java' include ':ijkplayer-exo' -- 2.7.4 (Apple Git-66) ================================================ FILE: android/patches/0004-armv7a-link-prebuilt-staic-libraries-of-ffmepg.patch ================================================ From fb17b98cfeb265e09220568df17cc493192e6ebe Mon Sep 17 00:00:00 2001 From: ctiao Date: Fri, 2 Sep 2016 16:39:02 +0800 Subject: [PATCH] armv7a: link prebuilt staic libraries of ffmepg --- .../src/main/jni/ffmpeg/Android.mk | 42 ++++++++++++++++++++-- .../danmaku/ijk/media/player/IjkMediaPlayer.java | 1 - ijkmedia/ijkplayer/Android.mk | 6 ++-- ijkmedia/ijksdl/Android.mk | 4 +-- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/android/ijkplayer/ijkplayer-armv7a/src/main/jni/ffmpeg/Android.mk b/android/ijkplayer/ijkplayer-armv7a/src/main/jni/ffmpeg/Android.mk index ec33908..3c525bd 100644 --- a/android/ijkplayer/ijkplayer-armv7a/src/main/jni/ffmpeg/Android.mk +++ b/android/ijkplayer/ijkplayer-armv7a/src/main/jni/ffmpeg/Android.mk @@ -1,6 +1,42 @@ LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := avcodec +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavcodec.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH) +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := avformat +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavformat.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH) +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := swscale +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libswscale.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_OUTPUT_PATH)/include +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := avutil +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavutil.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH) +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := avfilter +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavfilter.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH) +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) -LOCAL_MODULE := ijkffmpeg -LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/libijkffmpeg.so -include $(PREBUILT_SHARED_LIBRARY) \ No newline at end of file +LOCAL_MODULE := swresample +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libswresample.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH) +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) 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 985f848..7ad3fe4 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 @@ -165,7 +165,6 @@ public final class IjkMediaPlayer extends AbstractMediaPlayer { if (libLoader == null) libLoader = sLocalLibLoader; - libLoader.loadLibrary("ijkffmpeg"); libLoader.loadLibrary("ijksdl"); libLoader.loadLibrary("ijkplayer"); mIsLibLoaded = true; diff --git a/ijkmedia/ijkplayer/Android.mk b/ijkmedia/ijkplayer/Android.mk index 92372ab..6c9270d 100644 --- a/ijkmedia/ijkplayer/Android.mk +++ b/ijkmedia/ijkplayer/Android.mk @@ -26,7 +26,7 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) LOCAL_CFLAGS += -mfloat-abi=soft endif LOCAL_CFLAGS += -std=c99 -LOCAL_LDLIBS += -llog -landroid +LOCAL_LDLIBS += -llog -landroid -lm -lz LOCAL_C_INCLUDES += $(LOCAL_PATH) LOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/..) @@ -59,8 +59,8 @@ LOCAL_SRC_FILES += ijkavformat/ijkurlhook.c LOCAL_SRC_FILES += ijkavformat/ijklongurl.c LOCAL_SRC_FILES += ijkavformat/ijksegment.c -LOCAL_SHARED_LIBRARIES := ijkffmpeg ijksdl -LOCAL_STATIC_LIBRARIES := android-ndk-profiler +LOCAL_SHARED_LIBRARIES := ijksdl +LOCAL_STATIC_LIBRARIES := avformat avcodec swscale swresample avfilter avutil android-ndk-profiler LOCAL_MODULE := ijkplayer include $(BUILD_SHARED_LIBRARY) diff --git a/ijkmedia/ijksdl/Android.mk b/ijkmedia/ijksdl/Android.mk index 08ebbab..4f6d804 100644 --- a/ijkmedia/ijksdl/Android.mk +++ b/ijkmedia/ijksdl/Android.mk @@ -70,8 +70,8 @@ LOCAL_SRC_FILES += android/ijksdl_vout_android_nativewindow.c LOCAL_SRC_FILES += android/ijksdl_vout_android_surface.c LOCAL_SRC_FILES += android/ijksdl_vout_overlay_android_mediacodec.c -LOCAL_SHARED_LIBRARIES := ijkffmpeg ijkj4a -LOCAL_STATIC_LIBRARIES := cpufeatures yuv_static +LOCAL_STATIC_LIBRARIES := avformat avcodec swscale swresample avfilter avutil cpufeatures yuv_static +LOCAL_SHARED_LIBRARIES := ijkj4a LOCAL_MODULE := ijksdl include $(BUILD_SHARED_LIBRARY) -- 2.7.4 (Apple Git-66) ================================================ FILE: android/patches/0004-x86-link-prebuilt-staic-libraries-of-ffmepg.patch ================================================ From e8d39a74162855acb1332bd877f22fe1d881aa61 Mon Sep 17 00:00:00 2001 From: ctiao Date: Fri, 2 Sep 2016 17:01:57 +0800 Subject: [PATCH] x86: link prebuilt staic libraries of ffmepg --- .../danmaku/ijk/media/player/IjkMediaPlayer.java | 1 - .../ijkplayer-x86/src/main/jni/ffmpeg/Android.mk | 43 ++++++++++++++++++++-- ijkmedia/ijkplayer/Android.mk | 6 +-- ijkmedia/ijksdl/Android.mk | 4 +- 4 files changed, 45 insertions(+), 9 deletions(-) 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 985f848..7ad3fe4 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 @@ -165,7 +165,6 @@ public final class IjkMediaPlayer extends AbstractMediaPlayer { if (libLoader == null) libLoader = sLocalLibLoader; - libLoader.loadLibrary("ijkffmpeg"); libLoader.loadLibrary("ijksdl"); libLoader.loadLibrary("ijkplayer"); mIsLibLoaded = true; diff --git a/android/ijkplayer/ijkplayer-x86/src/main/jni/ffmpeg/Android.mk b/android/ijkplayer/ijkplayer-x86/src/main/jni/ffmpeg/Android.mk index ec33908..44c50b1 100644 --- a/android/ijkplayer/ijkplayer-x86/src/main/jni/ffmpeg/Android.mk +++ b/android/ijkplayer/ijkplayer-x86/src/main/jni/ffmpeg/Android.mk @@ -1,6 +1,43 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_MODULE := ijkffmpeg -LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/libijkffmpeg.so -include $(PREBUILT_SHARED_LIBRARY) \ No newline at end of file +LOCAL_MODULE := avcodec +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavcodec.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH) +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := avformat +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavformat.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH) +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := swscale +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libswscale.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_OUTPUT_PATH)/include +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := avutil +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavutil.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH) +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := avfilter +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavfilter.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH) +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := swresample +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libswresample.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH) +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) diff --git a/ijkmedia/ijkplayer/Android.mk b/ijkmedia/ijkplayer/Android.mk index 92372ab..6c9270d 100644 --- a/ijkmedia/ijkplayer/Android.mk +++ b/ijkmedia/ijkplayer/Android.mk @@ -26,7 +26,7 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) LOCAL_CFLAGS += -mfloat-abi=soft endif LOCAL_CFLAGS += -std=c99 -LOCAL_LDLIBS += -llog -landroid +LOCAL_LDLIBS += -llog -landroid -lm -lz LOCAL_C_INCLUDES += $(LOCAL_PATH) LOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/..) @@ -59,8 +59,8 @@ LOCAL_SRC_FILES += ijkavformat/ijkurlhook.c LOCAL_SRC_FILES += ijkavformat/ijklongurl.c LOCAL_SRC_FILES += ijkavformat/ijksegment.c -LOCAL_SHARED_LIBRARIES := ijkffmpeg ijksdl -LOCAL_STATIC_LIBRARIES := android-ndk-profiler +LOCAL_SHARED_LIBRARIES := ijksdl +LOCAL_STATIC_LIBRARIES := avformat avcodec swscale swresample avfilter avutil android-ndk-profiler LOCAL_MODULE := ijkplayer include $(BUILD_SHARED_LIBRARY) diff --git a/ijkmedia/ijksdl/Android.mk b/ijkmedia/ijksdl/Android.mk index 08ebbab..4f6d804 100644 --- a/ijkmedia/ijksdl/Android.mk +++ b/ijkmedia/ijksdl/Android.mk @@ -70,8 +70,8 @@ LOCAL_SRC_FILES += android/ijksdl_vout_android_nativewindow.c LOCAL_SRC_FILES += android/ijksdl_vout_android_surface.c LOCAL_SRC_FILES += android/ijksdl_vout_overlay_android_mediacodec.c -LOCAL_SHARED_LIBRARIES := ijkffmpeg ijkj4a -LOCAL_STATIC_LIBRARIES := cpufeatures yuv_static +LOCAL_STATIC_LIBRARIES := avformat avcodec swscale swresample avfilter avutil cpufeatures yuv_static +LOCAL_SHARED_LIBRARIES := ijkj4a LOCAL_MODULE := ijksdl include $(BUILD_SHARED_LIBRARY) -- 2.7.4 (Apple Git-66) ================================================ FILE: android/patches/0004-x86_64-link-prebuilt-staic-libraries-of-ffmepg.patch ================================================ From f123440d855e912f4ce94f48d06a84caffb9bfe2 Mon Sep 17 00:00:00 2001 From: ctiao Date: Fri, 2 Sep 2016 17:06:00 +0800 Subject: [PATCH] x86_64: link prebuilt staic libraries of ffmepg --- .../danmaku/ijk/media/player/IjkMediaPlayer.java | 1 - .../src/main/jni/ffmpeg/Android.mk | 42 ++++++++++++++++++++-- ijkmedia/ijkplayer/Android.mk | 6 ++-- ijkmedia/ijksdl/Android.mk | 4 +-- 4 files changed, 44 insertions(+), 9 deletions(-) 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 985f848..7ad3fe4 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 @@ -165,7 +165,6 @@ public final class IjkMediaPlayer extends AbstractMediaPlayer { if (libLoader == null) libLoader = sLocalLibLoader; - libLoader.loadLibrary("ijkffmpeg"); libLoader.loadLibrary("ijksdl"); libLoader.loadLibrary("ijkplayer"); mIsLibLoaded = true; diff --git a/android/ijkplayer/ijkplayer-x86_64/src/main/jni/ffmpeg/Android.mk b/android/ijkplayer/ijkplayer-x86_64/src/main/jni/ffmpeg/Android.mk index ec33908..3c525bd 100644 --- a/android/ijkplayer/ijkplayer-x86_64/src/main/jni/ffmpeg/Android.mk +++ b/android/ijkplayer/ijkplayer-x86_64/src/main/jni/ffmpeg/Android.mk @@ -1,6 +1,42 @@ LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := avcodec +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavcodec.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH) +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := avformat +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavformat.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH) +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := swscale +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libswscale.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_OUTPUT_PATH)/include +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := avutil +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavutil.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH) +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := avfilter +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libavfilter.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH) +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) -LOCAL_MODULE := ijkffmpeg -LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/libijkffmpeg.so -include $(PREBUILT_SHARED_LIBRARY) \ No newline at end of file +LOCAL_MODULE := swresample +LOCAL_SRC_FILES := $(MY_APP_FFMPEG_OUTPUT_PATH)/lib/libswresample.a +LOCAL_EXPORT_C_INCLUDES := $(MY_APP_FFMPEG_INCLUDE_PATH) +LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) +include $(PREBUILT_STATIC_LIBRARY) diff --git a/ijkmedia/ijkplayer/Android.mk b/ijkmedia/ijkplayer/Android.mk index 92372ab..6c9270d 100644 --- a/ijkmedia/ijkplayer/Android.mk +++ b/ijkmedia/ijkplayer/Android.mk @@ -26,7 +26,7 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) LOCAL_CFLAGS += -mfloat-abi=soft endif LOCAL_CFLAGS += -std=c99 -LOCAL_LDLIBS += -llog -landroid +LOCAL_LDLIBS += -llog -landroid -lm -lz LOCAL_C_INCLUDES += $(LOCAL_PATH) LOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/..) @@ -59,8 +59,8 @@ LOCAL_SRC_FILES += ijkavformat/ijkurlhook.c LOCAL_SRC_FILES += ijkavformat/ijklongurl.c LOCAL_SRC_FILES += ijkavformat/ijksegment.c -LOCAL_SHARED_LIBRARIES := ijkffmpeg ijksdl -LOCAL_STATIC_LIBRARIES := android-ndk-profiler +LOCAL_SHARED_LIBRARIES := ijksdl +LOCAL_STATIC_LIBRARIES := avformat avcodec swscale swresample avfilter avutil android-ndk-profiler LOCAL_MODULE := ijkplayer include $(BUILD_SHARED_LIBRARY) diff --git a/ijkmedia/ijksdl/Android.mk b/ijkmedia/ijksdl/Android.mk index 08ebbab..4f6d804 100644 --- a/ijkmedia/ijksdl/Android.mk +++ b/ijkmedia/ijksdl/Android.mk @@ -70,8 +70,8 @@ LOCAL_SRC_FILES += android/ijksdl_vout_android_nativewindow.c LOCAL_SRC_FILES += android/ijksdl_vout_android_surface.c LOCAL_SRC_FILES += android/ijksdl_vout_overlay_android_mediacodec.c -LOCAL_SHARED_LIBRARIES := ijkffmpeg ijkj4a -LOCAL_STATIC_LIBRARIES := cpufeatures yuv_static +LOCAL_STATIC_LIBRARIES := avformat avcodec swscale swresample avfilter avutil cpufeatures yuv_static +LOCAL_SHARED_LIBRARIES := ijkj4a LOCAL_MODULE := ijksdl include $(BUILD_SHARED_LIBRARY) -- 2.7.4 (Apple Git-66) ================================================ FILE: compile-android-j4a.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2016 Bilibili # Copyright (C) 2016 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # set -e cd extra/jni4android-fork ./configure --incdir=../../ijkmedia/ijkj4a --bindir=../bin make install cd - cd ijkmedia/ijkj4a make cd - ================================================ FILE: config/module-default.sh ================================================ #! /usr/bin/env bash #-------------------- # Standard options: export COMMON_FF_CFG_FLAGS= # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --prefix=PREFIX" # Licensing options: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-gpl" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-version3" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-nonfree" # Configuration options: # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-static" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-shared" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-small" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-runtime-cpudetect" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-gray" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-swscale-alpha" # Program options: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-programs" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffmpeg" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffplay" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffprobe" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffserver" # Documentation options: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-doc" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-htmlpages" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-manpages" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-podpages" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-txtpages" # Component options: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-avdevice" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avcodec" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avformat" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avutil" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-swresample" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-swscale" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-postproc" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avfilter" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-avresample" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-pthreads" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-w32threads" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-os2threads" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-network" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-dct" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-dwt" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-lsp" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-lzo" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mdct" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-rdft" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-fft" # Hardware accelerators: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-dxva2" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vaapi" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vda" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vdpau" # Individual component options: # 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-muxers" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-demuxers" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-parsers" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsfs" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocols" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-devices" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-filters" # External library support: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-iconv" # ... export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=async" # Advanced options (experts only): # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --cross-prefix=${FF_CROSS_PREFIX}-" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-cross-compile" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --sysroot=PATH" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --sysinclude=PATH" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --target-os=TAGET_OS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --target-exec=CMD" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --target-path=DIR" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --toolchain=NAME" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --nm=NM" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --ar=AR" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --as=AS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --yasmexe=EXE" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --cc=CC" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --cxx=CXX" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --dep-cc=DEPCC" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --ld=LD" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-cc=HOSTCC" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-cflags=HCFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-cppflags=HCPPFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-ld=HOSTLD" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-ldflags=HLDFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-libs=HLIBS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-os=OS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-cflags=ECFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-cxxflags=ECFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-ldflags=ELDFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-libs=ELIBS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-version=STRING" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --optflags=OPTFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --build-suffix=SUFFIX" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --malloc-prefix=PREFIX" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --progs-suffix=SUFFIX" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --arch=ARCH" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --cpu=CPU" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-pic" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-sram" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-thumb" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-symver" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-hardcoded-tables" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-safe-bitstream-reader" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-memalign-hack" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-lto" # Optimization options (experts only): # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-asm" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-altivec" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-amd3dnow" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-amd3dnowext" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mmx" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mmxext" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse2" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse3" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ssse3" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse4" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse42" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-avx" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-fma4" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-armv5te" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-armv6" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-armv6t2" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vfp" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-neon" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vis" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-inline-asm" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-yasm" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mips32r2" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mipsdspr1" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mipsdspr2" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mipsfpu" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-fast-unaligned" # Developer options (useful when working on FFmpeg itself): # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-coverage" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-debug" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-debug=LEVEL" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-optimizations" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-extra-warnings" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-stripping" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --assert-level=level" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-memory-poisoning" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --valgrind=VALGRIND" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-ftrapv" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --samples=PATH" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-xmm-clobber-test" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-random" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-random" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-random=LIST" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-random=LIST" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --random-seed=VALUE" ================================================ FILE: config/module-lite-hevc.sh ================================================ #! /usr/bin/env bash #-------------------- # Standard options: export COMMON_FF_CFG_FLAGS= # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --prefix=PREFIX" # Licensing options: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-gpl" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-version3" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-nonfree" # Configuration options: # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-static" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-shared" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-small" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-runtime-cpudetect" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-gray" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-swscale-alpha" # Program options: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-programs" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffmpeg" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffplay" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffprobe" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffserver" # Documentation options: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-doc" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-htmlpages" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-manpages" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-podpages" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-txtpages" # Component options: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-avdevice" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avcodec" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avformat" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avutil" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-swresample" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-swscale" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-postproc" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avfilter" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-avresample" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-pthreads" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-w32threads" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-os2threads" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-network" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-dct" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-dwt" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-lsp" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-lzo" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mdct" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-rdft" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-fft" # Hardware accelerators: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-dxva2" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vaapi" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vda" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vdpau" # Individual component options: # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-everything" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-encoders" # ./configure --list-decoders export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-decoders" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=aac" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=aac_latm" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=flv" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=h263" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=h263i" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=h263p" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=h264" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=mp3*" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=vp6" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=vp6a" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=vp6f" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=hevc" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-hwaccels" # ./configure --list-muxers export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-muxers" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-muxer=mpegts" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-muxer=mp4" # ./configure --list-demuxers export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-demuxers" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=aac" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=concat" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=data" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=flv" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=hls" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=latm" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=live_flv" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=loas" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=m4v" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mov" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mp3" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegps" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegts" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegvideo" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=hevc" # ./configure --list-parsers export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-parsers" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=aac" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=aac_latm" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=ac3" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=h263" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=h264" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=hevc" # ./configure --list-bsf export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-bsfs" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mjpeg2jpeg" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mjpeg2jpeg" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mjpega_dump_header" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mov2textsub" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=text2movsub" # ./configure --list-protocols export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocols" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=async" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=bluray" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=ffrtmpcrypt" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=ffrtmphttp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=gopher" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=librtmp*" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=libssh" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=mmsh" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=mmst" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=rtmp*" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtmp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtmpt" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=rtp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=sctp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=srtp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=unix" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-devices" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-filters" # External library support: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-iconv" # ... # Advanced options (experts only): # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --cross-prefix=${FF_CROSS_PREFIX}-" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-cross-compile" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --sysroot=PATH" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --sysinclude=PATH" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --target-os=TAGET_OS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --target-exec=CMD" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --target-path=DIR" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --toolchain=NAME" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --nm=NM" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --ar=AR" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --as=AS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --yasmexe=EXE" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --cc=CC" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --cxx=CXX" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --dep-cc=DEPCC" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --ld=LD" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-cc=HOSTCC" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-cflags=HCFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-cppflags=HCPPFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-ld=HOSTLD" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-ldflags=HLDFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-libs=HLIBS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-os=OS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-cflags=ECFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-cxxflags=ECFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-ldflags=ELDFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-libs=ELIBS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-version=STRING" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --optflags=OPTFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --build-suffix=SUFFIX" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --malloc-prefix=PREFIX" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --progs-suffix=SUFFIX" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --arch=ARCH" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --cpu=CPU" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-pic" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-sram" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-thumb" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-symver" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-hardcoded-tables" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-safe-bitstream-reader" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-memalign-hack" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-lto" # Optimization options (experts only): # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-asm" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-altivec" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-amd3dnow" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-amd3dnowext" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mmx" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mmxext" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse2" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse3" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ssse3" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse4" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse42" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-avx" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-fma4" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-armv5te" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-armv6" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-armv6t2" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vfp" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-neon" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vis" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-inline-asm" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-yasm" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mips32r2" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mipsdspr1" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mipsdspr2" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mipsfpu" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-fast-unaligned" # Developer options (useful when working on FFmpeg itself): # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-coverage" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-debug" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-debug=LEVEL" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-optimizations" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-extra-warnings" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-stripping" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --assert-level=level" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-memory-poisoning" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --valgrind=VALGRIND" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-ftrapv" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --samples=PATH" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-xmm-clobber-test" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-random" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-random" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-random=LIST" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-random=LIST" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --random-seed=VALUE" ================================================ FILE: config/module-lite.sh ================================================ #! /usr/bin/env bash #-------------------- # Standard options: export COMMON_FF_CFG_FLAGS= # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --prefix=PREFIX" # Licensing options: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-gpl" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-version3" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-nonfree" # Configuration options: # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-static" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-shared" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-small" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-runtime-cpudetect" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-gray" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-swscale-alpha" # Program options: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-programs" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffmpeg" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffplay" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffprobe" #export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffserver" # Documentation options: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-doc" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-htmlpages" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-manpages" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-podpages" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-txtpages" # Component options: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-avdevice" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avcodec" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avformat" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avutil" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-swresample" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-swscale" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-postproc" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avfilter" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-avresample" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-pthreads" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-w32threads" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-os2threads" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-network" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-dct" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-dwt" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-lsp" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-lzo" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mdct" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-rdft" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-fft" # Hardware accelerators: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-d3d11va" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-dxva2" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vaapi" #export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vda" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vdpau" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-videotoolbox" # Individual component options: # 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 --enable-encoder=png" # ./configure --list-decoders export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-decoders" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=aac" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=aac_latm" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=flv" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=h264" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=mp3*" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=vp6f" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=flac" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=hevc" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=vp8" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=vp9" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-hwaccels" # ./configure --list-muxers export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-muxers" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-muxer=mp4" # ./configure --list-demuxers export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-demuxers" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=ijk*" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=aac" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=concat" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=data" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=flv" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=hls" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=live_flv" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mov" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mp3" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegps" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegts" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegvideo" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=flac" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=hevc" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=webm_dash_manifest" # ./configure --list-parsers export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-parsers" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=aac" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=aac_latm" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=h264" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=flac" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=hevc" # ./configure --list-bsf export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-bsfs" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=chomp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=dca_core" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=dump_extradata" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=hevc_mp4toannexb" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=imx_dump_header" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mjpeg2jpeg" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mjpega_dump_header" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mov2textsub" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mp3_header_decompress" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mpeg4_unpack_bframes" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=noise" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=remove_extradata" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=text2movsub" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=vp9_superframe" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=eac3_core" # ./configure --list-protocols export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocols" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=async" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=bluray" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=concat" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=crypto" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=ffrtmpcrypt" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=ffrtmphttp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=gopher" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=icecast" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=librtmp*" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=libssh" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=md5" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=mmsh" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=mmst" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=rtmp*" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtmp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtmpt" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=rtp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=sctp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=srtp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=subfile" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=unix" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-devices" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-filters" # External library support: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-iconv" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-audiotoolbox" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-videotoolbox" # ... # Advanced options (experts only): # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --cross-prefix=${FF_CROSS_PREFIX}-" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-cross-compile" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --sysroot=PATH" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --sysinclude=PATH" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --target-os=TAGET_OS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --target-exec=CMD" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --target-path=DIR" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --toolchain=NAME" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --nm=NM" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --ar=AR" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --as=AS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --yasmexe=EXE" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --cc=CC" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --cxx=CXX" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --dep-cc=DEPCC" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --ld=LD" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-cc=HOSTCC" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-cflags=HCFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-cppflags=HCPPFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-ld=HOSTLD" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-ldflags=HLDFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-libs=HLIBS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-os=OS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-cflags=ECFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-cxxflags=ECFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-ldflags=ELDFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-libs=ELIBS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-version=STRING" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --optflags=OPTFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --build-suffix=SUFFIX" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --malloc-prefix=PREFIX" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --progs-suffix=SUFFIX" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --arch=ARCH" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --cpu=CPU" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-pic" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-sram" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-thumb" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-symver" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-hardcoded-tables" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-safe-bitstream-reader" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-memalign-hack" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-lto" # Optimization options (experts only): # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-asm" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-altivec" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-amd3dnow" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-amd3dnowext" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mmx" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mmxext" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse2" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse3" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ssse3" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse4" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse42" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-avx" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-fma4" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-armv5te" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-armv6" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-armv6t2" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vfp" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-neon" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vis" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-inline-asm" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-yasm" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mips32r2" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mipsdspr1" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mipsdspr2" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mipsfpu" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-fast-unaligned" # Developer options (useful when working on FFmpeg itself): # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-coverage" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-debug" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-debug=LEVEL" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-optimizations" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-extra-warnings" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-stripping" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --assert-level=level" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-memory-poisoning" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --valgrind=VALGRIND" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-ftrapv" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --samples=PATH" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-xmm-clobber-test" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-random" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-random" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-random=LIST" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-random=LIST" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --random-seed=VALUE" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-linux-perf" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bzlib" ================================================ FILE: doc/preflight_checklist.md ================================================ ChangeLog ----------------------- * Update NEWS.md * Update README.md * Commit and push FFmpeg ----------------------- * Build and test iOS and Android demo locally * Modify ffmpeg version in init-ios.sh and init-android.sh * Modify ffmpeg version in `IJKFFMoviePlayerController` (by running `sh init-ios.sh`) * Commit and push OpenSSL ---------------------- * Check openssl latest stable version ijkplayer ----------------------- * Update version.sh * Create a tag (subtitle) * Commit and push (TAG ONLY) Travis-ci ----------------------- * Modify ijk version in `.travis.yaml` in iOS and Android ci repo. * Ensure compile task has been started on travis-ci. * Ensure Andoird release has been released in bintray. Take off ----------------------- * Push master to github ================================================ FILE: ijkmedia/Android.mk ================================================ # Copyright (c) 2013 Bilibili # copyright (c) 2013 Zhang Rui # # This file is part of ijkPlayer. # # ijkPlayer 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. # # ijkPlayer 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 ijkPlayer; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA LOCAL_PATH := $(call my-dir) include $(call all-subdir-makefiles) ================================================ FILE: ijkmedia/ijkj4a/.gitignore ================================================ bin ================================================ FILE: ijkmedia/ijkj4a/Android.mk ================================================ # copyright (c) 2016 Zhang Rui # # This file is part of ijkPlayer. # # ijkPlayer 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. # # ijkPlayer 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 ijkPlayer; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_CFLAGS += -std=c99 LOCAL_C_INCLUDES += $(LOCAL_PATH) LOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)) LOCAL_SRC_FILES += j4a/j4a_allclasses.c LOCAL_SRC_FILES += j4a/j4a_base.c LOCAL_SRC_FILES += j4a/class/android/media/AudioTrack.c LOCAL_SRC_FILES += j4a/class/android/media/MediaCodec.c LOCAL_SRC_FILES += j4a/class/android/media/MediaFormat.c LOCAL_SRC_FILES += j4a/class/android/media/PlaybackParams.c LOCAL_SRC_FILES += j4a/class/android/os/Build.c LOCAL_SRC_FILES += j4a/class/android/os/Bundle.c LOCAL_SRC_FILES += j4a/class/java/nio/Buffer.c LOCAL_SRC_FILES += j4a/class/java/nio/ByteBuffer.c LOCAL_SRC_FILES += j4a/class/java/util/ArrayList.c LOCAL_SRC_FILES += j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.c LOCAL_SRC_FILES += j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.c LOCAL_SRC_FILES += j4a/class/tv/danmaku/ijk/media/player/IjkMediaPlayer.c LOCAL_SRC_FILES += j4au/class/android/media/AudioTrack.util.c LOCAL_SRC_FILES += j4au/class/java/nio/ByteBuffer.util.c LOCAL_MODULE := ijkj4a include $(BUILD_STATIC_LIBRARY) $(call import-module,android/cpufeatures) ================================================ FILE: ijkmedia/ijkj4a/Makefile ================================================ J4A = ../../extra/bin/j4a ROOT_CLASS_INCLUDES = j4a/j4a_allclasses.include.h ROOT_CLASS_LOADERS = j4a/j4a_allclasses.loader.h all: ijkj4a # test java -> c JAVA_SRCS = \ java/java/nio/Buffer.java \ java/java/nio/ByteBuffer.java \ java/java/util/ArrayList.java \ java/android/media/AudioTrack.java \ java/android/media/MediaCodec.java \ java/android/media/MediaFormat.java \ java/android/media/PlaybackParams.java \ java/android/os/Build.java \ java/android/os/Bundle.java \ java/tv/danmaku/ijk/media/player/misc/IMediaDataSource.java \ java/tv/danmaku/ijk/media/player/misc/IAndroidIO.java \ java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java \ C_SRCS := $(JAVA_SRCS:java/%.java=j4a/class/%.c) H_SRCS := $(C_SRCS:%.c=%.h) $(C_SRCS): j4a/class/%.c: $(J4A) $(C_SRCS): j4a/class/%.c: java/%.java ifneq ("$<", "j4a/class/.c") @mkdir -p $(shell dirname $@) $(J4A) -c $< -o $@ @cat j4a/class/$*.include.j4a >> $(ROOT_CLASS_INCLUDES) @echo >> $(ROOT_CLASS_INCLUDES) @cat j4a/class/$*.loader.j4a >> $(ROOT_CLASS_LOADERS) @echo >> $(ROOT_CLASS_LOADERS) endif ijkj4a: prebuild $(C_SRCS) prebuild: @rm -f $(ROOT_CLASS_INCLUDES) @rm -f $(ROOT_CLASS_LOADERS) # ----- .PHONY: all clean ijkj4a prebuild clean: @rm -f $(C_SRCS) @rm -f $(H_SRCS) @rm -f $(ROOT_CLASS_INCLUDES) @rm -f $(ROOT_CLASS_LOADERS) ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/media/AudioTrack.c ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #include "AudioTrack.h" typedef struct J4AC_android_media_AudioTrack { jclass id; jmethodID constructor_AudioTrack; jmethodID method_getMinBufferSize; jmethodID method_getMaxVolume; jmethodID method_getMinVolume; jmethodID method_getNativeOutputSampleRate; jmethodID method_play; jmethodID method_pause; jmethodID method_stop; jmethodID method_flush; jmethodID method_release; jmethodID method_write; jmethodID method_setStereoVolume; jmethodID method_getAudioSessionId; jmethodID method_getPlaybackParams; jmethodID method_setPlaybackParams; jmethodID method_getStreamType; jmethodID method_getSampleRate; jmethodID method_getPlaybackRate; jmethodID method_setPlaybackRate; } J4AC_android_media_AudioTrack; static J4AC_android_media_AudioTrack class_J4AC_android_media_AudioTrack; jobject J4AC_android_media_AudioTrack__AudioTrack(JNIEnv *env, jint streamType, jint sampleRateInHz, jint channelConfig, jint audioFormat, jint bufferSizeInBytes, jint mode) { return (*env)->NewObject(env, class_J4AC_android_media_AudioTrack.id, class_J4AC_android_media_AudioTrack.constructor_AudioTrack, streamType, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes, mode); } jobject J4AC_android_media_AudioTrack__AudioTrack__catchAll(JNIEnv *env, jint streamType, jint sampleRateInHz, jint channelConfig, jint audioFormat, jint bufferSizeInBytes, jint mode) { jobject ret_object = J4AC_android_media_AudioTrack__AudioTrack(env, streamType, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes, mode); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { return NULL; } return ret_object; } jobject J4AC_android_media_AudioTrack__AudioTrack__asGlobalRef__catchAll(JNIEnv *env, jint streamType, jint sampleRateInHz, jint channelConfig, jint audioFormat, jint bufferSizeInBytes, jint mode) { jobject ret_object = NULL; jobject local_object = J4AC_android_media_AudioTrack__AudioTrack__catchAll(env, streamType, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes, mode); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } jint J4AC_android_media_AudioTrack__getMinBufferSize(JNIEnv *env, jint sampleRateInHz, jint channelConfig, jint audioFormat) { return (*env)->CallStaticIntMethod(env, class_J4AC_android_media_AudioTrack.id, class_J4AC_android_media_AudioTrack.method_getMinBufferSize, sampleRateInHz, channelConfig, audioFormat); } jint J4AC_android_media_AudioTrack__getMinBufferSize__catchAll(JNIEnv *env, jint sampleRateInHz, jint channelConfig, jint audioFormat) { jint ret_value = J4AC_android_media_AudioTrack__getMinBufferSize(env, sampleRateInHz, channelConfig, audioFormat); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } jfloat J4AC_android_media_AudioTrack__getMaxVolume(JNIEnv *env) { return (*env)->CallStaticFloatMethod(env, class_J4AC_android_media_AudioTrack.id, class_J4AC_android_media_AudioTrack.method_getMaxVolume); } jfloat J4AC_android_media_AudioTrack__getMaxVolume__catchAll(JNIEnv *env) { jfloat ret_value = J4AC_android_media_AudioTrack__getMaxVolume(env); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } jfloat J4AC_android_media_AudioTrack__getMinVolume(JNIEnv *env) { return (*env)->CallStaticFloatMethod(env, class_J4AC_android_media_AudioTrack.id, class_J4AC_android_media_AudioTrack.method_getMinVolume); } jfloat J4AC_android_media_AudioTrack__getMinVolume__catchAll(JNIEnv *env) { jfloat ret_value = J4AC_android_media_AudioTrack__getMinVolume(env); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } jint J4AC_android_media_AudioTrack__getNativeOutputSampleRate(JNIEnv *env, jint streamType) { return (*env)->CallStaticIntMethod(env, class_J4AC_android_media_AudioTrack.id, class_J4AC_android_media_AudioTrack.method_getNativeOutputSampleRate, streamType); } jint J4AC_android_media_AudioTrack__getNativeOutputSampleRate__catchAll(JNIEnv *env, jint streamType) { jint ret_value = J4AC_android_media_AudioTrack__getNativeOutputSampleRate(env, streamType); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } void J4AC_android_media_AudioTrack__play(JNIEnv *env, jobject thiz) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_play); } void J4AC_android_media_AudioTrack__play__catchAll(JNIEnv *env, jobject thiz) { J4AC_android_media_AudioTrack__play(env, thiz); J4A_ExceptionCheck__catchAll(env); } void J4AC_android_media_AudioTrack__pause(JNIEnv *env, jobject thiz) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_pause); } void J4AC_android_media_AudioTrack__pause__catchAll(JNIEnv *env, jobject thiz) { J4AC_android_media_AudioTrack__pause(env, thiz); J4A_ExceptionCheck__catchAll(env); } void J4AC_android_media_AudioTrack__stop(JNIEnv *env, jobject thiz) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_stop); } void J4AC_android_media_AudioTrack__stop__catchAll(JNIEnv *env, jobject thiz) { J4AC_android_media_AudioTrack__stop(env, thiz); J4A_ExceptionCheck__catchAll(env); } void J4AC_android_media_AudioTrack__flush(JNIEnv *env, jobject thiz) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_flush); } void J4AC_android_media_AudioTrack__flush__catchAll(JNIEnv *env, jobject thiz) { J4AC_android_media_AudioTrack__flush(env, thiz); J4A_ExceptionCheck__catchAll(env); } void J4AC_android_media_AudioTrack__release(JNIEnv *env, jobject thiz) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_release); } void J4AC_android_media_AudioTrack__release__catchAll(JNIEnv *env, jobject thiz) { J4AC_android_media_AudioTrack__release(env, thiz); J4A_ExceptionCheck__catchAll(env); } jint J4AC_android_media_AudioTrack__write(JNIEnv *env, jobject thiz, jbyteArray audioData, jint offsetInBytes, jint sizeInBytes) { return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_write, audioData, offsetInBytes, sizeInBytes); } jint J4AC_android_media_AudioTrack__write__catchAll(JNIEnv *env, jobject thiz, jbyteArray audioData, jint offsetInBytes, jint sizeInBytes) { jint ret_value = J4AC_android_media_AudioTrack__write(env, thiz, audioData, offsetInBytes, sizeInBytes); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } jint J4AC_android_media_AudioTrack__setStereoVolume(JNIEnv *env, jobject thiz, jfloat leftGain, jfloat rightGain) { return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_setStereoVolume, leftGain, rightGain); } jint J4AC_android_media_AudioTrack__setStereoVolume__catchAll(JNIEnv *env, jobject thiz, jfloat leftGain, jfloat rightGain) { jint ret_value = J4AC_android_media_AudioTrack__setStereoVolume(env, thiz, leftGain, rightGain); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } jint J4AC_android_media_AudioTrack__getAudioSessionId(JNIEnv *env, jobject thiz) { return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_getAudioSessionId); } jint J4AC_android_media_AudioTrack__getAudioSessionId__catchAll(JNIEnv *env, jobject thiz) { jint ret_value = J4AC_android_media_AudioTrack__getAudioSessionId(env, thiz); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } jobject J4AC_android_media_AudioTrack__getPlaybackParams(JNIEnv *env, jobject thiz) { return (*env)->CallObjectMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_getPlaybackParams); } jobject J4AC_android_media_AudioTrack__getPlaybackParams__catchAll(JNIEnv *env, jobject thiz) { jobject ret_object = J4AC_android_media_AudioTrack__getPlaybackParams(env, thiz); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { return NULL; } return ret_object; } jobject J4AC_android_media_AudioTrack__getPlaybackParams__asGlobalRef__catchAll(JNIEnv *env, jobject thiz) { jobject ret_object = NULL; jobject local_object = J4AC_android_media_AudioTrack__getPlaybackParams__catchAll(env, thiz); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } void J4AC_android_media_AudioTrack__setPlaybackParams(JNIEnv *env, jobject thiz, jobject params) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_setPlaybackParams, params); } void J4AC_android_media_AudioTrack__setPlaybackParams__catchAll(JNIEnv *env, jobject thiz, jobject params) { J4AC_android_media_AudioTrack__setPlaybackParams(env, thiz, params); J4A_ExceptionCheck__catchAll(env); } jint J4AC_android_media_AudioTrack__getStreamType(JNIEnv *env, jobject thiz) { return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_getStreamType); } jint J4AC_android_media_AudioTrack__getStreamType__catchAll(JNIEnv *env, jobject thiz) { jint ret_value = J4AC_android_media_AudioTrack__getStreamType(env, thiz); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } jint J4AC_android_media_AudioTrack__getSampleRate(JNIEnv *env, jobject thiz) { return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_getSampleRate); } jint J4AC_android_media_AudioTrack__getSampleRate__catchAll(JNIEnv *env, jobject thiz) { jint ret_value = J4AC_android_media_AudioTrack__getSampleRate(env, thiz); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } jint J4AC_android_media_AudioTrack__getPlaybackRate(JNIEnv *env, jobject thiz) { return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_getPlaybackRate); } jint J4AC_android_media_AudioTrack__getPlaybackRate__catchAll(JNIEnv *env, jobject thiz) { jint ret_value = J4AC_android_media_AudioTrack__getPlaybackRate(env, thiz); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } jint J4AC_android_media_AudioTrack__setPlaybackRate(JNIEnv *env, jobject thiz, jint sampleRateInHz) { return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_AudioTrack.method_setPlaybackRate, sampleRateInHz); } jint J4AC_android_media_AudioTrack__setPlaybackRate__catchAll(JNIEnv *env, jobject thiz, jint sampleRateInHz) { jint ret_value = J4AC_android_media_AudioTrack__setPlaybackRate(env, thiz, sampleRateInHz); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } int J4A_loadClass__J4AC_android_media_AudioTrack(JNIEnv *env) { int ret = -1; const char *J4A_UNUSED(name) = NULL; const char *J4A_UNUSED(sign) = NULL; jclass J4A_UNUSED(class_id) = NULL; int J4A_UNUSED(api_level) = 0; if (class_J4AC_android_media_AudioTrack.id != NULL) return 0; sign = "android/media/AudioTrack"; class_J4AC_android_media_AudioTrack.id = J4A_FindClass__asGlobalRef__catchAll(env, sign); if (class_J4AC_android_media_AudioTrack.id == NULL) goto fail; class_id = class_J4AC_android_media_AudioTrack.id; name = ""; sign = "(IIIIII)V"; class_J4AC_android_media_AudioTrack.constructor_AudioTrack = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.constructor_AudioTrack == NULL) goto fail; class_id = class_J4AC_android_media_AudioTrack.id; name = "getMinBufferSize"; sign = "(III)I"; class_J4AC_android_media_AudioTrack.method_getMinBufferSize = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_getMinBufferSize == NULL) goto fail; class_id = class_J4AC_android_media_AudioTrack.id; name = "getMaxVolume"; sign = "()F"; class_J4AC_android_media_AudioTrack.method_getMaxVolume = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_getMaxVolume == NULL) goto fail; class_id = class_J4AC_android_media_AudioTrack.id; name = "getMinVolume"; sign = "()F"; class_J4AC_android_media_AudioTrack.method_getMinVolume = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_getMinVolume == NULL) goto fail; class_id = class_J4AC_android_media_AudioTrack.id; name = "getNativeOutputSampleRate"; sign = "(I)I"; class_J4AC_android_media_AudioTrack.method_getNativeOutputSampleRate = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_getNativeOutputSampleRate == NULL) goto fail; class_id = class_J4AC_android_media_AudioTrack.id; name = "play"; sign = "()V"; class_J4AC_android_media_AudioTrack.method_play = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_play == NULL) goto fail; class_id = class_J4AC_android_media_AudioTrack.id; name = "pause"; sign = "()V"; class_J4AC_android_media_AudioTrack.method_pause = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_pause == NULL) goto fail; class_id = class_J4AC_android_media_AudioTrack.id; name = "stop"; sign = "()V"; class_J4AC_android_media_AudioTrack.method_stop = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_stop == NULL) goto fail; class_id = class_J4AC_android_media_AudioTrack.id; name = "flush"; sign = "()V"; class_J4AC_android_media_AudioTrack.method_flush = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_flush == NULL) goto fail; class_id = class_J4AC_android_media_AudioTrack.id; name = "release"; sign = "()V"; class_J4AC_android_media_AudioTrack.method_release = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_release == NULL) goto fail; class_id = class_J4AC_android_media_AudioTrack.id; name = "write"; sign = "([BII)I"; class_J4AC_android_media_AudioTrack.method_write = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_write == NULL) goto fail; class_id = class_J4AC_android_media_AudioTrack.id; name = "setStereoVolume"; sign = "(FF)I"; class_J4AC_android_media_AudioTrack.method_setStereoVolume = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_setStereoVolume == NULL) goto fail; class_id = class_J4AC_android_media_AudioTrack.id; name = "getAudioSessionId"; sign = "()I"; class_J4AC_android_media_AudioTrack.method_getAudioSessionId = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_getAudioSessionId == NULL) goto fail; if (J4A_GetSystemAndroidApiLevel(env) >= 23) { class_id = class_J4AC_android_media_AudioTrack.id; name = "getPlaybackParams"; sign = "()Landroid/media/PlaybackParams;"; class_J4AC_android_media_AudioTrack.method_getPlaybackParams = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_getPlaybackParams == NULL) goto fail; } if (J4A_GetSystemAndroidApiLevel(env) >= 23) { class_id = class_J4AC_android_media_AudioTrack.id; name = "setPlaybackParams"; sign = "(Landroid/media/PlaybackParams;)V"; class_J4AC_android_media_AudioTrack.method_setPlaybackParams = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_setPlaybackParams == NULL) goto fail; } class_id = class_J4AC_android_media_AudioTrack.id; name = "getStreamType"; sign = "()I"; class_J4AC_android_media_AudioTrack.method_getStreamType = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_getStreamType == NULL) goto fail; class_id = class_J4AC_android_media_AudioTrack.id; name = "getSampleRate"; sign = "()I"; class_J4AC_android_media_AudioTrack.method_getSampleRate = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_getSampleRate == NULL) goto fail; class_id = class_J4AC_android_media_AudioTrack.id; name = "getPlaybackRate"; sign = "()I"; class_J4AC_android_media_AudioTrack.method_getPlaybackRate = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_getPlaybackRate == NULL) goto fail; class_id = class_J4AC_android_media_AudioTrack.id; name = "setPlaybackRate"; sign = "(I)I"; class_J4AC_android_media_AudioTrack.method_setPlaybackRate = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_AudioTrack.method_setPlaybackRate == NULL) goto fail; J4A_ALOGD("J4ALoader: OK: '%s' loaded\n", "android.media.AudioTrack"); ret = 0; fail: return ret; } ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/media/AudioTrack.h ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #ifndef J4A__android_media_AudioTrack__H #define J4A__android_media_AudioTrack__H #include "j4a/j4a_base.h" jobject J4AC_android_media_AudioTrack__AudioTrack(JNIEnv *env, jint streamType, jint sampleRateInHz, jint channelConfig, jint audioFormat, jint bufferSizeInBytes, jint mode); jobject J4AC_android_media_AudioTrack__AudioTrack__catchAll(JNIEnv *env, jint streamType, jint sampleRateInHz, jint channelConfig, jint audioFormat, jint bufferSizeInBytes, jint mode); jobject J4AC_android_media_AudioTrack__AudioTrack__asGlobalRef__catchAll(JNIEnv *env, jint streamType, jint sampleRateInHz, jint channelConfig, jint audioFormat, jint bufferSizeInBytes, jint mode); jint J4AC_android_media_AudioTrack__getMinBufferSize(JNIEnv *env, jint sampleRateInHz, jint channelConfig, jint audioFormat); jint J4AC_android_media_AudioTrack__getMinBufferSize__catchAll(JNIEnv *env, jint sampleRateInHz, jint channelConfig, jint audioFormat); jfloat J4AC_android_media_AudioTrack__getMaxVolume(JNIEnv *env); jfloat J4AC_android_media_AudioTrack__getMaxVolume__catchAll(JNIEnv *env); jfloat J4AC_android_media_AudioTrack__getMinVolume(JNIEnv *env); jfloat J4AC_android_media_AudioTrack__getMinVolume__catchAll(JNIEnv *env); jint J4AC_android_media_AudioTrack__getNativeOutputSampleRate(JNIEnv *env, jint streamType); jint J4AC_android_media_AudioTrack__getNativeOutputSampleRate__catchAll(JNIEnv *env, jint streamType); void J4AC_android_media_AudioTrack__play(JNIEnv *env, jobject thiz); void J4AC_android_media_AudioTrack__play__catchAll(JNIEnv *env, jobject thiz); void J4AC_android_media_AudioTrack__pause(JNIEnv *env, jobject thiz); void J4AC_android_media_AudioTrack__pause__catchAll(JNIEnv *env, jobject thiz); void J4AC_android_media_AudioTrack__stop(JNIEnv *env, jobject thiz); void J4AC_android_media_AudioTrack__stop__catchAll(JNIEnv *env, jobject thiz); void J4AC_android_media_AudioTrack__flush(JNIEnv *env, jobject thiz); void J4AC_android_media_AudioTrack__flush__catchAll(JNIEnv *env, jobject thiz); void J4AC_android_media_AudioTrack__release(JNIEnv *env, jobject thiz); void J4AC_android_media_AudioTrack__release__catchAll(JNIEnv *env, jobject thiz); jint J4AC_android_media_AudioTrack__write(JNIEnv *env, jobject thiz, jbyteArray audioData, jint offsetInBytes, jint sizeInBytes); jint J4AC_android_media_AudioTrack__write__catchAll(JNIEnv *env, jobject thiz, jbyteArray audioData, jint offsetInBytes, jint sizeInBytes); jint J4AC_android_media_AudioTrack__setStereoVolume(JNIEnv *env, jobject thiz, jfloat leftGain, jfloat rightGain); jint J4AC_android_media_AudioTrack__setStereoVolume__catchAll(JNIEnv *env, jobject thiz, jfloat leftGain, jfloat rightGain); jint J4AC_android_media_AudioTrack__getAudioSessionId(JNIEnv *env, jobject thiz); jint J4AC_android_media_AudioTrack__getAudioSessionId__catchAll(JNIEnv *env, jobject thiz); jobject J4AC_android_media_AudioTrack__getPlaybackParams(JNIEnv *env, jobject thiz); jobject J4AC_android_media_AudioTrack__getPlaybackParams__catchAll(JNIEnv *env, jobject thiz); jobject J4AC_android_media_AudioTrack__getPlaybackParams__asGlobalRef__catchAll(JNIEnv *env, jobject thiz); void J4AC_android_media_AudioTrack__setPlaybackParams(JNIEnv *env, jobject thiz, jobject params); void J4AC_android_media_AudioTrack__setPlaybackParams__catchAll(JNIEnv *env, jobject thiz, jobject params); jint J4AC_android_media_AudioTrack__getStreamType(JNIEnv *env, jobject thiz); jint J4AC_android_media_AudioTrack__getStreamType__catchAll(JNIEnv *env, jobject thiz); jint J4AC_android_media_AudioTrack__getSampleRate(JNIEnv *env, jobject thiz); jint J4AC_android_media_AudioTrack__getSampleRate__catchAll(JNIEnv *env, jobject thiz); jint J4AC_android_media_AudioTrack__getPlaybackRate(JNIEnv *env, jobject thiz); jint J4AC_android_media_AudioTrack__getPlaybackRate__catchAll(JNIEnv *env, jobject thiz); jint J4AC_android_media_AudioTrack__setPlaybackRate(JNIEnv *env, jobject thiz, jint sampleRateInHz); jint J4AC_android_media_AudioTrack__setPlaybackRate__catchAll(JNIEnv *env, jobject thiz, jint sampleRateInHz); int J4A_loadClass__J4AC_android_media_AudioTrack(JNIEnv *env); #define J4A_HAVE_SIMPLE__J4AC_android_media_AudioTrack #define J4AC_AudioTrack__AudioTrack J4AC_android_media_AudioTrack__AudioTrack #define J4AC_AudioTrack__AudioTrack__asGlobalRef__catchAll J4AC_android_media_AudioTrack__AudioTrack__asGlobalRef__catchAll #define J4AC_AudioTrack__AudioTrack__catchAll J4AC_android_media_AudioTrack__AudioTrack__catchAll #define J4AC_AudioTrack__getMinBufferSize J4AC_android_media_AudioTrack__getMinBufferSize #define J4AC_AudioTrack__getMinBufferSize__catchAll J4AC_android_media_AudioTrack__getMinBufferSize__catchAll #define J4AC_AudioTrack__getMaxVolume J4AC_android_media_AudioTrack__getMaxVolume #define J4AC_AudioTrack__getMaxVolume__catchAll J4AC_android_media_AudioTrack__getMaxVolume__catchAll #define J4AC_AudioTrack__getMinVolume J4AC_android_media_AudioTrack__getMinVolume #define J4AC_AudioTrack__getMinVolume__catchAll J4AC_android_media_AudioTrack__getMinVolume__catchAll #define J4AC_AudioTrack__getNativeOutputSampleRate J4AC_android_media_AudioTrack__getNativeOutputSampleRate #define J4AC_AudioTrack__getNativeOutputSampleRate__catchAll J4AC_android_media_AudioTrack__getNativeOutputSampleRate__catchAll #define J4AC_AudioTrack__play J4AC_android_media_AudioTrack__play #define J4AC_AudioTrack__play__catchAll J4AC_android_media_AudioTrack__play__catchAll #define J4AC_AudioTrack__pause J4AC_android_media_AudioTrack__pause #define J4AC_AudioTrack__pause__catchAll J4AC_android_media_AudioTrack__pause__catchAll #define J4AC_AudioTrack__stop J4AC_android_media_AudioTrack__stop #define J4AC_AudioTrack__stop__catchAll J4AC_android_media_AudioTrack__stop__catchAll #define J4AC_AudioTrack__flush J4AC_android_media_AudioTrack__flush #define J4AC_AudioTrack__flush__catchAll J4AC_android_media_AudioTrack__flush__catchAll #define J4AC_AudioTrack__release J4AC_android_media_AudioTrack__release #define J4AC_AudioTrack__release__catchAll J4AC_android_media_AudioTrack__release__catchAll #define J4AC_AudioTrack__write J4AC_android_media_AudioTrack__write #define J4AC_AudioTrack__write__catchAll J4AC_android_media_AudioTrack__write__catchAll #define J4AC_AudioTrack__setStereoVolume J4AC_android_media_AudioTrack__setStereoVolume #define J4AC_AudioTrack__setStereoVolume__catchAll J4AC_android_media_AudioTrack__setStereoVolume__catchAll #define J4AC_AudioTrack__getAudioSessionId J4AC_android_media_AudioTrack__getAudioSessionId #define J4AC_AudioTrack__getAudioSessionId__catchAll J4AC_android_media_AudioTrack__getAudioSessionId__catchAll #define J4AC_AudioTrack__getPlaybackParams J4AC_android_media_AudioTrack__getPlaybackParams #define J4AC_AudioTrack__getPlaybackParams__asGlobalRef__catchAll J4AC_android_media_AudioTrack__getPlaybackParams__asGlobalRef__catchAll #define J4AC_AudioTrack__getPlaybackParams__catchAll J4AC_android_media_AudioTrack__getPlaybackParams__catchAll #define J4AC_AudioTrack__setPlaybackParams J4AC_android_media_AudioTrack__setPlaybackParams #define J4AC_AudioTrack__setPlaybackParams__catchAll J4AC_android_media_AudioTrack__setPlaybackParams__catchAll #define J4AC_AudioTrack__getStreamType J4AC_android_media_AudioTrack__getStreamType #define J4AC_AudioTrack__getStreamType__catchAll J4AC_android_media_AudioTrack__getStreamType__catchAll #define J4AC_AudioTrack__getSampleRate J4AC_android_media_AudioTrack__getSampleRate #define J4AC_AudioTrack__getSampleRate__catchAll J4AC_android_media_AudioTrack__getSampleRate__catchAll #define J4AC_AudioTrack__getPlaybackRate J4AC_android_media_AudioTrack__getPlaybackRate #define J4AC_AudioTrack__getPlaybackRate__catchAll J4AC_android_media_AudioTrack__getPlaybackRate__catchAll #define J4AC_AudioTrack__setPlaybackRate J4AC_android_media_AudioTrack__setPlaybackRate #define J4AC_AudioTrack__setPlaybackRate__catchAll J4AC_android_media_AudioTrack__setPlaybackRate__catchAll #define J4A_loadClass__J4AC_AudioTrack J4A_loadClass__J4AC_android_media_AudioTrack #endif//J4A__android_media_AudioTrack__H ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/media/AudioTrack.include.j4a ================================================ #include "j4a/class/android/media/AudioTrack.h" ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/media/AudioTrack.loader.j4a ================================================ J4A_LOAD_CLASS(android_media_AudioTrack); ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/media/MediaCodec.c ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #include "MediaCodec.h" typedef struct J4AC_android_media_MediaCodec__BufferInfo { jclass id; jfieldID field_flags; jfieldID field_offset; jfieldID field_presentationTimeUs; jfieldID field_size; jmethodID constructor_BufferInfo; } J4AC_android_media_MediaCodec__BufferInfo; static J4AC_android_media_MediaCodec__BufferInfo class_J4AC_android_media_MediaCodec__BufferInfo; typedef struct J4AC_android_media_MediaCodec { jclass id; jmethodID method_createByCodecName; jmethodID method_configure; jmethodID method_getOutputFormat; jmethodID method_getInputBuffers; jmethodID method_dequeueInputBuffer; jmethodID method_queueInputBuffer; jmethodID method_dequeueOutputBuffer; jmethodID method_releaseOutputBuffer; jmethodID method_start; jmethodID method_stop; jmethodID method_flush; jmethodID method_release; } J4AC_android_media_MediaCodec; static J4AC_android_media_MediaCodec class_J4AC_android_media_MediaCodec; jint J4AC_android_media_MediaCodec__BufferInfo__flags__get(JNIEnv *env, jobject thiz) { return (*env)->GetIntField(env, thiz, class_J4AC_android_media_MediaCodec__BufferInfo.field_flags); } jint J4AC_android_media_MediaCodec__BufferInfo__flags__get__catchAll(JNIEnv *env, jobject thiz) { jint ret_value = J4AC_android_media_MediaCodec__BufferInfo__flags__get(env, thiz); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } void J4AC_android_media_MediaCodec__BufferInfo__flags__set(JNIEnv *env, jobject thiz, jint value) { (*env)->SetIntField(env, thiz, class_J4AC_android_media_MediaCodec__BufferInfo.field_flags, value); } void J4AC_android_media_MediaCodec__BufferInfo__flags__set__catchAll(JNIEnv *env, jobject thiz, jint value) { J4AC_android_media_MediaCodec__BufferInfo__flags__set(env, thiz, value); J4A_ExceptionCheck__catchAll(env); } jint J4AC_android_media_MediaCodec__BufferInfo__offset__get(JNIEnv *env, jobject thiz) { return (*env)->GetIntField(env, thiz, class_J4AC_android_media_MediaCodec__BufferInfo.field_offset); } jint J4AC_android_media_MediaCodec__BufferInfo__offset__get__catchAll(JNIEnv *env, jobject thiz) { jint ret_value = J4AC_android_media_MediaCodec__BufferInfo__offset__get(env, thiz); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } void J4AC_android_media_MediaCodec__BufferInfo__offset__set(JNIEnv *env, jobject thiz, jint value) { (*env)->SetIntField(env, thiz, class_J4AC_android_media_MediaCodec__BufferInfo.field_offset, value); } void J4AC_android_media_MediaCodec__BufferInfo__offset__set__catchAll(JNIEnv *env, jobject thiz, jint value) { J4AC_android_media_MediaCodec__BufferInfo__offset__set(env, thiz, value); J4A_ExceptionCheck__catchAll(env); } jlong J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__get(JNIEnv *env, jobject thiz) { return (*env)->GetLongField(env, thiz, class_J4AC_android_media_MediaCodec__BufferInfo.field_presentationTimeUs); } jlong J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__get__catchAll(JNIEnv *env, jobject thiz) { jlong ret_value = J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__get(env, thiz); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } void J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__set(JNIEnv *env, jobject thiz, jlong value) { (*env)->SetLongField(env, thiz, class_J4AC_android_media_MediaCodec__BufferInfo.field_presentationTimeUs, value); } void J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__set__catchAll(JNIEnv *env, jobject thiz, jlong value) { J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__set(env, thiz, value); J4A_ExceptionCheck__catchAll(env); } jint J4AC_android_media_MediaCodec__BufferInfo__size__get(JNIEnv *env, jobject thiz) { return (*env)->GetIntField(env, thiz, class_J4AC_android_media_MediaCodec__BufferInfo.field_size); } jint J4AC_android_media_MediaCodec__BufferInfo__size__get__catchAll(JNIEnv *env, jobject thiz) { jint ret_value = J4AC_android_media_MediaCodec__BufferInfo__size__get(env, thiz); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } void J4AC_android_media_MediaCodec__BufferInfo__size__set(JNIEnv *env, jobject thiz, jint value) { (*env)->SetIntField(env, thiz, class_J4AC_android_media_MediaCodec__BufferInfo.field_size, value); } void J4AC_android_media_MediaCodec__BufferInfo__size__set__catchAll(JNIEnv *env, jobject thiz, jint value) { J4AC_android_media_MediaCodec__BufferInfo__size__set(env, thiz, value); J4A_ExceptionCheck__catchAll(env); } jobject J4AC_android_media_MediaCodec__BufferInfo__BufferInfo(JNIEnv *env) { return (*env)->NewObject(env, class_J4AC_android_media_MediaCodec__BufferInfo.id, class_J4AC_android_media_MediaCodec__BufferInfo.constructor_BufferInfo); } jobject J4AC_android_media_MediaCodec__BufferInfo__BufferInfo__catchAll(JNIEnv *env) { jobject ret_object = J4AC_android_media_MediaCodec__BufferInfo__BufferInfo(env); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { return NULL; } return ret_object; } jobject J4AC_android_media_MediaCodec__BufferInfo__BufferInfo__asGlobalRef__catchAll(JNIEnv *env) { jobject ret_object = NULL; jobject local_object = J4AC_android_media_MediaCodec__BufferInfo__BufferInfo__catchAll(env); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } int J4A_loadClass__J4AC_android_media_MediaCodec__BufferInfo(JNIEnv *env) { int ret = -1; const char *J4A_UNUSED(name) = NULL; const char *J4A_UNUSED(sign) = NULL; jclass J4A_UNUSED(class_id) = NULL; int J4A_UNUSED(api_level) = 0; if (class_J4AC_android_media_MediaCodec__BufferInfo.id != NULL) return 0; sign = "android/media/MediaCodec$BufferInfo"; class_J4AC_android_media_MediaCodec__BufferInfo.id = J4A_FindClass__asGlobalRef__catchAll(env, sign); if (class_J4AC_android_media_MediaCodec__BufferInfo.id == NULL) goto fail; class_id = class_J4AC_android_media_MediaCodec__BufferInfo.id; name = "flags"; sign = "I"; class_J4AC_android_media_MediaCodec__BufferInfo.field_flags = J4A_GetFieldID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaCodec__BufferInfo.field_flags == NULL) goto fail; class_id = class_J4AC_android_media_MediaCodec__BufferInfo.id; name = "offset"; sign = "I"; class_J4AC_android_media_MediaCodec__BufferInfo.field_offset = J4A_GetFieldID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaCodec__BufferInfo.field_offset == NULL) goto fail; class_id = class_J4AC_android_media_MediaCodec__BufferInfo.id; name = "presentationTimeUs"; sign = "J"; class_J4AC_android_media_MediaCodec__BufferInfo.field_presentationTimeUs = J4A_GetFieldID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaCodec__BufferInfo.field_presentationTimeUs == NULL) goto fail; class_id = class_J4AC_android_media_MediaCodec__BufferInfo.id; name = "size"; sign = "I"; class_J4AC_android_media_MediaCodec__BufferInfo.field_size = J4A_GetFieldID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaCodec__BufferInfo.field_size == NULL) goto fail; class_id = class_J4AC_android_media_MediaCodec__BufferInfo.id; name = ""; sign = "()V"; class_J4AC_android_media_MediaCodec__BufferInfo.constructor_BufferInfo = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaCodec__BufferInfo.constructor_BufferInfo == NULL) goto fail; J4A_ALOGD("J4ALoader: OK: '%s' loaded\n", "android.media.MediaCodec$BufferInfo"); ret = 0; fail: return ret; } jobject J4AC_android_media_MediaCodec__createByCodecName(JNIEnv *env, jstring name) { return (*env)->CallStaticObjectMethod(env, class_J4AC_android_media_MediaCodec.id, class_J4AC_android_media_MediaCodec.method_createByCodecName, name); } jobject J4AC_android_media_MediaCodec__createByCodecName__catchAll(JNIEnv *env, jstring name) { jobject ret_object = J4AC_android_media_MediaCodec__createByCodecName(env, name); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { return NULL; } return ret_object; } jobject J4AC_android_media_MediaCodec__createByCodecName__asGlobalRef__catchAll(JNIEnv *env, jstring name) { jobject ret_object = NULL; jobject local_object = J4AC_android_media_MediaCodec__createByCodecName__catchAll(env, name); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } jobject J4AC_android_media_MediaCodec__createByCodecName__withCString(JNIEnv *env, const char *name_cstr__) { jobject ret_object = NULL; jstring name = NULL; name = (*env)->NewStringUTF(env, name_cstr__); if (J4A_ExceptionCheck__throwAny(env) || !name) goto fail; ret_object = J4AC_android_media_MediaCodec__createByCodecName(env, name); if (J4A_ExceptionCheck__throwAny(env) || !ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &name); return ret_object; } jobject J4AC_android_media_MediaCodec__createByCodecName__withCString__catchAll(JNIEnv *env, const char *name_cstr__) { jobject ret_object = NULL; jstring name = NULL; name = (*env)->NewStringUTF(env, name_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !name) goto fail; ret_object = J4AC_android_media_MediaCodec__createByCodecName__catchAll(env, name); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &name); return ret_object; } jobject J4AC_android_media_MediaCodec__createByCodecName__withCString__asGlobalRef__catchAll(JNIEnv *env, const char *name_cstr__) { jobject ret_object = NULL; jobject local_object = J4AC_android_media_MediaCodec__createByCodecName__withCString__catchAll(env, name_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } void J4AC_android_media_MediaCodec__configure(JNIEnv *env, jobject thiz, jobject format, jobject surface, jobject crypto, jint flags) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_configure, format, surface, crypto, flags); } void J4AC_android_media_MediaCodec__configure__catchAll(JNIEnv *env, jobject thiz, jobject format, jobject surface, jobject crypto, jint flags) { J4AC_android_media_MediaCodec__configure(env, thiz, format, surface, crypto, flags); J4A_ExceptionCheck__catchAll(env); } jobject J4AC_android_media_MediaCodec__getOutputFormat(JNIEnv *env, jobject thiz) { return (*env)->CallObjectMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_getOutputFormat); } jobject J4AC_android_media_MediaCodec__getOutputFormat__catchAll(JNIEnv *env, jobject thiz) { jobject ret_object = J4AC_android_media_MediaCodec__getOutputFormat(env, thiz); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { return NULL; } return ret_object; } jobject J4AC_android_media_MediaCodec__getOutputFormat__asGlobalRef__catchAll(JNIEnv *env, jobject thiz) { jobject ret_object = NULL; jobject local_object = J4AC_android_media_MediaCodec__getOutputFormat__catchAll(env, thiz); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } jobjectArray J4AC_android_media_MediaCodec__getInputBuffers(JNIEnv *env, jobject thiz) { return (*env)->CallObjectMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_getInputBuffers); } jobjectArray J4AC_android_media_MediaCodec__getInputBuffers__catchAll(JNIEnv *env, jobject thiz) { jobjectArray ret_object = J4AC_android_media_MediaCodec__getInputBuffers(env, thiz); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { return NULL; } return ret_object; } jobjectArray J4AC_android_media_MediaCodec__getInputBuffers__asGlobalRef__catchAll(JNIEnv *env, jobject thiz) { jobjectArray ret_object = NULL; jobjectArray local_object = J4AC_android_media_MediaCodec__getInputBuffers__catchAll(env, thiz); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } jint J4AC_android_media_MediaCodec__dequeueInputBuffer(JNIEnv *env, jobject thiz, jlong timeoutUs) { return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_dequeueInputBuffer, timeoutUs); } jint J4AC_android_media_MediaCodec__dequeueInputBuffer__catchAll(JNIEnv *env, jobject thiz, jlong timeoutUs) { jint ret_value = J4AC_android_media_MediaCodec__dequeueInputBuffer(env, thiz, timeoutUs); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } void J4AC_android_media_MediaCodec__queueInputBuffer(JNIEnv *env, jobject thiz, jint index, jint offset, jint size, jlong presentationTimeUs, jint flags) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_queueInputBuffer, index, offset, size, presentationTimeUs, flags); } void J4AC_android_media_MediaCodec__queueInputBuffer__catchAll(JNIEnv *env, jobject thiz, jint index, jint offset, jint size, jlong presentationTimeUs, jint flags) { J4AC_android_media_MediaCodec__queueInputBuffer(env, thiz, index, offset, size, presentationTimeUs, flags); J4A_ExceptionCheck__catchAll(env); } jint J4AC_android_media_MediaCodec__dequeueOutputBuffer(JNIEnv *env, jobject thiz, jobject info, jlong timeoutUs) { return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_dequeueOutputBuffer, info, timeoutUs); } jint J4AC_android_media_MediaCodec__dequeueOutputBuffer__catchAll(JNIEnv *env, jobject thiz, jobject info, jlong timeoutUs) { jint ret_value = J4AC_android_media_MediaCodec__dequeueOutputBuffer(env, thiz, info, timeoutUs); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } void J4AC_android_media_MediaCodec__releaseOutputBuffer(JNIEnv *env, jobject thiz, jint index, jboolean render) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_releaseOutputBuffer, index, render); } void J4AC_android_media_MediaCodec__releaseOutputBuffer__catchAll(JNIEnv *env, jobject thiz, jint index, jboolean render) { J4AC_android_media_MediaCodec__releaseOutputBuffer(env, thiz, index, render); J4A_ExceptionCheck__catchAll(env); } void J4AC_android_media_MediaCodec__start(JNIEnv *env, jobject thiz) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_start); } void J4AC_android_media_MediaCodec__start__catchAll(JNIEnv *env, jobject thiz) { J4AC_android_media_MediaCodec__start(env, thiz); J4A_ExceptionCheck__catchAll(env); } void J4AC_android_media_MediaCodec__stop(JNIEnv *env, jobject thiz) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_stop); } void J4AC_android_media_MediaCodec__stop__catchAll(JNIEnv *env, jobject thiz) { J4AC_android_media_MediaCodec__stop(env, thiz); J4A_ExceptionCheck__catchAll(env); } void J4AC_android_media_MediaCodec__flush(JNIEnv *env, jobject thiz) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_flush); } void J4AC_android_media_MediaCodec__flush__catchAll(JNIEnv *env, jobject thiz) { J4AC_android_media_MediaCodec__flush(env, thiz); J4A_ExceptionCheck__catchAll(env); } void J4AC_android_media_MediaCodec__release(JNIEnv *env, jobject thiz) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaCodec.method_release); } void J4AC_android_media_MediaCodec__release__catchAll(JNIEnv *env, jobject thiz) { J4AC_android_media_MediaCodec__release(env, thiz); J4A_ExceptionCheck__catchAll(env); } int J4A_loadClass__J4AC_android_media_MediaCodec(JNIEnv *env) { int ret = -1; const char *J4A_UNUSED(name) = NULL; const char *J4A_UNUSED(sign) = NULL; jclass J4A_UNUSED(class_id) = NULL; int J4A_UNUSED(api_level) = 0; if (class_J4AC_android_media_MediaCodec.id != NULL) return 0; api_level = J4A_GetSystemAndroidApiLevel(env); if (api_level < 16) { J4A_ALOGW("J4ALoader: Ignore: '%s' need API %d\n", "android.media.MediaCodec", api_level); goto ignore; } sign = "android/media/MediaCodec"; class_J4AC_android_media_MediaCodec.id = J4A_FindClass__asGlobalRef__catchAll(env, sign); if (class_J4AC_android_media_MediaCodec.id == NULL) goto fail; ret = J4A_loadClass__J4AC_android_media_MediaCodec__BufferInfo(env); if (ret) goto fail; class_id = class_J4AC_android_media_MediaCodec.id; name = "createByCodecName"; sign = "(Ljava/lang/String;)Landroid/media/MediaCodec;"; class_J4AC_android_media_MediaCodec.method_createByCodecName = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaCodec.method_createByCodecName == NULL) goto fail; class_id = class_J4AC_android_media_MediaCodec.id; name = "configure"; sign = "(Landroid/media/MediaFormat;Landroid/view/Surface;Landroid/media/MediaCrypto;I)V"; class_J4AC_android_media_MediaCodec.method_configure = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaCodec.method_configure == NULL) goto fail; class_id = class_J4AC_android_media_MediaCodec.id; name = "getOutputFormat"; sign = "()Landroid/media/MediaFormat;"; class_J4AC_android_media_MediaCodec.method_getOutputFormat = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaCodec.method_getOutputFormat == NULL) goto fail; class_id = class_J4AC_android_media_MediaCodec.id; name = "getInputBuffers"; sign = "()[Ljava/nio/ByteBuffer;"; class_J4AC_android_media_MediaCodec.method_getInputBuffers = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaCodec.method_getInputBuffers == NULL) goto fail; class_id = class_J4AC_android_media_MediaCodec.id; name = "dequeueInputBuffer"; sign = "(J)I"; class_J4AC_android_media_MediaCodec.method_dequeueInputBuffer = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaCodec.method_dequeueInputBuffer == NULL) goto fail; class_id = class_J4AC_android_media_MediaCodec.id; name = "queueInputBuffer"; sign = "(IIIJI)V"; class_J4AC_android_media_MediaCodec.method_queueInputBuffer = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaCodec.method_queueInputBuffer == NULL) goto fail; class_id = class_J4AC_android_media_MediaCodec.id; name = "dequeueOutputBuffer"; sign = "(Landroid/media/MediaCodec$BufferInfo;J)I"; class_J4AC_android_media_MediaCodec.method_dequeueOutputBuffer = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaCodec.method_dequeueOutputBuffer == NULL) goto fail; class_id = class_J4AC_android_media_MediaCodec.id; name = "releaseOutputBuffer"; sign = "(IZ)V"; class_J4AC_android_media_MediaCodec.method_releaseOutputBuffer = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaCodec.method_releaseOutputBuffer == NULL) goto fail; class_id = class_J4AC_android_media_MediaCodec.id; name = "start"; sign = "()V"; class_J4AC_android_media_MediaCodec.method_start = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaCodec.method_start == NULL) goto fail; class_id = class_J4AC_android_media_MediaCodec.id; name = "stop"; sign = "()V"; class_J4AC_android_media_MediaCodec.method_stop = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaCodec.method_stop == NULL) goto fail; class_id = class_J4AC_android_media_MediaCodec.id; name = "flush"; sign = "()V"; class_J4AC_android_media_MediaCodec.method_flush = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaCodec.method_flush == NULL) goto fail; class_id = class_J4AC_android_media_MediaCodec.id; name = "release"; sign = "()V"; class_J4AC_android_media_MediaCodec.method_release = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaCodec.method_release == NULL) goto fail; J4A_ALOGD("J4ALoader: OK: '%s' loaded\n", "android.media.MediaCodec"); ignore: ret = 0; fail: return ret; } ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/media/MediaCodec.h ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #ifndef J4A__android_media_MediaCodec__H #define J4A__android_media_MediaCodec__H #include "j4a/j4a_base.h" jint J4AC_android_media_MediaCodec__BufferInfo__flags__get(JNIEnv *env, jobject thiz); jint J4AC_android_media_MediaCodec__BufferInfo__flags__get__catchAll(JNIEnv *env, jobject thiz); void J4AC_android_media_MediaCodec__BufferInfo__flags__set(JNIEnv *env, jobject thiz, jint value); void J4AC_android_media_MediaCodec__BufferInfo__flags__set__catchAll(JNIEnv *env, jobject thiz, jint value); jint J4AC_android_media_MediaCodec__BufferInfo__offset__get(JNIEnv *env, jobject thiz); jint J4AC_android_media_MediaCodec__BufferInfo__offset__get__catchAll(JNIEnv *env, jobject thiz); void J4AC_android_media_MediaCodec__BufferInfo__offset__set(JNIEnv *env, jobject thiz, jint value); void J4AC_android_media_MediaCodec__BufferInfo__offset__set__catchAll(JNIEnv *env, jobject thiz, jint value); jlong J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__get(JNIEnv *env, jobject thiz); jlong J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__get__catchAll(JNIEnv *env, jobject thiz); void J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__set(JNIEnv *env, jobject thiz, jlong value); void J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__set__catchAll(JNIEnv *env, jobject thiz, jlong value); jint J4AC_android_media_MediaCodec__BufferInfo__size__get(JNIEnv *env, jobject thiz); jint J4AC_android_media_MediaCodec__BufferInfo__size__get__catchAll(JNIEnv *env, jobject thiz); void J4AC_android_media_MediaCodec__BufferInfo__size__set(JNIEnv *env, jobject thiz, jint value); void J4AC_android_media_MediaCodec__BufferInfo__size__set__catchAll(JNIEnv *env, jobject thiz, jint value); jobject J4AC_android_media_MediaCodec__BufferInfo__BufferInfo(JNIEnv *env); jobject J4AC_android_media_MediaCodec__BufferInfo__BufferInfo__catchAll(JNIEnv *env); jobject J4AC_android_media_MediaCodec__BufferInfo__BufferInfo__asGlobalRef__catchAll(JNIEnv *env); jobject J4AC_android_media_MediaCodec__createByCodecName(JNIEnv *env, jstring name); jobject J4AC_android_media_MediaCodec__createByCodecName__catchAll(JNIEnv *env, jstring name); jobject J4AC_android_media_MediaCodec__createByCodecName__asGlobalRef__catchAll(JNIEnv *env, jstring name); jobject J4AC_android_media_MediaCodec__createByCodecName__withCString(JNIEnv *env, const char *name_cstr__); jobject J4AC_android_media_MediaCodec__createByCodecName__withCString__catchAll(JNIEnv *env, const char *name_cstr__); jobject J4AC_android_media_MediaCodec__createByCodecName__withCString__asGlobalRef__catchAll(JNIEnv *env, const char *name_cstr__); void J4AC_android_media_MediaCodec__configure(JNIEnv *env, jobject thiz, jobject format, jobject surface, jobject crypto, jint flags); void J4AC_android_media_MediaCodec__configure__catchAll(JNIEnv *env, jobject thiz, jobject format, jobject surface, jobject crypto, jint flags); jobject J4AC_android_media_MediaCodec__getOutputFormat(JNIEnv *env, jobject thiz); jobject J4AC_android_media_MediaCodec__getOutputFormat__catchAll(JNIEnv *env, jobject thiz); jobject J4AC_android_media_MediaCodec__getOutputFormat__asGlobalRef__catchAll(JNIEnv *env, jobject thiz); jobjectArray J4AC_android_media_MediaCodec__getInputBuffers(JNIEnv *env, jobject thiz); jobjectArray J4AC_android_media_MediaCodec__getInputBuffers__catchAll(JNIEnv *env, jobject thiz); jobjectArray J4AC_android_media_MediaCodec__getInputBuffers__asGlobalRef__catchAll(JNIEnv *env, jobject thiz); jint J4AC_android_media_MediaCodec__dequeueInputBuffer(JNIEnv *env, jobject thiz, jlong timeoutUs); jint J4AC_android_media_MediaCodec__dequeueInputBuffer__catchAll(JNIEnv *env, jobject thiz, jlong timeoutUs); void J4AC_android_media_MediaCodec__queueInputBuffer(JNIEnv *env, jobject thiz, jint index, jint offset, jint size, jlong presentationTimeUs, jint flags); void J4AC_android_media_MediaCodec__queueInputBuffer__catchAll(JNIEnv *env, jobject thiz, jint index, jint offset, jint size, jlong presentationTimeUs, jint flags); jint J4AC_android_media_MediaCodec__dequeueOutputBuffer(JNIEnv *env, jobject thiz, jobject info, jlong timeoutUs); jint J4AC_android_media_MediaCodec__dequeueOutputBuffer__catchAll(JNIEnv *env, jobject thiz, jobject info, jlong timeoutUs); void J4AC_android_media_MediaCodec__releaseOutputBuffer(JNIEnv *env, jobject thiz, jint index, jboolean render); void J4AC_android_media_MediaCodec__releaseOutputBuffer__catchAll(JNIEnv *env, jobject thiz, jint index, jboolean render); void J4AC_android_media_MediaCodec__start(JNIEnv *env, jobject thiz); void J4AC_android_media_MediaCodec__start__catchAll(JNIEnv *env, jobject thiz); void J4AC_android_media_MediaCodec__stop(JNIEnv *env, jobject thiz); void J4AC_android_media_MediaCodec__stop__catchAll(JNIEnv *env, jobject thiz); void J4AC_android_media_MediaCodec__flush(JNIEnv *env, jobject thiz); void J4AC_android_media_MediaCodec__flush__catchAll(JNIEnv *env, jobject thiz); void J4AC_android_media_MediaCodec__release(JNIEnv *env, jobject thiz); void J4AC_android_media_MediaCodec__release__catchAll(JNIEnv *env, jobject thiz); int J4A_loadClass__J4AC_android_media_MediaCodec(JNIEnv *env); #define J4A_HAVE_SIMPLE__J4AC_android_media_MediaCodec #define J4AC_MediaCodec__BufferInfo__flags__get J4AC_android_media_MediaCodec__BufferInfo__flags__get #define J4AC_MediaCodec__BufferInfo__flags__get__catchAll J4AC_android_media_MediaCodec__BufferInfo__flags__get__catchAll #define J4AC_MediaCodec__BufferInfo__flags__set J4AC_android_media_MediaCodec__BufferInfo__flags__set #define J4AC_MediaCodec__BufferInfo__flags__set__catchAll J4AC_android_media_MediaCodec__BufferInfo__flags__set__catchAll #define J4AC_MediaCodec__BufferInfo__offset__get J4AC_android_media_MediaCodec__BufferInfo__offset__get #define J4AC_MediaCodec__BufferInfo__offset__get__catchAll J4AC_android_media_MediaCodec__BufferInfo__offset__get__catchAll #define J4AC_MediaCodec__BufferInfo__offset__set J4AC_android_media_MediaCodec__BufferInfo__offset__set #define J4AC_MediaCodec__BufferInfo__offset__set__catchAll J4AC_android_media_MediaCodec__BufferInfo__offset__set__catchAll #define J4AC_MediaCodec__BufferInfo__presentationTimeUs__get J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__get #define J4AC_MediaCodec__BufferInfo__presentationTimeUs__get__catchAll J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__get__catchAll #define J4AC_MediaCodec__BufferInfo__presentationTimeUs__set J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__set #define J4AC_MediaCodec__BufferInfo__presentationTimeUs__set__catchAll J4AC_android_media_MediaCodec__BufferInfo__presentationTimeUs__set__catchAll #define J4AC_MediaCodec__BufferInfo__size__get J4AC_android_media_MediaCodec__BufferInfo__size__get #define J4AC_MediaCodec__BufferInfo__size__get__catchAll J4AC_android_media_MediaCodec__BufferInfo__size__get__catchAll #define J4AC_MediaCodec__BufferInfo__size__set J4AC_android_media_MediaCodec__BufferInfo__size__set #define J4AC_MediaCodec__BufferInfo__size__set__catchAll J4AC_android_media_MediaCodec__BufferInfo__size__set__catchAll #define J4AC_MediaCodec__BufferInfo__BufferInfo J4AC_android_media_MediaCodec__BufferInfo__BufferInfo #define J4AC_MediaCodec__BufferInfo__BufferInfo__asGlobalRef__catchAll J4AC_android_media_MediaCodec__BufferInfo__BufferInfo__asGlobalRef__catchAll #define J4AC_MediaCodec__BufferInfo__BufferInfo__catchAll J4AC_android_media_MediaCodec__BufferInfo__BufferInfo__catchAll #define J4AC_MediaCodec__createByCodecName J4AC_android_media_MediaCodec__createByCodecName #define J4AC_MediaCodec__createByCodecName__asGlobalRef__catchAll J4AC_android_media_MediaCodec__createByCodecName__asGlobalRef__catchAll #define J4AC_MediaCodec__createByCodecName__catchAll J4AC_android_media_MediaCodec__createByCodecName__catchAll #define J4AC_MediaCodec__createByCodecName__withCString J4AC_android_media_MediaCodec__createByCodecName__withCString #define J4AC_MediaCodec__createByCodecName__withCString__asGlobalRef__catchAll J4AC_android_media_MediaCodec__createByCodecName__withCString__asGlobalRef__catchAll #define J4AC_MediaCodec__createByCodecName__withCString__catchAll J4AC_android_media_MediaCodec__createByCodecName__withCString__catchAll #define J4AC_MediaCodec__configure J4AC_android_media_MediaCodec__configure #define J4AC_MediaCodec__configure__catchAll J4AC_android_media_MediaCodec__configure__catchAll #define J4AC_MediaCodec__getOutputFormat J4AC_android_media_MediaCodec__getOutputFormat #define J4AC_MediaCodec__getOutputFormat__asGlobalRef__catchAll J4AC_android_media_MediaCodec__getOutputFormat__asGlobalRef__catchAll #define J4AC_MediaCodec__getOutputFormat__catchAll J4AC_android_media_MediaCodec__getOutputFormat__catchAll #define J4AC_MediaCodec__getInputBuffers J4AC_android_media_MediaCodec__getInputBuffers #define J4AC_MediaCodec__getInputBuffers__asGlobalRef__catchAll J4AC_android_media_MediaCodec__getInputBuffers__asGlobalRef__catchAll #define J4AC_MediaCodec__getInputBuffers__catchAll J4AC_android_media_MediaCodec__getInputBuffers__catchAll #define J4AC_MediaCodec__dequeueInputBuffer J4AC_android_media_MediaCodec__dequeueInputBuffer #define J4AC_MediaCodec__dequeueInputBuffer__catchAll J4AC_android_media_MediaCodec__dequeueInputBuffer__catchAll #define J4AC_MediaCodec__queueInputBuffer J4AC_android_media_MediaCodec__queueInputBuffer #define J4AC_MediaCodec__queueInputBuffer__catchAll J4AC_android_media_MediaCodec__queueInputBuffer__catchAll #define J4AC_MediaCodec__dequeueOutputBuffer J4AC_android_media_MediaCodec__dequeueOutputBuffer #define J4AC_MediaCodec__dequeueOutputBuffer__catchAll J4AC_android_media_MediaCodec__dequeueOutputBuffer__catchAll #define J4AC_MediaCodec__releaseOutputBuffer J4AC_android_media_MediaCodec__releaseOutputBuffer #define J4AC_MediaCodec__releaseOutputBuffer__catchAll J4AC_android_media_MediaCodec__releaseOutputBuffer__catchAll #define J4AC_MediaCodec__start J4AC_android_media_MediaCodec__start #define J4AC_MediaCodec__start__catchAll J4AC_android_media_MediaCodec__start__catchAll #define J4AC_MediaCodec__stop J4AC_android_media_MediaCodec__stop #define J4AC_MediaCodec__stop__catchAll J4AC_android_media_MediaCodec__stop__catchAll #define J4AC_MediaCodec__flush J4AC_android_media_MediaCodec__flush #define J4AC_MediaCodec__flush__catchAll J4AC_android_media_MediaCodec__flush__catchAll #define J4AC_MediaCodec__release J4AC_android_media_MediaCodec__release #define J4AC_MediaCodec__release__catchAll J4AC_android_media_MediaCodec__release__catchAll #define J4A_loadClass__J4AC_MediaCodec J4A_loadClass__J4AC_android_media_MediaCodec #endif//J4A__android_media_MediaCodec__H ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/media/MediaCodec.include.j4a ================================================ #include "j4a/class/android/media/MediaCodec.h" ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/media/MediaCodec.loader.j4a ================================================ J4A_LOAD_CLASS(android_media_MediaCodec); ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/media/MediaFormat.c ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #include "MediaFormat.h" typedef struct J4AC_android_media_MediaFormat { jclass id; jmethodID constructor_MediaFormat; jmethodID method_createVideoFormat; jmethodID method_getInteger; jmethodID method_setInteger; jmethodID method_setByteBuffer; } J4AC_android_media_MediaFormat; static J4AC_android_media_MediaFormat class_J4AC_android_media_MediaFormat; jobject J4AC_android_media_MediaFormat__MediaFormat(JNIEnv *env) { return (*env)->NewObject(env, class_J4AC_android_media_MediaFormat.id, class_J4AC_android_media_MediaFormat.constructor_MediaFormat); } jobject J4AC_android_media_MediaFormat__MediaFormat__catchAll(JNIEnv *env) { jobject ret_object = J4AC_android_media_MediaFormat__MediaFormat(env); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { return NULL; } return ret_object; } jobject J4AC_android_media_MediaFormat__MediaFormat__asGlobalRef__catchAll(JNIEnv *env) { jobject ret_object = NULL; jobject local_object = J4AC_android_media_MediaFormat__MediaFormat__catchAll(env); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } jobject J4AC_android_media_MediaFormat__createVideoFormat(JNIEnv *env, jstring mime, jint width, jint height) { return (*env)->CallStaticObjectMethod(env, class_J4AC_android_media_MediaFormat.id, class_J4AC_android_media_MediaFormat.method_createVideoFormat, mime, width, height); } jobject J4AC_android_media_MediaFormat__createVideoFormat__catchAll(JNIEnv *env, jstring mime, jint width, jint height) { jobject ret_object = J4AC_android_media_MediaFormat__createVideoFormat(env, mime, width, height); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { return NULL; } return ret_object; } jobject J4AC_android_media_MediaFormat__createVideoFormat__asGlobalRef__catchAll(JNIEnv *env, jstring mime, jint width, jint height) { jobject ret_object = NULL; jobject local_object = J4AC_android_media_MediaFormat__createVideoFormat__catchAll(env, mime, width, height); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } jobject J4AC_android_media_MediaFormat__createVideoFormat__withCString(JNIEnv *env, const char *mime_cstr__, jint width, jint height) { jobject ret_object = NULL; jstring mime = NULL; mime = (*env)->NewStringUTF(env, mime_cstr__); if (J4A_ExceptionCheck__throwAny(env) || !mime) goto fail; ret_object = J4AC_android_media_MediaFormat__createVideoFormat(env, mime, width, height); if (J4A_ExceptionCheck__throwAny(env) || !ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &mime); return ret_object; } jobject J4AC_android_media_MediaFormat__createVideoFormat__withCString__catchAll(JNIEnv *env, const char *mime_cstr__, jint width, jint height) { jobject ret_object = NULL; jstring mime = NULL; mime = (*env)->NewStringUTF(env, mime_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !mime) goto fail; ret_object = J4AC_android_media_MediaFormat__createVideoFormat__catchAll(env, mime, width, height); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &mime); return ret_object; } jobject J4AC_android_media_MediaFormat__createVideoFormat__withCString__asGlobalRef__catchAll(JNIEnv *env, const char *mime_cstr__, jint width, jint height) { jobject ret_object = NULL; jobject local_object = J4AC_android_media_MediaFormat__createVideoFormat__withCString__catchAll(env, mime_cstr__, width, height); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } jint J4AC_android_media_MediaFormat__getInteger(JNIEnv *env, jobject thiz, jstring name) { return (*env)->CallIntMethod(env, thiz, class_J4AC_android_media_MediaFormat.method_getInteger, name); } jint J4AC_android_media_MediaFormat__getInteger__catchAll(JNIEnv *env, jobject thiz, jstring name) { jint ret_value = J4AC_android_media_MediaFormat__getInteger(env, thiz, name); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } jint J4AC_android_media_MediaFormat__getInteger__withCString(JNIEnv *env, jobject thiz, const char *name_cstr__) { jint ret_value = 0; jstring name = NULL; name = (*env)->NewStringUTF(env, name_cstr__); if (J4A_ExceptionCheck__throwAny(env) || !name) goto fail; ret_value = J4AC_android_media_MediaFormat__getInteger(env, thiz, name); if (J4A_ExceptionCheck__throwAny(env)) { ret_value = 0; goto fail; } fail: J4A_DeleteLocalRef__p(env, &name); return ret_value; } jint J4AC_android_media_MediaFormat__getInteger__withCString__catchAll(JNIEnv *env, jobject thiz, const char *name_cstr__) { jint ret_value = 0; jstring name = NULL; name = (*env)->NewStringUTF(env, name_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !name) goto fail; ret_value = J4AC_android_media_MediaFormat__getInteger__catchAll(env, thiz, name); if (J4A_ExceptionCheck__catchAll(env)) { ret_value = 0; goto fail; } fail: J4A_DeleteLocalRef__p(env, &name); return ret_value; } void J4AC_android_media_MediaFormat__setInteger(JNIEnv *env, jobject thiz, jstring name, jint value) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaFormat.method_setInteger, name, value); } void J4AC_android_media_MediaFormat__setInteger__catchAll(JNIEnv *env, jobject thiz, jstring name, jint value) { J4AC_android_media_MediaFormat__setInteger(env, thiz, name, value); J4A_ExceptionCheck__catchAll(env); } void J4AC_android_media_MediaFormat__setInteger__withCString(JNIEnv *env, jobject thiz, const char *name_cstr__, jint value) { jstring name = NULL; name = (*env)->NewStringUTF(env, name_cstr__); if (J4A_ExceptionCheck__throwAny(env) || !name) goto fail; J4AC_android_media_MediaFormat__setInteger(env, thiz, name, value); fail: J4A_DeleteLocalRef__p(env, &name); } void J4AC_android_media_MediaFormat__setInteger__withCString__catchAll(JNIEnv *env, jobject thiz, const char *name_cstr__, jint value) { jstring name = NULL; name = (*env)->NewStringUTF(env, name_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !name) goto fail; J4AC_android_media_MediaFormat__setInteger__catchAll(env, thiz, name, value); fail: J4A_DeleteLocalRef__p(env, &name); } void J4AC_android_media_MediaFormat__setByteBuffer(JNIEnv *env, jobject thiz, jstring name, jobject bytes) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_media_MediaFormat.method_setByteBuffer, name, bytes); } void J4AC_android_media_MediaFormat__setByteBuffer__catchAll(JNIEnv *env, jobject thiz, jstring name, jobject bytes) { J4AC_android_media_MediaFormat__setByteBuffer(env, thiz, name, bytes); J4A_ExceptionCheck__catchAll(env); } void J4AC_android_media_MediaFormat__setByteBuffer__withCString(JNIEnv *env, jobject thiz, const char *name_cstr__, jobject bytes) { jstring name = NULL; name = (*env)->NewStringUTF(env, name_cstr__); if (J4A_ExceptionCheck__throwAny(env) || !name) goto fail; J4AC_android_media_MediaFormat__setByteBuffer(env, thiz, name, bytes); fail: J4A_DeleteLocalRef__p(env, &name); } void J4AC_android_media_MediaFormat__setByteBuffer__withCString__catchAll(JNIEnv *env, jobject thiz, const char *name_cstr__, jobject bytes) { jstring name = NULL; name = (*env)->NewStringUTF(env, name_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !name) goto fail; J4AC_android_media_MediaFormat__setByteBuffer__catchAll(env, thiz, name, bytes); fail: J4A_DeleteLocalRef__p(env, &name); } int J4A_loadClass__J4AC_android_media_MediaFormat(JNIEnv *env) { int ret = -1; const char *J4A_UNUSED(name) = NULL; const char *J4A_UNUSED(sign) = NULL; jclass J4A_UNUSED(class_id) = NULL; int J4A_UNUSED(api_level) = 0; if (class_J4AC_android_media_MediaFormat.id != NULL) return 0; api_level = J4A_GetSystemAndroidApiLevel(env); if (api_level < 16) { J4A_ALOGW("J4ALoader: Ignore: '%s' need API %d\n", "android.media.MediaFormat", api_level); goto ignore; } sign = "android/media/MediaFormat"; class_J4AC_android_media_MediaFormat.id = J4A_FindClass__asGlobalRef__catchAll(env, sign); if (class_J4AC_android_media_MediaFormat.id == NULL) goto fail; class_id = class_J4AC_android_media_MediaFormat.id; name = ""; sign = "()V"; class_J4AC_android_media_MediaFormat.constructor_MediaFormat = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaFormat.constructor_MediaFormat == NULL) goto fail; class_id = class_J4AC_android_media_MediaFormat.id; name = "createVideoFormat"; sign = "(Ljava/lang/String;II)Landroid/media/MediaFormat;"; class_J4AC_android_media_MediaFormat.method_createVideoFormat = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaFormat.method_createVideoFormat == NULL) goto fail; class_id = class_J4AC_android_media_MediaFormat.id; name = "getInteger"; sign = "(Ljava/lang/String;)I"; class_J4AC_android_media_MediaFormat.method_getInteger = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaFormat.method_getInteger == NULL) goto fail; class_id = class_J4AC_android_media_MediaFormat.id; name = "setInteger"; sign = "(Ljava/lang/String;I)V"; class_J4AC_android_media_MediaFormat.method_setInteger = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaFormat.method_setInteger == NULL) goto fail; class_id = class_J4AC_android_media_MediaFormat.id; name = "setByteBuffer"; sign = "(Ljava/lang/String;Ljava/nio/ByteBuffer;)V"; class_J4AC_android_media_MediaFormat.method_setByteBuffer = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_MediaFormat.method_setByteBuffer == NULL) goto fail; J4A_ALOGD("J4ALoader: OK: '%s' loaded\n", "android.media.MediaFormat"); ignore: ret = 0; fail: return ret; } ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/media/MediaFormat.h ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #ifndef J4A__android_media_MediaFormat__H #define J4A__android_media_MediaFormat__H #include "j4a/j4a_base.h" jobject J4AC_android_media_MediaFormat__MediaFormat(JNIEnv *env); jobject J4AC_android_media_MediaFormat__MediaFormat__catchAll(JNIEnv *env); jobject J4AC_android_media_MediaFormat__MediaFormat__asGlobalRef__catchAll(JNIEnv *env); jobject J4AC_android_media_MediaFormat__createVideoFormat(JNIEnv *env, jstring mime, jint width, jint height); jobject J4AC_android_media_MediaFormat__createVideoFormat__catchAll(JNIEnv *env, jstring mime, jint width, jint height); jobject J4AC_android_media_MediaFormat__createVideoFormat__asGlobalRef__catchAll(JNIEnv *env, jstring mime, jint width, jint height); jobject J4AC_android_media_MediaFormat__createVideoFormat__withCString(JNIEnv *env, const char *mime_cstr__, jint width, jint height); jobject J4AC_android_media_MediaFormat__createVideoFormat__withCString__catchAll(JNIEnv *env, const char *mime_cstr__, jint width, jint height); jobject J4AC_android_media_MediaFormat__createVideoFormat__withCString__asGlobalRef__catchAll(JNIEnv *env, const char *mime_cstr__, jint width, jint height); jint J4AC_android_media_MediaFormat__getInteger(JNIEnv *env, jobject thiz, jstring name); jint J4AC_android_media_MediaFormat__getInteger__catchAll(JNIEnv *env, jobject thiz, jstring name); jint J4AC_android_media_MediaFormat__getInteger__withCString(JNIEnv *env, jobject thiz, const char *name_cstr__); jint J4AC_android_media_MediaFormat__getInteger__withCString__catchAll(JNIEnv *env, jobject thiz, const char *name_cstr__); void J4AC_android_media_MediaFormat__setInteger(JNIEnv *env, jobject thiz, jstring name, jint value); void J4AC_android_media_MediaFormat__setInteger__catchAll(JNIEnv *env, jobject thiz, jstring name, jint value); void J4AC_android_media_MediaFormat__setInteger__withCString(JNIEnv *env, jobject thiz, const char *name_cstr__, jint value); void J4AC_android_media_MediaFormat__setInteger__withCString__catchAll(JNIEnv *env, jobject thiz, const char *name_cstr__, jint value); void J4AC_android_media_MediaFormat__setByteBuffer(JNIEnv *env, jobject thiz, jstring name, jobject bytes); void J4AC_android_media_MediaFormat__setByteBuffer__catchAll(JNIEnv *env, jobject thiz, jstring name, jobject bytes); void J4AC_android_media_MediaFormat__setByteBuffer__withCString(JNIEnv *env, jobject thiz, const char *name_cstr__, jobject bytes); void J4AC_android_media_MediaFormat__setByteBuffer__withCString__catchAll(JNIEnv *env, jobject thiz, const char *name_cstr__, jobject bytes); int J4A_loadClass__J4AC_android_media_MediaFormat(JNIEnv *env); #define J4A_HAVE_SIMPLE__J4AC_android_media_MediaFormat #define J4AC_MediaFormat__MediaFormat J4AC_android_media_MediaFormat__MediaFormat #define J4AC_MediaFormat__MediaFormat__asGlobalRef__catchAll J4AC_android_media_MediaFormat__MediaFormat__asGlobalRef__catchAll #define J4AC_MediaFormat__MediaFormat__catchAll J4AC_android_media_MediaFormat__MediaFormat__catchAll #define J4AC_MediaFormat__createVideoFormat J4AC_android_media_MediaFormat__createVideoFormat #define J4AC_MediaFormat__createVideoFormat__asGlobalRef__catchAll J4AC_android_media_MediaFormat__createVideoFormat__asGlobalRef__catchAll #define J4AC_MediaFormat__createVideoFormat__catchAll J4AC_android_media_MediaFormat__createVideoFormat__catchAll #define J4AC_MediaFormat__createVideoFormat__withCString J4AC_android_media_MediaFormat__createVideoFormat__withCString #define J4AC_MediaFormat__createVideoFormat__withCString__asGlobalRef__catchAll J4AC_android_media_MediaFormat__createVideoFormat__withCString__asGlobalRef__catchAll #define J4AC_MediaFormat__createVideoFormat__withCString__catchAll J4AC_android_media_MediaFormat__createVideoFormat__withCString__catchAll #define J4AC_MediaFormat__getInteger J4AC_android_media_MediaFormat__getInteger #define J4AC_MediaFormat__getInteger__catchAll J4AC_android_media_MediaFormat__getInteger__catchAll #define J4AC_MediaFormat__getInteger__withCString J4AC_android_media_MediaFormat__getInteger__withCString #define J4AC_MediaFormat__getInteger__withCString__catchAll J4AC_android_media_MediaFormat__getInteger__withCString__catchAll #define J4AC_MediaFormat__setInteger J4AC_android_media_MediaFormat__setInteger #define J4AC_MediaFormat__setInteger__catchAll J4AC_android_media_MediaFormat__setInteger__catchAll #define J4AC_MediaFormat__setInteger__withCString J4AC_android_media_MediaFormat__setInteger__withCString #define J4AC_MediaFormat__setInteger__withCString__catchAll J4AC_android_media_MediaFormat__setInteger__withCString__catchAll #define J4AC_MediaFormat__setByteBuffer J4AC_android_media_MediaFormat__setByteBuffer #define J4AC_MediaFormat__setByteBuffer__catchAll J4AC_android_media_MediaFormat__setByteBuffer__catchAll #define J4AC_MediaFormat__setByteBuffer__withCString J4AC_android_media_MediaFormat__setByteBuffer__withCString #define J4AC_MediaFormat__setByteBuffer__withCString__catchAll J4AC_android_media_MediaFormat__setByteBuffer__withCString__catchAll #define J4A_loadClass__J4AC_MediaFormat J4A_loadClass__J4AC_android_media_MediaFormat #endif//J4A__android_media_MediaFormat__H ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/media/MediaFormat.include.j4a ================================================ #include "j4a/class/android/media/MediaFormat.h" ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/media/MediaFormat.loader.j4a ================================================ J4A_LOAD_CLASS(android_media_MediaFormat); ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/media/PlaybackParams.c ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #include "PlaybackParams.h" typedef struct J4AC_android_media_PlaybackParams { jclass id; jmethodID method_setSpeed; } J4AC_android_media_PlaybackParams; static J4AC_android_media_PlaybackParams class_J4AC_android_media_PlaybackParams; jobject J4AC_android_media_PlaybackParams__setSpeed(JNIEnv *env, jobject thiz, jfloat speed) { return (*env)->CallObjectMethod(env, thiz, class_J4AC_android_media_PlaybackParams.method_setSpeed, speed); } jobject J4AC_android_media_PlaybackParams__setSpeed__catchAll(JNIEnv *env, jobject thiz, jfloat speed) { jobject ret_object = J4AC_android_media_PlaybackParams__setSpeed(env, thiz, speed); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { return NULL; } return ret_object; } jobject J4AC_android_media_PlaybackParams__setSpeed__asGlobalRef__catchAll(JNIEnv *env, jobject thiz, jfloat speed) { jobject ret_object = NULL; jobject local_object = J4AC_android_media_PlaybackParams__setSpeed__catchAll(env, thiz, speed); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } int J4A_loadClass__J4AC_android_media_PlaybackParams(JNIEnv *env) { int ret = -1; const char *J4A_UNUSED(name) = NULL; const char *J4A_UNUSED(sign) = NULL; jclass J4A_UNUSED(class_id) = NULL; int J4A_UNUSED(api_level) = 0; if (class_J4AC_android_media_PlaybackParams.id != NULL) return 0; api_level = J4A_GetSystemAndroidApiLevel(env); if (api_level < 23) { J4A_ALOGW("J4ALoader: Ignore: '%s' need API %d\n", "android.media.PlaybackParams", api_level); goto ignore; } sign = "android/media/PlaybackParams"; class_J4AC_android_media_PlaybackParams.id = J4A_FindClass__asGlobalRef__catchAll(env, sign); if (class_J4AC_android_media_PlaybackParams.id == NULL) goto fail; class_id = class_J4AC_android_media_PlaybackParams.id; name = "setSpeed"; sign = "(F)Landroid/media/PlaybackParams;"; class_J4AC_android_media_PlaybackParams.method_setSpeed = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_media_PlaybackParams.method_setSpeed == NULL) goto fail; J4A_ALOGD("J4ALoader: OK: '%s' loaded\n", "android.media.PlaybackParams"); ignore: ret = 0; fail: return ret; } ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/media/PlaybackParams.h ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #ifndef J4A__android_media_PlaybackParams__H #define J4A__android_media_PlaybackParams__H #include "j4a/j4a_base.h" jobject J4AC_android_media_PlaybackParams__setSpeed(JNIEnv *env, jobject thiz, jfloat speed); jobject J4AC_android_media_PlaybackParams__setSpeed__catchAll(JNIEnv *env, jobject thiz, jfloat speed); jobject J4AC_android_media_PlaybackParams__setSpeed__asGlobalRef__catchAll(JNIEnv *env, jobject thiz, jfloat speed); int J4A_loadClass__J4AC_android_media_PlaybackParams(JNIEnv *env); #define J4A_HAVE_SIMPLE__J4AC_android_media_PlaybackParams #define J4AC_PlaybackParams__setSpeed J4AC_android_media_PlaybackParams__setSpeed #define J4AC_PlaybackParams__setSpeed__asGlobalRef__catchAll J4AC_android_media_PlaybackParams__setSpeed__asGlobalRef__catchAll #define J4AC_PlaybackParams__setSpeed__catchAll J4AC_android_media_PlaybackParams__setSpeed__catchAll #define J4A_loadClass__J4AC_PlaybackParams J4A_loadClass__J4AC_android_media_PlaybackParams #endif//J4A__android_media_PlaybackParams__H ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/media/PlaybackParams.include.j4a ================================================ #include "j4a/class/android/media/PlaybackParams.h" ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/media/PlaybackParams.loader.j4a ================================================ J4A_LOAD_CLASS(android_media_PlaybackParams); ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/os/Build.c ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #include "Build.h" typedef struct J4AC_android_os_Build__VERSION { jclass id; jfieldID field_SDK_INT; } J4AC_android_os_Build__VERSION; static J4AC_android_os_Build__VERSION class_J4AC_android_os_Build__VERSION; typedef struct J4AC_android_os_Build { jclass id; } J4AC_android_os_Build; static J4AC_android_os_Build class_J4AC_android_os_Build; jint J4AC_android_os_Build__VERSION__SDK_INT__get(JNIEnv *env) { return (*env)->GetStaticIntField(env, class_J4AC_android_os_Build__VERSION.id, class_J4AC_android_os_Build__VERSION.field_SDK_INT); } jint J4AC_android_os_Build__VERSION__SDK_INT__get__catchAll(JNIEnv *env) { jint ret_value = J4AC_android_os_Build__VERSION__SDK_INT__get(env); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } void J4AC_android_os_Build__VERSION__SDK_INT__set(JNIEnv *env, jint value) { (*env)->SetStaticIntField(env, class_J4AC_android_os_Build__VERSION.id, class_J4AC_android_os_Build__VERSION.field_SDK_INT, value); } void J4AC_android_os_Build__VERSION__SDK_INT__set__catchAll(JNIEnv *env, jint value) { J4AC_android_os_Build__VERSION__SDK_INT__set(env, value); J4A_ExceptionCheck__catchAll(env); } int J4A_loadClass__J4AC_android_os_Build__VERSION(JNIEnv *env) { int ret = -1; const char *J4A_UNUSED(name) = NULL; const char *J4A_UNUSED(sign) = NULL; jclass J4A_UNUSED(class_id) = NULL; int J4A_UNUSED(api_level) = 0; if (class_J4AC_android_os_Build__VERSION.id != NULL) return 0; sign = "android/os/Build$VERSION"; class_J4AC_android_os_Build__VERSION.id = J4A_FindClass__asGlobalRef__catchAll(env, sign); if (class_J4AC_android_os_Build__VERSION.id == NULL) goto fail; class_id = class_J4AC_android_os_Build__VERSION.id; name = "SDK_INT"; sign = "I"; class_J4AC_android_os_Build__VERSION.field_SDK_INT = J4A_GetStaticFieldID__catchAll(env, class_id, name, sign); if (class_J4AC_android_os_Build__VERSION.field_SDK_INT == NULL) goto fail; J4A_ALOGD("J4ALoader: OK: '%s' loaded\n", "android.os.Build$VERSION"); ret = 0; fail: return ret; } int J4A_loadClass__J4AC_android_os_Build(JNIEnv *env) { int ret = -1; const char *J4A_UNUSED(name) = NULL; const char *J4A_UNUSED(sign) = NULL; jclass J4A_UNUSED(class_id) = NULL; int J4A_UNUSED(api_level) = 0; if (class_J4AC_android_os_Build.id != NULL) return 0; sign = "android/os/Build"; class_J4AC_android_os_Build.id = J4A_FindClass__asGlobalRef__catchAll(env, sign); if (class_J4AC_android_os_Build.id == NULL) goto fail; ret = J4A_loadClass__J4AC_android_os_Build__VERSION(env); if (ret) goto fail; J4A_ALOGD("J4ALoader: OK: '%s' loaded\n", "android.os.Build"); ret = 0; fail: return ret; } ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/os/Build.h ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #ifndef J4A__android_os_Build__H #define J4A__android_os_Build__H #include "j4a/j4a_base.h" jint J4AC_android_os_Build__VERSION__SDK_INT__get(JNIEnv *env); jint J4AC_android_os_Build__VERSION__SDK_INT__get__catchAll(JNIEnv *env); void J4AC_android_os_Build__VERSION__SDK_INT__set(JNIEnv *env, jint value); void J4AC_android_os_Build__VERSION__SDK_INT__set__catchAll(JNIEnv *env, jint value); int J4A_loadClass__J4AC_android_os_Build(JNIEnv *env); #endif//J4A__android_os_Build__H ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/os/Build.include.j4a ================================================ #include "j4a/class/android/os/Build.h" ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/os/Build.loader.j4a ================================================ J4A_LOAD_CLASS(android_os_Build); ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/os/Bundle.c ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #include "Bundle.h" typedef struct J4AC_android_os_Bundle { jclass id; jmethodID constructor_Bundle; jmethodID method_getInt; jmethodID method_putInt; jmethodID method_getString; jmethodID method_putString; jmethodID method_putParcelableArrayList; jmethodID method_getLong; jmethodID method_putLong; } J4AC_android_os_Bundle; static J4AC_android_os_Bundle class_J4AC_android_os_Bundle; jobject J4AC_android_os_Bundle__Bundle(JNIEnv *env) { return (*env)->NewObject(env, class_J4AC_android_os_Bundle.id, class_J4AC_android_os_Bundle.constructor_Bundle); } jobject J4AC_android_os_Bundle__Bundle__catchAll(JNIEnv *env) { jobject ret_object = J4AC_android_os_Bundle__Bundle(env); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { return NULL; } return ret_object; } jobject J4AC_android_os_Bundle__Bundle__asGlobalRef__catchAll(JNIEnv *env) { jobject ret_object = NULL; jobject local_object = J4AC_android_os_Bundle__Bundle__catchAll(env); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } jint J4AC_android_os_Bundle__getInt(JNIEnv *env, jobject thiz, jstring key, jint defaultValue) { return (*env)->CallIntMethod(env, thiz, class_J4AC_android_os_Bundle.method_getInt, key, defaultValue); } jint J4AC_android_os_Bundle__getInt__catchAll(JNIEnv *env, jobject thiz, jstring key, jint defaultValue) { jint ret_value = J4AC_android_os_Bundle__getInt(env, thiz, key, defaultValue); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } jint J4AC_android_os_Bundle__getInt__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, jint defaultValue) { jint ret_value = 0; jstring key = NULL; key = (*env)->NewStringUTF(env, key_cstr__); if (J4A_ExceptionCheck__throwAny(env) || !key) goto fail; ret_value = J4AC_android_os_Bundle__getInt(env, thiz, key, defaultValue); if (J4A_ExceptionCheck__throwAny(env)) { ret_value = 0; goto fail; } fail: J4A_DeleteLocalRef__p(env, &key); return ret_value; } jint J4AC_android_os_Bundle__getInt__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, jint defaultValue) { jint ret_value = 0; jstring key = NULL; key = (*env)->NewStringUTF(env, key_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !key) goto fail; ret_value = J4AC_android_os_Bundle__getInt__catchAll(env, thiz, key, defaultValue); if (J4A_ExceptionCheck__catchAll(env)) { ret_value = 0; goto fail; } fail: J4A_DeleteLocalRef__p(env, &key); return ret_value; } void J4AC_android_os_Bundle__putInt(JNIEnv *env, jobject thiz, jstring key, jint value) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_os_Bundle.method_putInt, key, value); } void J4AC_android_os_Bundle__putInt__catchAll(JNIEnv *env, jobject thiz, jstring key, jint value) { J4AC_android_os_Bundle__putInt(env, thiz, key, value); J4A_ExceptionCheck__catchAll(env); } void J4AC_android_os_Bundle__putInt__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, jint value) { jstring key = NULL; key = (*env)->NewStringUTF(env, key_cstr__); if (J4A_ExceptionCheck__throwAny(env) || !key) goto fail; J4AC_android_os_Bundle__putInt(env, thiz, key, value); fail: J4A_DeleteLocalRef__p(env, &key); } void J4AC_android_os_Bundle__putInt__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, jint value) { jstring key = NULL; key = (*env)->NewStringUTF(env, key_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !key) goto fail; J4AC_android_os_Bundle__putInt__catchAll(env, thiz, key, value); fail: J4A_DeleteLocalRef__p(env, &key); } jstring J4AC_android_os_Bundle__getString(JNIEnv *env, jobject thiz, jstring key) { return (*env)->CallObjectMethod(env, thiz, class_J4AC_android_os_Bundle.method_getString, key); } jstring J4AC_android_os_Bundle__getString__catchAll(JNIEnv *env, jobject thiz, jstring key) { jstring ret_object = J4AC_android_os_Bundle__getString(env, thiz, key); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { return NULL; } return ret_object; } jstring J4AC_android_os_Bundle__getString__asGlobalRef__catchAll(JNIEnv *env, jobject thiz, jstring key) { jstring ret_object = NULL; jstring local_object = J4AC_android_os_Bundle__getString__catchAll(env, thiz, key); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } const char *J4AC_android_os_Bundle__getString__asCBuffer(JNIEnv *env, jobject thiz, jstring key, char *out_buf, int out_len) { const char *ret_value = NULL; const char *c_str = NULL; jstring local_string = J4AC_android_os_Bundle__getString(env, thiz, key); if (J4A_ExceptionCheck__throwAny(env) || !local_string) { goto fail; } c_str = (*env)->GetStringUTFChars(env, local_string, NULL ); if (J4A_ExceptionCheck__throwAny(env) || !c_str) { goto fail; } strlcpy(out_buf, c_str, out_len); ret_value = out_buf; fail: J4A_ReleaseStringUTFChars__p(env, local_string, &c_str); J4A_DeleteLocalRef__p(env, &local_string); return ret_value; } const char *J4AC_android_os_Bundle__getString__asCBuffer__catchAll(JNIEnv *env, jobject thiz, jstring key, char *out_buf, int out_len) { const char *ret_value = NULL; const char *c_str = NULL; jstring local_string = J4AC_android_os_Bundle__getString__catchAll(env, thiz, key); if (J4A_ExceptionCheck__catchAll(env) || !local_string) { goto fail; } c_str = (*env)->GetStringUTFChars(env, local_string, NULL ); if (J4A_ExceptionCheck__catchAll(env) || !c_str) { goto fail; } strlcpy(out_buf, c_str, out_len); ret_value = out_buf; fail: J4A_ReleaseStringUTFChars__p(env, local_string, &c_str); J4A_DeleteLocalRef__p(env, &local_string); return ret_value; } jstring J4AC_android_os_Bundle__getString__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__) { jstring ret_object = NULL; jstring key = NULL; key = (*env)->NewStringUTF(env, key_cstr__); if (J4A_ExceptionCheck__throwAny(env) || !key) goto fail; ret_object = J4AC_android_os_Bundle__getString(env, thiz, key); if (J4A_ExceptionCheck__throwAny(env) || !ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &key); return ret_object; } jstring J4AC_android_os_Bundle__getString__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__) { jstring ret_object = NULL; jstring key = NULL; key = (*env)->NewStringUTF(env, key_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !key) goto fail; ret_object = J4AC_android_os_Bundle__getString__catchAll(env, thiz, key); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &key); return ret_object; } jstring J4AC_android_os_Bundle__getString__withCString__asGlobalRef__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__) { jstring ret_object = NULL; jstring local_object = J4AC_android_os_Bundle__getString__withCString__catchAll(env, thiz, key_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } const char *J4AC_android_os_Bundle__getString__withCString__asCBuffer(JNIEnv *env, jobject thiz, const char *key_cstr__, char *out_buf, int out_len) { const char *ret_value = NULL; const char *c_str = NULL; jstring local_string = J4AC_android_os_Bundle__getString__withCString(env, thiz, key_cstr__); if (J4A_ExceptionCheck__throwAny(env) || !local_string) { goto fail; } c_str = (*env)->GetStringUTFChars(env, local_string, NULL ); if (J4A_ExceptionCheck__throwAny(env) || !c_str) { goto fail; } strlcpy(out_buf, c_str, out_len); ret_value = out_buf; fail: J4A_ReleaseStringUTFChars__p(env, local_string, &c_str); J4A_DeleteLocalRef__p(env, &local_string); return ret_value; } const char *J4AC_android_os_Bundle__getString__withCString__asCBuffer__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, char *out_buf, int out_len) { const char *ret_value = NULL; const char *c_str = NULL; jstring local_string = J4AC_android_os_Bundle__getString__withCString__catchAll(env, thiz, key_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !local_string) { goto fail; } c_str = (*env)->GetStringUTFChars(env, local_string, NULL ); if (J4A_ExceptionCheck__catchAll(env) || !c_str) { goto fail; } strlcpy(out_buf, c_str, out_len); ret_value = out_buf; fail: J4A_ReleaseStringUTFChars__p(env, local_string, &c_str); J4A_DeleteLocalRef__p(env, &local_string); return ret_value; } void J4AC_android_os_Bundle__putString(JNIEnv *env, jobject thiz, jstring key, jstring value) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_os_Bundle.method_putString, key, value); } void J4AC_android_os_Bundle__putString__catchAll(JNIEnv *env, jobject thiz, jstring key, jstring value) { J4AC_android_os_Bundle__putString(env, thiz, key, value); J4A_ExceptionCheck__catchAll(env); } void J4AC_android_os_Bundle__putString__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, const char *value_cstr__) { jstring key = NULL; jstring value = NULL; key = (*env)->NewStringUTF(env, key_cstr__); if (J4A_ExceptionCheck__throwAny(env) || !key) goto fail; value = (*env)->NewStringUTF(env, value_cstr__); if (J4A_ExceptionCheck__throwAny(env) || !value) goto fail; J4AC_android_os_Bundle__putString(env, thiz, key, value); fail: J4A_DeleteLocalRef__p(env, &key); J4A_DeleteLocalRef__p(env, &value); } void J4AC_android_os_Bundle__putString__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, const char *value_cstr__) { jstring key = NULL; jstring value = NULL; key = (*env)->NewStringUTF(env, key_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !key) goto fail; value = (*env)->NewStringUTF(env, value_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !value) goto fail; J4AC_android_os_Bundle__putString__catchAll(env, thiz, key, value); fail: J4A_DeleteLocalRef__p(env, &key); J4A_DeleteLocalRef__p(env, &value); } void J4AC_android_os_Bundle__putParcelableArrayList(JNIEnv *env, jobject thiz, jstring key, jobject value) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_os_Bundle.method_putParcelableArrayList, key, value); } void J4AC_android_os_Bundle__putParcelableArrayList__catchAll(JNIEnv *env, jobject thiz, jstring key, jobject value) { J4AC_android_os_Bundle__putParcelableArrayList(env, thiz, key, value); J4A_ExceptionCheck__catchAll(env); } void J4AC_android_os_Bundle__putParcelableArrayList__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, jobject value) { jstring key = NULL; key = (*env)->NewStringUTF(env, key_cstr__); if (J4A_ExceptionCheck__throwAny(env) || !key) goto fail; J4AC_android_os_Bundle__putParcelableArrayList(env, thiz, key, value); fail: J4A_DeleteLocalRef__p(env, &key); } void J4AC_android_os_Bundle__putParcelableArrayList__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, jobject value) { jstring key = NULL; key = (*env)->NewStringUTF(env, key_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !key) goto fail; J4AC_android_os_Bundle__putParcelableArrayList__catchAll(env, thiz, key, value); fail: J4A_DeleteLocalRef__p(env, &key); } jlong J4AC_android_os_Bundle__getLong(JNIEnv *env, jobject thiz, jstring key) { return (*env)->CallLongMethod(env, thiz, class_J4AC_android_os_Bundle.method_getLong, key); } jlong J4AC_android_os_Bundle__getLong__catchAll(JNIEnv *env, jobject thiz, jstring key) { jlong ret_value = J4AC_android_os_Bundle__getLong(env, thiz, key); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } jlong J4AC_android_os_Bundle__getLong__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__) { jlong ret_value = 0; jstring key = NULL; key = (*env)->NewStringUTF(env, key_cstr__); if (J4A_ExceptionCheck__throwAny(env) || !key) goto fail; ret_value = J4AC_android_os_Bundle__getLong(env, thiz, key); if (J4A_ExceptionCheck__throwAny(env)) { ret_value = 0; goto fail; } fail: J4A_DeleteLocalRef__p(env, &key); return ret_value; } jlong J4AC_android_os_Bundle__getLong__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__) { jlong ret_value = 0; jstring key = NULL; key = (*env)->NewStringUTF(env, key_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !key) goto fail; ret_value = J4AC_android_os_Bundle__getLong__catchAll(env, thiz, key); if (J4A_ExceptionCheck__catchAll(env)) { ret_value = 0; goto fail; } fail: J4A_DeleteLocalRef__p(env, &key); return ret_value; } void J4AC_android_os_Bundle__putLong(JNIEnv *env, jobject thiz, jstring key, jlong value) { (*env)->CallVoidMethod(env, thiz, class_J4AC_android_os_Bundle.method_putLong, key, value); } void J4AC_android_os_Bundle__putLong__catchAll(JNIEnv *env, jobject thiz, jstring key, jlong value) { J4AC_android_os_Bundle__putLong(env, thiz, key, value); J4A_ExceptionCheck__catchAll(env); } void J4AC_android_os_Bundle__putLong__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, jlong value) { jstring key = NULL; key = (*env)->NewStringUTF(env, key_cstr__); if (J4A_ExceptionCheck__throwAny(env) || !key) goto fail; J4AC_android_os_Bundle__putLong(env, thiz, key, value); fail: J4A_DeleteLocalRef__p(env, &key); } void J4AC_android_os_Bundle__putLong__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, jlong value) { jstring key = NULL; key = (*env)->NewStringUTF(env, key_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !key) goto fail; J4AC_android_os_Bundle__putLong__catchAll(env, thiz, key, value); fail: J4A_DeleteLocalRef__p(env, &key); } int J4A_loadClass__J4AC_android_os_Bundle(JNIEnv *env) { int ret = -1; const char *J4A_UNUSED(name) = NULL; const char *J4A_UNUSED(sign) = NULL; jclass J4A_UNUSED(class_id) = NULL; int J4A_UNUSED(api_level) = 0; if (class_J4AC_android_os_Bundle.id != NULL) return 0; sign = "android/os/Bundle"; class_J4AC_android_os_Bundle.id = J4A_FindClass__asGlobalRef__catchAll(env, sign); if (class_J4AC_android_os_Bundle.id == NULL) goto fail; class_id = class_J4AC_android_os_Bundle.id; name = ""; sign = "()V"; class_J4AC_android_os_Bundle.constructor_Bundle = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_os_Bundle.constructor_Bundle == NULL) goto fail; class_id = class_J4AC_android_os_Bundle.id; name = "getInt"; sign = "(Ljava/lang/String;I)I"; class_J4AC_android_os_Bundle.method_getInt = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_os_Bundle.method_getInt == NULL) goto fail; class_id = class_J4AC_android_os_Bundle.id; name = "putInt"; sign = "(Ljava/lang/String;I)V"; class_J4AC_android_os_Bundle.method_putInt = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_os_Bundle.method_putInt == NULL) goto fail; class_id = class_J4AC_android_os_Bundle.id; name = "getString"; sign = "(Ljava/lang/String;)Ljava/lang/String;"; class_J4AC_android_os_Bundle.method_getString = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_os_Bundle.method_getString == NULL) goto fail; class_id = class_J4AC_android_os_Bundle.id; name = "putString"; sign = "(Ljava/lang/String;Ljava/lang/String;)V"; class_J4AC_android_os_Bundle.method_putString = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_os_Bundle.method_putString == NULL) goto fail; class_id = class_J4AC_android_os_Bundle.id; name = "putParcelableArrayList"; sign = "(Ljava/lang/String;Ljava/util/ArrayList;)V"; class_J4AC_android_os_Bundle.method_putParcelableArrayList = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_os_Bundle.method_putParcelableArrayList == NULL) goto fail; class_id = class_J4AC_android_os_Bundle.id; name = "getLong"; sign = "(Ljava/lang/String;)J"; class_J4AC_android_os_Bundle.method_getLong = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_os_Bundle.method_getLong == NULL) goto fail; class_id = class_J4AC_android_os_Bundle.id; name = "putLong"; sign = "(Ljava/lang/String;J)V"; class_J4AC_android_os_Bundle.method_putLong = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_android_os_Bundle.method_putLong == NULL) goto fail; J4A_ALOGD("J4ALoader: OK: '%s' loaded\n", "android.os.Bundle"); ret = 0; fail: return ret; } ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/os/Bundle.h ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #ifndef J4A__android_os_Bundle__H #define J4A__android_os_Bundle__H #include "j4a/j4a_base.h" jobject J4AC_android_os_Bundle__Bundle(JNIEnv *env); jobject J4AC_android_os_Bundle__Bundle__catchAll(JNIEnv *env); jobject J4AC_android_os_Bundle__Bundle__asGlobalRef__catchAll(JNIEnv *env); jint J4AC_android_os_Bundle__getInt(JNIEnv *env, jobject thiz, jstring key, jint defaultValue); jint J4AC_android_os_Bundle__getInt__catchAll(JNIEnv *env, jobject thiz, jstring key, jint defaultValue); jint J4AC_android_os_Bundle__getInt__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, jint defaultValue); jint J4AC_android_os_Bundle__getInt__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, jint defaultValue); void J4AC_android_os_Bundle__putInt(JNIEnv *env, jobject thiz, jstring key, jint value); void J4AC_android_os_Bundle__putInt__catchAll(JNIEnv *env, jobject thiz, jstring key, jint value); void J4AC_android_os_Bundle__putInt__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, jint value); void J4AC_android_os_Bundle__putInt__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, jint value); jstring J4AC_android_os_Bundle__getString(JNIEnv *env, jobject thiz, jstring key); jstring J4AC_android_os_Bundle__getString__catchAll(JNIEnv *env, jobject thiz, jstring key); jstring J4AC_android_os_Bundle__getString__asGlobalRef__catchAll(JNIEnv *env, jobject thiz, jstring key); const char *J4AC_android_os_Bundle__getString__asCBuffer(JNIEnv *env, jobject thiz, jstring key, char *out_buf, int out_len); const char *J4AC_android_os_Bundle__getString__asCBuffer__catchAll(JNIEnv *env, jobject thiz, jstring key, char *out_buf, int out_len); jstring J4AC_android_os_Bundle__getString__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__); jstring J4AC_android_os_Bundle__getString__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__); jstring J4AC_android_os_Bundle__getString__withCString__asGlobalRef__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__); const char *J4AC_android_os_Bundle__getString__withCString__asCBuffer(JNIEnv *env, jobject thiz, const char *key_cstr__, char *out_buf, int out_len); const char *J4AC_android_os_Bundle__getString__withCString__asCBuffer__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, char *out_buf, int out_len); void J4AC_android_os_Bundle__putString(JNIEnv *env, jobject thiz, jstring key, jstring value); void J4AC_android_os_Bundle__putString__catchAll(JNIEnv *env, jobject thiz, jstring key, jstring value); void J4AC_android_os_Bundle__putString__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, const char *value_cstr__); void J4AC_android_os_Bundle__putString__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, const char *value_cstr__); void J4AC_android_os_Bundle__putParcelableArrayList(JNIEnv *env, jobject thiz, jstring key, jobject value); void J4AC_android_os_Bundle__putParcelableArrayList__catchAll(JNIEnv *env, jobject thiz, jstring key, jobject value); void J4AC_android_os_Bundle__putParcelableArrayList__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, jobject value); void J4AC_android_os_Bundle__putParcelableArrayList__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, jobject value); jlong J4AC_android_os_Bundle__getLong(JNIEnv *env, jobject thiz, jstring key); jlong J4AC_android_os_Bundle__getLong__catchAll(JNIEnv *env, jobject thiz, jstring key); jlong J4AC_android_os_Bundle__getLong__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__); jlong J4AC_android_os_Bundle__getLong__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__); void J4AC_android_os_Bundle__putLong(JNIEnv *env, jobject thiz, jstring key, jlong value); void J4AC_android_os_Bundle__putLong__catchAll(JNIEnv *env, jobject thiz, jstring key, jlong value); void J4AC_android_os_Bundle__putLong__withCString(JNIEnv *env, jobject thiz, const char *key_cstr__, jlong value); void J4AC_android_os_Bundle__putLong__withCString__catchAll(JNIEnv *env, jobject thiz, const char *key_cstr__, jlong value); int J4A_loadClass__J4AC_android_os_Bundle(JNIEnv *env); #define J4A_HAVE_SIMPLE__J4AC_android_os_Bundle #define J4AC_Bundle__Bundle J4AC_android_os_Bundle__Bundle #define J4AC_Bundle__Bundle__asGlobalRef__catchAll J4AC_android_os_Bundle__Bundle__asGlobalRef__catchAll #define J4AC_Bundle__Bundle__catchAll J4AC_android_os_Bundle__Bundle__catchAll #define J4AC_Bundle__getInt J4AC_android_os_Bundle__getInt #define J4AC_Bundle__getInt__catchAll J4AC_android_os_Bundle__getInt__catchAll #define J4AC_Bundle__getInt__withCString J4AC_android_os_Bundle__getInt__withCString #define J4AC_Bundle__getInt__withCString__catchAll J4AC_android_os_Bundle__getInt__withCString__catchAll #define J4AC_Bundle__putInt J4AC_android_os_Bundle__putInt #define J4AC_Bundle__putInt__catchAll J4AC_android_os_Bundle__putInt__catchAll #define J4AC_Bundle__putInt__withCString J4AC_android_os_Bundle__putInt__withCString #define J4AC_Bundle__putInt__withCString__catchAll J4AC_android_os_Bundle__putInt__withCString__catchAll #define J4AC_Bundle__getString J4AC_android_os_Bundle__getString #define J4AC_Bundle__getString__asCBuffer J4AC_android_os_Bundle__getString__asCBuffer #define J4AC_Bundle__getString__asCBuffer__catchAll J4AC_android_os_Bundle__getString__asCBuffer__catchAll #define J4AC_Bundle__getString__asGlobalRef__catchAll J4AC_android_os_Bundle__getString__asGlobalRef__catchAll #define J4AC_Bundle__getString__catchAll J4AC_android_os_Bundle__getString__catchAll #define J4AC_Bundle__getString__withCString J4AC_android_os_Bundle__getString__withCString #define J4AC_Bundle__getString__withCString__asCBuffer J4AC_android_os_Bundle__getString__withCString__asCBuffer #define J4AC_Bundle__getString__withCString__asCBuffer__catchAll J4AC_android_os_Bundle__getString__withCString__asCBuffer__catchAll #define J4AC_Bundle__getString__withCString__asGlobalRef__catchAll J4AC_android_os_Bundle__getString__withCString__asGlobalRef__catchAll #define J4AC_Bundle__getString__withCString__catchAll J4AC_android_os_Bundle__getString__withCString__catchAll #define J4AC_Bundle__putString J4AC_android_os_Bundle__putString #define J4AC_Bundle__putString__catchAll J4AC_android_os_Bundle__putString__catchAll #define J4AC_Bundle__putString__withCString J4AC_android_os_Bundle__putString__withCString #define J4AC_Bundle__putString__withCString__catchAll J4AC_android_os_Bundle__putString__withCString__catchAll #define J4AC_Bundle__putParcelableArrayList J4AC_android_os_Bundle__putParcelableArrayList #define J4AC_Bundle__putParcelableArrayList__catchAll J4AC_android_os_Bundle__putParcelableArrayList__catchAll #define J4AC_Bundle__putParcelableArrayList__withCString J4AC_android_os_Bundle__putParcelableArrayList__withCString #define J4AC_Bundle__putParcelableArrayList__withCString__catchAll J4AC_android_os_Bundle__putParcelableArrayList__withCString__catchAll #define J4AC_Bundle__getLong J4AC_android_os_Bundle__getLong #define J4AC_Bundle__getLong__catchAll J4AC_android_os_Bundle__getLong__catchAll #define J4AC_Bundle__getLong__withCString J4AC_android_os_Bundle__getLong__withCString #define J4AC_Bundle__getLong__withCString__catchAll J4AC_android_os_Bundle__getLong__withCString__catchAll #define J4AC_Bundle__putLong J4AC_android_os_Bundle__putLong #define J4AC_Bundle__putLong__catchAll J4AC_android_os_Bundle__putLong__catchAll #define J4AC_Bundle__putLong__withCString J4AC_android_os_Bundle__putLong__withCString #define J4AC_Bundle__putLong__withCString__catchAll J4AC_android_os_Bundle__putLong__withCString__catchAll #define J4A_loadClass__J4AC_Bundle J4A_loadClass__J4AC_android_os_Bundle #endif//J4A__android_os_Bundle__H ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/os/Bundle.include.j4a ================================================ #include "j4a/class/android/os/Bundle.h" ================================================ FILE: ijkmedia/ijkj4a/j4a/class/android/os/Bundle.loader.j4a ================================================ J4A_LOAD_CLASS(android_os_Bundle); ================================================ FILE: ijkmedia/ijkj4a/j4a/class/java/nio/Buffer.c ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #include "Buffer.h" typedef struct J4AC_java_nio_Buffer { jclass id; } J4AC_java_nio_Buffer; static J4AC_java_nio_Buffer class_J4AC_java_nio_Buffer; int J4A_loadClass__J4AC_java_nio_Buffer(JNIEnv *env) { int ret = -1; const char *J4A_UNUSED(name) = NULL; const char *J4A_UNUSED(sign) = NULL; jclass J4A_UNUSED(class_id) = NULL; int J4A_UNUSED(api_level) = 0; if (class_J4AC_java_nio_Buffer.id != NULL) return 0; sign = "java/nio/Buffer"; class_J4AC_java_nio_Buffer.id = J4A_FindClass__asGlobalRef__catchAll(env, sign); if (class_J4AC_java_nio_Buffer.id == NULL) goto fail; J4A_ALOGD("J4ALoader: OK: '%s' loaded\n", "java.nio.Buffer"); ret = 0; fail: return ret; } ================================================ FILE: ijkmedia/ijkj4a/j4a/class/java/nio/Buffer.h ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #ifndef J4A__java_nio_Buffer__H #define J4A__java_nio_Buffer__H #include "j4a/j4a_base.h" int J4A_loadClass__J4AC_java_nio_Buffer(JNIEnv *env); #endif//J4A__java_nio_Buffer__H ================================================ FILE: ijkmedia/ijkj4a/j4a/class/java/nio/Buffer.include.j4a ================================================ #include "j4a/class/java/nio/Buffer.h" ================================================ FILE: ijkmedia/ijkj4a/j4a/class/java/nio/Buffer.loader.j4a ================================================ J4A_LOAD_CLASS(java_nio_Buffer); ================================================ FILE: ijkmedia/ijkj4a/j4a/class/java/nio/ByteBuffer.c ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #include "ByteBuffer.h" typedef struct J4AC_java_nio_ByteBuffer { jclass id; jmethodID method_allocate; jmethodID method_allocateDirect; jmethodID method_limit; } J4AC_java_nio_ByteBuffer; static J4AC_java_nio_ByteBuffer class_J4AC_java_nio_ByteBuffer; jobject J4AC_java_nio_ByteBuffer__allocate(JNIEnv *env, jint capacity) { return (*env)->CallStaticObjectMethod(env, class_J4AC_java_nio_ByteBuffer.id, class_J4AC_java_nio_ByteBuffer.method_allocate, capacity); } jobject J4AC_java_nio_ByteBuffer__allocate__catchAll(JNIEnv *env, jint capacity) { jobject ret_object = J4AC_java_nio_ByteBuffer__allocate(env, capacity); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { return NULL; } return ret_object; } jobject J4AC_java_nio_ByteBuffer__allocate__asGlobalRef__catchAll(JNIEnv *env, jint capacity) { jobject ret_object = NULL; jobject local_object = J4AC_java_nio_ByteBuffer__allocate__catchAll(env, capacity); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } jobject J4AC_java_nio_ByteBuffer__allocateDirect(JNIEnv *env, jint capacity) { return (*env)->CallStaticObjectMethod(env, class_J4AC_java_nio_ByteBuffer.id, class_J4AC_java_nio_ByteBuffer.method_allocateDirect, capacity); } jobject J4AC_java_nio_ByteBuffer__allocateDirect__catchAll(JNIEnv *env, jint capacity) { jobject ret_object = J4AC_java_nio_ByteBuffer__allocateDirect(env, capacity); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { return NULL; } return ret_object; } jobject J4AC_java_nio_ByteBuffer__allocateDirect__asGlobalRef__catchAll(JNIEnv *env, jint capacity) { jobject ret_object = NULL; jobject local_object = J4AC_java_nio_ByteBuffer__allocateDirect__catchAll(env, capacity); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } jobject J4AC_java_nio_ByteBuffer__limit(JNIEnv *env, jobject thiz, jint newLimit) { return (*env)->CallObjectMethod(env, thiz, class_J4AC_java_nio_ByteBuffer.method_limit, newLimit); } jobject J4AC_java_nio_ByteBuffer__limit__catchAll(JNIEnv *env, jobject thiz, jint newLimit) { jobject ret_object = J4AC_java_nio_ByteBuffer__limit(env, thiz, newLimit); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { return NULL; } return ret_object; } jobject J4AC_java_nio_ByteBuffer__limit__asGlobalRef__catchAll(JNIEnv *env, jobject thiz, jint newLimit) { jobject ret_object = NULL; jobject local_object = J4AC_java_nio_ByteBuffer__limit__catchAll(env, thiz, newLimit); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } int J4A_loadClass__J4AC_java_nio_ByteBuffer(JNIEnv *env) { int ret = -1; const char *J4A_UNUSED(name) = NULL; const char *J4A_UNUSED(sign) = NULL; jclass J4A_UNUSED(class_id) = NULL; int J4A_UNUSED(api_level) = 0; if (class_J4AC_java_nio_ByteBuffer.id != NULL) return 0; sign = "java/nio/ByteBuffer"; class_J4AC_java_nio_ByteBuffer.id = J4A_FindClass__asGlobalRef__catchAll(env, sign); if (class_J4AC_java_nio_ByteBuffer.id == NULL) goto fail; class_id = class_J4AC_java_nio_ByteBuffer.id; name = "allocate"; sign = "(I)Ljava/nio/ByteBuffer;"; class_J4AC_java_nio_ByteBuffer.method_allocate = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_java_nio_ByteBuffer.method_allocate == NULL) goto fail; class_id = class_J4AC_java_nio_ByteBuffer.id; name = "allocateDirect"; sign = "(I)Ljava/nio/ByteBuffer;"; class_J4AC_java_nio_ByteBuffer.method_allocateDirect = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_java_nio_ByteBuffer.method_allocateDirect == NULL) goto fail; class_id = class_J4AC_java_nio_ByteBuffer.id; name = "limit"; sign = "(I)Ljava/nio/Buffer;"; class_J4AC_java_nio_ByteBuffer.method_limit = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_java_nio_ByteBuffer.method_limit == NULL) goto fail; J4A_ALOGD("J4ALoader: OK: '%s' loaded\n", "java.nio.ByteBuffer"); ret = 0; fail: return ret; } ================================================ FILE: ijkmedia/ijkj4a/j4a/class/java/nio/ByteBuffer.h ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #ifndef J4A__java_nio_ByteBuffer__H #define J4A__java_nio_ByteBuffer__H #include "j4a/j4a_base.h" jobject J4AC_java_nio_ByteBuffer__allocate(JNIEnv *env, jint capacity); jobject J4AC_java_nio_ByteBuffer__allocate__catchAll(JNIEnv *env, jint capacity); jobject J4AC_java_nio_ByteBuffer__allocate__asGlobalRef__catchAll(JNIEnv *env, jint capacity); jobject J4AC_java_nio_ByteBuffer__allocateDirect(JNIEnv *env, jint capacity); jobject J4AC_java_nio_ByteBuffer__allocateDirect__catchAll(JNIEnv *env, jint capacity); jobject J4AC_java_nio_ByteBuffer__allocateDirect__asGlobalRef__catchAll(JNIEnv *env, jint capacity); jobject J4AC_java_nio_ByteBuffer__limit(JNIEnv *env, jobject thiz, jint newLimit); jobject J4AC_java_nio_ByteBuffer__limit__catchAll(JNIEnv *env, jobject thiz, jint newLimit); jobject J4AC_java_nio_ByteBuffer__limit__asGlobalRef__catchAll(JNIEnv *env, jobject thiz, jint newLimit); int J4A_loadClass__J4AC_java_nio_ByteBuffer(JNIEnv *env); #define J4A_HAVE_SIMPLE__J4AC_java_nio_ByteBuffer #define J4AC_ByteBuffer__allocate J4AC_java_nio_ByteBuffer__allocate #define J4AC_ByteBuffer__allocate__asGlobalRef__catchAll J4AC_java_nio_ByteBuffer__allocate__asGlobalRef__catchAll #define J4AC_ByteBuffer__allocate__catchAll J4AC_java_nio_ByteBuffer__allocate__catchAll #define J4AC_ByteBuffer__allocateDirect J4AC_java_nio_ByteBuffer__allocateDirect #define J4AC_ByteBuffer__allocateDirect__asGlobalRef__catchAll J4AC_java_nio_ByteBuffer__allocateDirect__asGlobalRef__catchAll #define J4AC_ByteBuffer__allocateDirect__catchAll J4AC_java_nio_ByteBuffer__allocateDirect__catchAll #define J4AC_ByteBuffer__limit J4AC_java_nio_ByteBuffer__limit #define J4AC_ByteBuffer__limit__asGlobalRef__catchAll J4AC_java_nio_ByteBuffer__limit__asGlobalRef__catchAll #define J4AC_ByteBuffer__limit__catchAll J4AC_java_nio_ByteBuffer__limit__catchAll #define J4A_loadClass__J4AC_ByteBuffer J4A_loadClass__J4AC_java_nio_ByteBuffer #endif//J4A__java_nio_ByteBuffer__H ================================================ FILE: ijkmedia/ijkj4a/j4a/class/java/nio/ByteBuffer.include.j4a ================================================ #include "j4a/class/java/nio/ByteBuffer.h" ================================================ FILE: ijkmedia/ijkj4a/j4a/class/java/nio/ByteBuffer.loader.j4a ================================================ J4A_LOAD_CLASS(java_nio_ByteBuffer); ================================================ FILE: ijkmedia/ijkj4a/j4a/class/java/util/ArrayList.c ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #include "ArrayList.h" typedef struct J4AC_java_util_ArrayList { jclass id; jmethodID constructor_ArrayList; jmethodID method_add; } J4AC_java_util_ArrayList; static J4AC_java_util_ArrayList class_J4AC_java_util_ArrayList; jobject J4AC_java_util_ArrayList__ArrayList(JNIEnv *env) { return (*env)->NewObject(env, class_J4AC_java_util_ArrayList.id, class_J4AC_java_util_ArrayList.constructor_ArrayList); } jobject J4AC_java_util_ArrayList__ArrayList__catchAll(JNIEnv *env) { jobject ret_object = J4AC_java_util_ArrayList__ArrayList(env); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { return NULL; } return ret_object; } jobject J4AC_java_util_ArrayList__ArrayList__asGlobalRef__catchAll(JNIEnv *env) { jobject ret_object = NULL; jobject local_object = J4AC_java_util_ArrayList__ArrayList__catchAll(env); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } jboolean J4AC_java_util_ArrayList__add(JNIEnv *env, jobject thiz, jobject object) { return (*env)->CallBooleanMethod(env, thiz, class_J4AC_java_util_ArrayList.method_add, object); } jboolean J4AC_java_util_ArrayList__add__catchAll(JNIEnv *env, jobject thiz, jobject object) { jboolean ret_value = J4AC_java_util_ArrayList__add(env, thiz, object); if (J4A_ExceptionCheck__catchAll(env)) { return false; } return ret_value; } int J4A_loadClass__J4AC_java_util_ArrayList(JNIEnv *env) { int ret = -1; const char *J4A_UNUSED(name) = NULL; const char *J4A_UNUSED(sign) = NULL; jclass J4A_UNUSED(class_id) = NULL; int J4A_UNUSED(api_level) = 0; if (class_J4AC_java_util_ArrayList.id != NULL) return 0; sign = "java/util/ArrayList"; class_J4AC_java_util_ArrayList.id = J4A_FindClass__asGlobalRef__catchAll(env, sign); if (class_J4AC_java_util_ArrayList.id == NULL) goto fail; class_id = class_J4AC_java_util_ArrayList.id; name = ""; sign = "()V"; class_J4AC_java_util_ArrayList.constructor_ArrayList = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_java_util_ArrayList.constructor_ArrayList == NULL) goto fail; class_id = class_J4AC_java_util_ArrayList.id; name = "add"; sign = "(Ljava/lang/Object;)Z"; class_J4AC_java_util_ArrayList.method_add = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_java_util_ArrayList.method_add == NULL) goto fail; J4A_ALOGD("J4ALoader: OK: '%s' loaded\n", "java.util.ArrayList"); ret = 0; fail: return ret; } ================================================ FILE: ijkmedia/ijkj4a/j4a/class/java/util/ArrayList.h ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #ifndef J4A__java_util_ArrayList__H #define J4A__java_util_ArrayList__H #include "j4a/j4a_base.h" jobject J4AC_java_util_ArrayList__ArrayList(JNIEnv *env); jobject J4AC_java_util_ArrayList__ArrayList__catchAll(JNIEnv *env); jobject J4AC_java_util_ArrayList__ArrayList__asGlobalRef__catchAll(JNIEnv *env); jboolean J4AC_java_util_ArrayList__add(JNIEnv *env, jobject thiz, jobject object); jboolean J4AC_java_util_ArrayList__add__catchAll(JNIEnv *env, jobject thiz, jobject object); int J4A_loadClass__J4AC_java_util_ArrayList(JNIEnv *env); #define J4A_HAVE_SIMPLE__J4AC_java_util_ArrayList #define J4AC_ArrayList__ArrayList J4AC_java_util_ArrayList__ArrayList #define J4AC_ArrayList__ArrayList__asGlobalRef__catchAll J4AC_java_util_ArrayList__ArrayList__asGlobalRef__catchAll #define J4AC_ArrayList__ArrayList__catchAll J4AC_java_util_ArrayList__ArrayList__catchAll #define J4AC_ArrayList__add J4AC_java_util_ArrayList__add #define J4AC_ArrayList__add__catchAll J4AC_java_util_ArrayList__add__catchAll #define J4A_loadClass__J4AC_ArrayList J4A_loadClass__J4AC_java_util_ArrayList #endif//J4A__java_util_ArrayList__H ================================================ FILE: ijkmedia/ijkj4a/j4a/class/java/util/ArrayList.include.j4a ================================================ #include "j4a/class/java/util/ArrayList.h" ================================================ FILE: ijkmedia/ijkj4a/j4a/class/java/util/ArrayList.loader.j4a ================================================ J4A_LOAD_CLASS(java_util_ArrayList); ================================================ FILE: ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/IjkMediaPlayer.c ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #include "IjkMediaPlayer.h" typedef struct J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer { jclass id; jfieldID field_mNativeMediaPlayer; jfieldID field_mNativeMediaDataSource; jfieldID field_mNativeAndroidIO; jmethodID method_postEventFromNative; jmethodID method_onSelectCodec; jmethodID method_onNativeInvoke; } J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer; static J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer; jlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__get(JNIEnv *env, jobject thiz) { return (*env)->GetLongField(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeMediaPlayer); } jlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__get__catchAll(JNIEnv *env, jobject thiz) { jlong ret_value = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__get(env, thiz); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } void J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__set(JNIEnv *env, jobject thiz, jlong value) { (*env)->SetLongField(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeMediaPlayer, value); } void J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__set__catchAll(JNIEnv *env, jobject thiz, jlong value) { J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__set(env, thiz, value); J4A_ExceptionCheck__catchAll(env); } jlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__get(JNIEnv *env, jobject thiz) { return (*env)->GetLongField(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeMediaDataSource); } jlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__get__catchAll(JNIEnv *env, jobject thiz) { jlong ret_value = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__get(env, thiz); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } void J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__set(JNIEnv *env, jobject thiz, jlong value) { (*env)->SetLongField(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeMediaDataSource, value); } void J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__set__catchAll(JNIEnv *env, jobject thiz, jlong value) { J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__set(env, thiz, value); J4A_ExceptionCheck__catchAll(env); } jlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__get(JNIEnv *env, jobject thiz) { return (*env)->GetLongField(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeAndroidIO); } jlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__get__catchAll(JNIEnv *env, jobject thiz) { jlong ret_value = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__get(env, thiz); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } void J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__set(JNIEnv *env, jobject thiz, jlong value) { (*env)->SetLongField(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeAndroidIO, value); } void J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__set__catchAll(JNIEnv *env, jobject thiz, jlong value) { J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__set(env, thiz, value); J4A_ExceptionCheck__catchAll(env); } void J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__postEventFromNative(JNIEnv *env, jobject weakThiz, jint what, jint arg1, jint arg2, jobject obj) { (*env)->CallStaticVoidMethod(env, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_postEventFromNative, weakThiz, what, arg1, arg2, obj); } void J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__postEventFromNative__catchAll(JNIEnv *env, jobject weakThiz, jint what, jint arg1, jint arg2, jobject obj) { J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__postEventFromNative(env, weakThiz, what, arg1, arg2, obj); J4A_ExceptionCheck__catchAll(env); } jstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level) { return (*env)->CallStaticObjectMethod(env, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_onSelectCodec, weakThiz, mimeType, profile, level); } jstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__catchAll(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level) { jstring ret_object = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec(env, weakThiz, mimeType, profile, level); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { return NULL; } return ret_object; } jstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asGlobalRef__catchAll(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level) { jstring ret_object = NULL; jstring local_object = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__catchAll(env, weakThiz, mimeType, profile, level); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } const char *J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asCBuffer(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level, char *out_buf, int out_len) { const char *ret_value = NULL; const char *c_str = NULL; jstring local_string = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec(env, weakThiz, mimeType, profile, level); if (J4A_ExceptionCheck__throwAny(env) || !local_string) { goto fail; } c_str = (*env)->GetStringUTFChars(env, local_string, NULL ); if (J4A_ExceptionCheck__throwAny(env) || !c_str) { goto fail; } strlcpy(out_buf, c_str, out_len); ret_value = out_buf; fail: J4A_ReleaseStringUTFChars__p(env, local_string, &c_str); J4A_DeleteLocalRef__p(env, &local_string); return ret_value; } const char *J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asCBuffer__catchAll(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level, char *out_buf, int out_len) { const char *ret_value = NULL; const char *c_str = NULL; jstring local_string = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__catchAll(env, weakThiz, mimeType, profile, level); if (J4A_ExceptionCheck__catchAll(env) || !local_string) { goto fail; } c_str = (*env)->GetStringUTFChars(env, local_string, NULL ); if (J4A_ExceptionCheck__catchAll(env) || !c_str) { goto fail; } strlcpy(out_buf, c_str, out_len); ret_value = out_buf; fail: J4A_ReleaseStringUTFChars__p(env, local_string, &c_str); J4A_DeleteLocalRef__p(env, &local_string); return ret_value; } jstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level) { jstring ret_object = NULL; jstring mimeType = NULL; mimeType = (*env)->NewStringUTF(env, mimeType_cstr__); if (J4A_ExceptionCheck__throwAny(env) || !mimeType) goto fail; ret_object = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec(env, weakThiz, mimeType, profile, level); if (J4A_ExceptionCheck__throwAny(env) || !ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &mimeType); return ret_object; } jstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__catchAll(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level) { jstring ret_object = NULL; jstring mimeType = NULL; mimeType = (*env)->NewStringUTF(env, mimeType_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !mimeType) goto fail; ret_object = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__catchAll(env, weakThiz, mimeType, profile, level); if (J4A_ExceptionCheck__catchAll(env) || !ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &mimeType); return ret_object; } jstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asGlobalRef__catchAll(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level) { jstring ret_object = NULL; jstring local_object = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__catchAll(env, weakThiz, mimeType_cstr__, profile, level); if (J4A_ExceptionCheck__catchAll(env) || !local_object) { ret_object = NULL; goto fail; } ret_object = J4A_NewGlobalRef__catchAll(env, local_object); if (!ret_object) { ret_object = NULL; goto fail; } fail: J4A_DeleteLocalRef__p(env, &local_object); return ret_object; } const char *J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level, char *out_buf, int out_len) { const char *ret_value = NULL; const char *c_str = NULL; jstring local_string = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString(env, weakThiz, mimeType_cstr__, profile, level); if (J4A_ExceptionCheck__throwAny(env) || !local_string) { goto fail; } c_str = (*env)->GetStringUTFChars(env, local_string, NULL ); if (J4A_ExceptionCheck__throwAny(env) || !c_str) { goto fail; } strlcpy(out_buf, c_str, out_len); ret_value = out_buf; fail: J4A_ReleaseStringUTFChars__p(env, local_string, &c_str); J4A_DeleteLocalRef__p(env, &local_string); return ret_value; } const char *J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer__catchAll(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level, char *out_buf, int out_len) { const char *ret_value = NULL; const char *c_str = NULL; jstring local_string = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__catchAll(env, weakThiz, mimeType_cstr__, profile, level); if (J4A_ExceptionCheck__catchAll(env) || !local_string) { goto fail; } c_str = (*env)->GetStringUTFChars(env, local_string, NULL ); if (J4A_ExceptionCheck__catchAll(env) || !c_str) { goto fail; } strlcpy(out_buf, c_str, out_len); ret_value = out_buf; fail: J4A_ReleaseStringUTFChars__p(env, local_string, &c_str); J4A_DeleteLocalRef__p(env, &local_string); return ret_value; } jboolean J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onNativeInvoke(JNIEnv *env, jobject weakThiz, jint what, jobject args) { return (*env)->CallStaticBooleanMethod(env, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id, class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_onNativeInvoke, weakThiz, what, args); } jboolean J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onNativeInvoke__catchAll(JNIEnv *env, jobject weakThiz, jint what, jobject args) { jboolean ret_value = J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onNativeInvoke(env, weakThiz, what, args); if (J4A_ExceptionCheck__catchAll(env)) { return false; } return ret_value; } int J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer(JNIEnv *env) { int ret = -1; const char *J4A_UNUSED(name) = NULL; const char *J4A_UNUSED(sign) = NULL; jclass J4A_UNUSED(class_id) = NULL; int J4A_UNUSED(api_level) = 0; if (class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id != NULL) return 0; sign = "tv/danmaku/ijk/media/player/IjkMediaPlayer"; class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id = J4A_FindClass__asGlobalRef__catchAll(env, sign); if (class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id == NULL) goto fail; class_id = class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id; name = "mNativeMediaPlayer"; sign = "J"; class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeMediaPlayer = J4A_GetFieldID__catchAll(env, class_id, name, sign); if (class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeMediaPlayer == NULL) goto fail; class_id = class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id; name = "mNativeMediaDataSource"; sign = "J"; class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeMediaDataSource = J4A_GetFieldID__catchAll(env, class_id, name, sign); if (class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeMediaDataSource == NULL) goto fail; class_id = class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id; name = "mNativeAndroidIO"; sign = "J"; class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeAndroidIO = J4A_GetFieldID__catchAll(env, class_id, name, sign); if (class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.field_mNativeAndroidIO == NULL) goto fail; class_id = class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id; name = "postEventFromNative"; sign = "(Ljava/lang/Object;IIILjava/lang/Object;)V"; class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_postEventFromNative = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_postEventFromNative == NULL) goto fail; class_id = class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id; name = "onSelectCodec"; sign = "(Ljava/lang/Object;Ljava/lang/String;II)Ljava/lang/String;"; class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_onSelectCodec = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_onSelectCodec == NULL) goto fail; class_id = class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.id; name = "onNativeInvoke"; sign = "(Ljava/lang/Object;ILandroid/os/Bundle;)Z"; class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_onNativeInvoke = J4A_GetStaticMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer.method_onNativeInvoke == NULL) goto fail; J4A_ALOGD("J4ALoader: OK: '%s' loaded\n", "tv.danmaku.ijk.media.player.IjkMediaPlayer"); ret = 0; fail: return ret; } ================================================ FILE: ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/IjkMediaPlayer.h ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #ifndef J4A__tv_danmaku_ijk_media_player_IjkMediaPlayer__H #define J4A__tv_danmaku_ijk_media_player_IjkMediaPlayer__H #include "j4a/j4a_base.h" jlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__get(JNIEnv *env, jobject thiz); jlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__get__catchAll(JNIEnv *env, jobject thiz); void J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__set(JNIEnv *env, jobject thiz, jlong value); void J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__set__catchAll(JNIEnv *env, jobject thiz, jlong value); jlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__get(JNIEnv *env, jobject thiz); jlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__get__catchAll(JNIEnv *env, jobject thiz); void J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__set(JNIEnv *env, jobject thiz, jlong value); void J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__set__catchAll(JNIEnv *env, jobject thiz, jlong value); jlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__get(JNIEnv *env, jobject thiz); jlong J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__get__catchAll(JNIEnv *env, jobject thiz); void J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__set(JNIEnv *env, jobject thiz, jlong value); void J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__set__catchAll(JNIEnv *env, jobject thiz, jlong value); void J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__postEventFromNative(JNIEnv *env, jobject weakThiz, jint what, jint arg1, jint arg2, jobject obj); void J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__postEventFromNative__catchAll(JNIEnv *env, jobject weakThiz, jint what, jint arg1, jint arg2, jobject obj); jstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level); jstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__catchAll(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level); jstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asGlobalRef__catchAll(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level); const char *J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asCBuffer(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level, char *out_buf, int out_len); const char *J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asCBuffer__catchAll(JNIEnv *env, jobject weakThiz, jstring mimeType, jint profile, jint level, char *out_buf, int out_len); jstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level); jstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__catchAll(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level); jstring J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asGlobalRef__catchAll(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level); const char *J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level, char *out_buf, int out_len); const char *J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer__catchAll(JNIEnv *env, jobject weakThiz, const char *mimeType_cstr__, jint profile, jint level, char *out_buf, int out_len); jboolean J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onNativeInvoke(JNIEnv *env, jobject weakThiz, jint what, jobject args); jboolean J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onNativeInvoke__catchAll(JNIEnv *env, jobject weakThiz, jint what, jobject args); int J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer(JNIEnv *env); #define J4A_HAVE_SIMPLE__J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer #define J4AC_IjkMediaPlayer__mNativeMediaPlayer__get J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__get #define J4AC_IjkMediaPlayer__mNativeMediaPlayer__get__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__get__catchAll #define J4AC_IjkMediaPlayer__mNativeMediaPlayer__set J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__set #define J4AC_IjkMediaPlayer__mNativeMediaPlayer__set__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaPlayer__set__catchAll #define J4AC_IjkMediaPlayer__mNativeMediaDataSource__get J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__get #define J4AC_IjkMediaPlayer__mNativeMediaDataSource__get__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__get__catchAll #define J4AC_IjkMediaPlayer__mNativeMediaDataSource__set J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__set #define J4AC_IjkMediaPlayer__mNativeMediaDataSource__set__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeMediaDataSource__set__catchAll #define J4AC_IjkMediaPlayer__mNativeAndroidIO__get J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__get #define J4AC_IjkMediaPlayer__mNativeAndroidIO__get__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__get__catchAll #define J4AC_IjkMediaPlayer__mNativeAndroidIO__set J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__set #define J4AC_IjkMediaPlayer__mNativeAndroidIO__set__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__mNativeAndroidIO__set__catchAll #define J4AC_IjkMediaPlayer__postEventFromNative J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__postEventFromNative #define J4AC_IjkMediaPlayer__postEventFromNative__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__postEventFromNative__catchAll #define J4AC_IjkMediaPlayer__onSelectCodec J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec #define J4AC_IjkMediaPlayer__onSelectCodec__asCBuffer J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asCBuffer #define J4AC_IjkMediaPlayer__onSelectCodec__asCBuffer__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asCBuffer__catchAll #define J4AC_IjkMediaPlayer__onSelectCodec__asGlobalRef__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__asGlobalRef__catchAll #define J4AC_IjkMediaPlayer__onSelectCodec__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__catchAll #define J4AC_IjkMediaPlayer__onSelectCodec__withCString J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString #define J4AC_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer #define J4AC_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer__catchAll #define J4AC_IjkMediaPlayer__onSelectCodec__withCString__asGlobalRef__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__asGlobalRef__catchAll #define J4AC_IjkMediaPlayer__onSelectCodec__withCString__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onSelectCodec__withCString__catchAll #define J4AC_IjkMediaPlayer__onNativeInvoke J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onNativeInvoke #define J4AC_IjkMediaPlayer__onNativeInvoke__catchAll J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer__onNativeInvoke__catchAll #define J4A_loadClass__J4AC_IjkMediaPlayer J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_IjkMediaPlayer #endif//J4A__tv_danmaku_ijk_media_player_IjkMediaPlayer__H ================================================ FILE: ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/IjkMediaPlayer.include.j4a ================================================ #include "j4a/class/tv/danmaku/ijk/media/player/IjkMediaPlayer.h" ================================================ FILE: ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/IjkMediaPlayer.loader.j4a ================================================ J4A_LOAD_CLASS(tv_danmaku_ijk_media_player_IjkMediaPlayer); ================================================ FILE: ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.c ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #include "IAndroidIO.h" typedef struct J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO { jclass id; jmethodID method_open; jmethodID method_read; jmethodID method_seek; jmethodID method_close; } J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO; static J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO; jint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open(JNIEnv *env, jobject thiz, jstring url) { return (*env)->CallIntMethod(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_open, url); } jint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__catchAll(JNIEnv *env, jobject thiz, jstring url) { jint ret_value = J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open(env, thiz, url); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } jint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__withCString(JNIEnv *env, jobject thiz, const char *url_cstr__) { jint ret_value = 0; jstring url = NULL; url = (*env)->NewStringUTF(env, url_cstr__); if (J4A_ExceptionCheck__throwAny(env) || !url) goto fail; ret_value = J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open(env, thiz, url); if (J4A_ExceptionCheck__throwAny(env)) { ret_value = 0; goto fail; } fail: J4A_DeleteLocalRef__p(env, &url); return ret_value; } jint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__withCString__catchAll(JNIEnv *env, jobject thiz, const char *url_cstr__) { jint ret_value = 0; jstring url = NULL; url = (*env)->NewStringUTF(env, url_cstr__); if (J4A_ExceptionCheck__catchAll(env) || !url) goto fail; ret_value = J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__catchAll(env, thiz, url); if (J4A_ExceptionCheck__catchAll(env)) { ret_value = 0; goto fail; } fail: J4A_DeleteLocalRef__p(env, &url); return ret_value; } jint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__read(JNIEnv *env, jobject thiz, jbyteArray buffer, jint size) { return (*env)->CallIntMethod(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_read, buffer, size); } jint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__read__catchAll(JNIEnv *env, jobject thiz, jbyteArray buffer, jint size) { jint ret_value = J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__read(env, thiz, buffer, size); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } jlong J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__seek(JNIEnv *env, jobject thiz, jlong offset, jint whence) { return (*env)->CallLongMethod(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_seek, offset, whence); } jlong J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__seek__catchAll(JNIEnv *env, jobject thiz, jlong offset, jint whence) { jlong ret_value = J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__seek(env, thiz, offset, whence); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } jint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__close(JNIEnv *env, jobject thiz) { return (*env)->CallIntMethod(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_close); } jint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__close__catchAll(JNIEnv *env, jobject thiz) { jint ret_value = J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__close(env, thiz); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } int J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO(JNIEnv *env) { int ret = -1; const char *J4A_UNUSED(name) = NULL; const char *J4A_UNUSED(sign) = NULL; jclass J4A_UNUSED(class_id) = NULL; int J4A_UNUSED(api_level) = 0; if (class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.id != NULL) return 0; sign = "tv/danmaku/ijk/media/player/misc/IAndroidIO"; class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.id = J4A_FindClass__asGlobalRef__catchAll(env, sign); if (class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.id == NULL) goto fail; class_id = class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.id; name = "open"; sign = "(Ljava/lang/String;)I"; class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_open = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_open == NULL) goto fail; class_id = class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.id; name = "read"; sign = "([BI)I"; class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_read = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_read == NULL) goto fail; class_id = class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.id; name = "seek"; sign = "(JI)J"; class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_seek = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_seek == NULL) goto fail; class_id = class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.id; name = "close"; sign = "()I"; class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_close = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO.method_close == NULL) goto fail; J4A_ALOGD("J4ALoader: OK: '%s' loaded\n", "tv.danmaku.ijk.media.player.misc.IAndroidIO"); ret = 0; fail: return ret; } ================================================ FILE: ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.h ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #ifndef J4A__tv_danmaku_ijk_media_player_misc_IAndroidIO__H #define J4A__tv_danmaku_ijk_media_player_misc_IAndroidIO__H #include "j4a/j4a_base.h" jint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open(JNIEnv *env, jobject thiz, jstring url); jint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__catchAll(JNIEnv *env, jobject thiz, jstring url); jint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__withCString(JNIEnv *env, jobject thiz, const char *url_cstr__); jint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__withCString__catchAll(JNIEnv *env, jobject thiz, const char *url_cstr__); jint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__read(JNIEnv *env, jobject thiz, jbyteArray buffer, jint size); jint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__read__catchAll(JNIEnv *env, jobject thiz, jbyteArray buffer, jint size); jlong J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__seek(JNIEnv *env, jobject thiz, jlong offset, jint whence); jlong J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__seek__catchAll(JNIEnv *env, jobject thiz, jlong offset, jint whence); jint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__close(JNIEnv *env, jobject thiz); jint J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__close__catchAll(JNIEnv *env, jobject thiz); int J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO(JNIEnv *env); #define J4A_HAVE_SIMPLE__J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO #define J4AC_IAndroidIO__open J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open #define J4AC_IAndroidIO__open__catchAll J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__catchAll #define J4AC_IAndroidIO__open__withCString J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__withCString #define J4AC_IAndroidIO__open__withCString__catchAll J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__open__withCString__catchAll #define J4AC_IAndroidIO__read J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__read #define J4AC_IAndroidIO__read__catchAll J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__read__catchAll #define J4AC_IAndroidIO__seek J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__seek #define J4AC_IAndroidIO__seek__catchAll J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__seek__catchAll #define J4AC_IAndroidIO__close J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__close #define J4AC_IAndroidIO__close__catchAll J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO__close__catchAll #define J4A_loadClass__J4AC_IAndroidIO J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_misc_IAndroidIO #endif//J4A__tv_danmaku_ijk_media_player_misc_IAndroidIO__H ================================================ FILE: ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.include.j4a ================================================ #include "j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.h" ================================================ FILE: ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.loader.j4a ================================================ J4A_LOAD_CLASS(tv_danmaku_ijk_media_player_misc_IAndroidIO); ================================================ FILE: ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.c ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #include "IMediaDataSource.h" typedef struct J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource { jclass id; jmethodID method_readAt; jmethodID method_getSize; jmethodID method_close; } J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource; static J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource; jint J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__readAt(JNIEnv *env, jobject thiz, jlong position, jbyteArray buffer, jint offset, jint size) { return (*env)->CallIntMethod(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_readAt, position, buffer, offset, size); } jint J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__readAt__catchAll(JNIEnv *env, jobject thiz, jlong position, jbyteArray buffer, jint offset, jint size) { jint ret_value = J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__readAt(env, thiz, position, buffer, offset, size); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } jlong J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__getSize(JNIEnv *env, jobject thiz) { return (*env)->CallLongMethod(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_getSize); } jlong J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__getSize__catchAll(JNIEnv *env, jobject thiz) { jlong ret_value = J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__getSize(env, thiz); if (J4A_ExceptionCheck__catchAll(env)) { return 0; } return ret_value; } void J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__close(JNIEnv *env, jobject thiz) { (*env)->CallVoidMethod(env, thiz, class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_close); } void J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__close__catchAll(JNIEnv *env, jobject thiz) { J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__close(env, thiz); J4A_ExceptionCheck__catchAll(env); } int J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource(JNIEnv *env) { int ret = -1; const char *J4A_UNUSED(name) = NULL; const char *J4A_UNUSED(sign) = NULL; jclass J4A_UNUSED(class_id) = NULL; int J4A_UNUSED(api_level) = 0; if (class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.id != NULL) return 0; sign = "tv/danmaku/ijk/media/player/misc/IMediaDataSource"; class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.id = J4A_FindClass__asGlobalRef__catchAll(env, sign); if (class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.id == NULL) goto fail; class_id = class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.id; name = "readAt"; sign = "(J[BII)I"; class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_readAt = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_readAt == NULL) goto fail; class_id = class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.id; name = "getSize"; sign = "()J"; class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_getSize = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_getSize == NULL) goto fail; class_id = class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.id; name = "close"; sign = "()V"; class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_close = J4A_GetMethodID__catchAll(env, class_id, name, sign); if (class_J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource.method_close == NULL) goto fail; J4A_ALOGD("J4ALoader: OK: '%s' loaded\n", "tv.danmaku.ijk.media.player.misc.IMediaDataSource"); ret = 0; fail: return ret; } ================================================ FILE: ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.h ================================================ /* * Copyright (C) 2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * https://github.com/Bilibili/jni4android * This file is automatically generated by jni4android, do not modify. */ #ifndef J4A__tv_danmaku_ijk_media_player_misc_IMediaDataSource__H #define J4A__tv_danmaku_ijk_media_player_misc_IMediaDataSource__H #include "j4a/j4a_base.h" jint J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__readAt(JNIEnv *env, jobject thiz, jlong position, jbyteArray buffer, jint offset, jint size); jint J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__readAt__catchAll(JNIEnv *env, jobject thiz, jlong position, jbyteArray buffer, jint offset, jint size); jlong J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__getSize(JNIEnv *env, jobject thiz); jlong J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__getSize__catchAll(JNIEnv *env, jobject thiz); void J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__close(JNIEnv *env, jobject thiz); void J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__close__catchAll(JNIEnv *env, jobject thiz); int J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource(JNIEnv *env); #define J4A_HAVE_SIMPLE__J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource #define J4AC_IMediaDataSource__readAt J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__readAt #define J4AC_IMediaDataSource__readAt__catchAll J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__readAt__catchAll #define J4AC_IMediaDataSource__getSize J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__getSize #define J4AC_IMediaDataSource__getSize__catchAll J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__getSize__catchAll #define J4AC_IMediaDataSource__close J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__close #define J4AC_IMediaDataSource__close__catchAll J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource__close__catchAll #define J4A_loadClass__J4AC_IMediaDataSource J4A_loadClass__J4AC_tv_danmaku_ijk_media_player_misc_IMediaDataSource #endif//J4A__tv_danmaku_ijk_media_player_misc_IMediaDataSource__H ================================================ FILE: ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.include.j4a ================================================ #include "j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.h" ================================================ FILE: ijkmedia/ijkj4a/j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.loader.j4a ================================================ J4A_LOAD_CLASS(tv_danmaku_ijk_media_player_misc_IMediaDataSource); ================================================ FILE: ijkmedia/ijkj4a/j4a/j4a_allclasses.c ================================================ /* * copyright (c) 2016 Zhang Rui * * This file is part of jni4android. * * jni4android 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. * * jni4android 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 jni4android; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "j4a_allclasses.h" int J4A_LoadAll__catchAll(JNIEnv *env) { int ret = 0; // load android.os.Build at very beginning J4A_LOAD_CLASS(android_os_Build); #include "j4a/j4a_allclasses.loader.h" fail: return ret; } ================================================ FILE: ijkmedia/ijkj4a/j4a/j4a_allclasses.h ================================================ /* * copyright (c) 2016 Zhang Rui * * This file is part of jni4android. * * jni4android 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. * * jni4android 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 jni4android; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKJ4A__J4A__J4A_ALLCLASSES__H #define IJKJ4A__J4A__J4A_ALLCLASSES__H #include "j4a_base.h" #include "j4a_allclasses.include.h" #endif ================================================ FILE: ijkmedia/ijkj4a/j4a/j4a_allclasses.include.h ================================================ #include "j4a/class/java/nio/Buffer.h" #include "j4a/class/java/nio/ByteBuffer.h" #include "j4a/class/java/util/ArrayList.h" #include "j4a/class/android/media/AudioTrack.h" #include "j4a/class/android/media/MediaCodec.h" #include "j4a/class/android/media/MediaFormat.h" #include "j4a/class/android/media/PlaybackParams.h" #include "j4a/class/android/os/Build.h" #include "j4a/class/android/os/Bundle.h" #include "j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.h" #include "j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.h" #include "j4a/class/tv/danmaku/ijk/media/player/IjkMediaPlayer.h" ================================================ FILE: ijkmedia/ijkj4a/j4a/j4a_allclasses.loader.h ================================================ J4A_LOAD_CLASS(java_nio_Buffer); J4A_LOAD_CLASS(java_nio_ByteBuffer); J4A_LOAD_CLASS(java_util_ArrayList); J4A_LOAD_CLASS(android_media_AudioTrack); J4A_LOAD_CLASS(android_media_MediaCodec); J4A_LOAD_CLASS(android_media_MediaFormat); J4A_LOAD_CLASS(android_media_PlaybackParams); J4A_LOAD_CLASS(android_os_Build); J4A_LOAD_CLASS(android_os_Bundle); J4A_LOAD_CLASS(tv_danmaku_ijk_media_player_misc_IMediaDataSource); J4A_LOAD_CLASS(tv_danmaku_ijk_media_player_misc_IAndroidIO); J4A_LOAD_CLASS(tv_danmaku_ijk_media_player_IjkMediaPlayer); ================================================ FILE: ijkmedia/ijkj4a/j4a/j4a_base.c ================================================ /* * copyright (c) 2015 Zhang Rui * * This file is part of jni4android. * * jni4android 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. * * jni4android 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 jni4android; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "j4a_base.h" #include "j4a/class/android/os/Build.h" /******************** * Exception Handle ********************/ bool J4A_ExceptionCheck__throwAny(JNIEnv *env) { if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionDescribe(env); return true; } return false; } bool J4A_ExceptionCheck__catchAll(JNIEnv *env) { if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); return true; } return false; } int J4A_ThrowExceptionOfClass(JNIEnv* env, jclass clazz, const char* msg) { if ((*env)->ThrowNew(env, clazz, msg) != JNI_OK) J4A_ALOGE("%s: Failed: msg: '%s'\n", __func__, msg); return 0; } int J4A_ThrowException(JNIEnv* env, const char* class_sign, const char* msg) { int ret = -1; if (J4A_ExceptionCheck__catchAll(env)) { J4A_ALOGE("pending exception throwed.\n"); } jclass exceptionClass = J4A_FindClass__catchAll(env, class_sign); if (exceptionClass == NULL) { J4A_FUNC_FAIL_TRACE(); ret = -1; goto fail; } ret = J4A_ThrowExceptionOfClass(env, exceptionClass, msg); if (ret) { J4A_FUNC_FAIL_TRACE(); goto fail; } ret = 0; fail: J4A_DeleteLocalRef__p(env, &exceptionClass); return ret; } int J4A_ThrowIllegalStateException(JNIEnv *env, const char* msg) { return J4A_ThrowException(env, "java/lang/IllegalStateException", msg); } /******************** * References ********************/ jclass J4A_NewGlobalRef__catchAll(JNIEnv *env, jobject obj) { jclass obj_global = (*env)->NewGlobalRef(env, obj); if (J4A_ExceptionCheck__catchAll(env) || !(obj_global)) { J4A_FUNC_FAIL_TRACE(); goto fail; } fail: return obj_global; } void J4A_DeleteLocalRef(JNIEnv *env, jobject obj) { if (!obj) return; (*env)->DeleteLocalRef(env, obj); } void J4A_DeleteLocalRef__p(JNIEnv *env, jobject *obj) { if (!obj) return; J4A_DeleteLocalRef(env, *obj); *obj = NULL; } void J4A_DeleteGlobalRef(JNIEnv *env, jobject obj) { if (!obj) return; (*env)->DeleteGlobalRef(env, obj); } void J4A_DeleteGlobalRef__p(JNIEnv *env, jobject *obj) { if (!obj) return; J4A_DeleteGlobalRef(env, *obj); *obj = NULL; } void J4A_ReleaseStringUTFChars(JNIEnv *env, jstring str, const char *c_str) { if (!str || !c_str) return; (*env)->ReleaseStringUTFChars(env, str, c_str); } void J4A_ReleaseStringUTFChars__p(JNIEnv *env, jstring str, const char **c_str) { if (!str || !c_str) return; J4A_ReleaseStringUTFChars(env, str, *c_str); *c_str = NULL; } /******************** * Class Load ********************/ jclass J4A_FindClass__catchAll(JNIEnv *env, const char *class_sign) { jclass clazz = (*env)->FindClass(env, class_sign); if (J4A_ExceptionCheck__catchAll(env) || !(clazz)) { J4A_FUNC_FAIL_TRACE(); clazz = NULL; goto fail; } fail: return clazz; } jclass J4A_FindClass__asGlobalRef__catchAll(JNIEnv *env, const char *class_sign) { jclass clazz_global = NULL; jclass clazz = J4A_FindClass__catchAll(env, class_sign); if (!clazz) { J4A_FUNC_FAIL_TRACE1(class_sign); goto fail; } clazz_global = J4A_NewGlobalRef__catchAll(env, clazz); if (!clazz_global) { J4A_FUNC_FAIL_TRACE1(class_sign); goto fail; } fail: J4A_DeleteLocalRef__p(env, &clazz); return clazz_global; } jmethodID J4A_GetMethodID__catchAll(JNIEnv *env, jclass clazz, const char *method_name, const char *method_sign) { jmethodID method_id = (*env)->GetMethodID(env, clazz, method_name, method_sign); if (J4A_ExceptionCheck__catchAll(env) || !method_id) { J4A_FUNC_FAIL_TRACE2(method_name, method_sign); method_id = NULL; goto fail; } fail: return method_id; } jmethodID J4A_GetStaticMethodID__catchAll(JNIEnv *env, jclass clazz, const char *method_name, const char *method_sign) { jmethodID method_id = (*env)->GetStaticMethodID(env, clazz, method_name, method_sign); if (J4A_ExceptionCheck__catchAll(env) || !method_id) { J4A_FUNC_FAIL_TRACE2(method_name, method_sign); method_id = NULL; goto fail; } fail: return method_id; } jfieldID J4A_GetFieldID__catchAll(JNIEnv *env, jclass clazz, const char *field_name, const char *field_sign) { jfieldID field_id = (*env)->GetFieldID(env, clazz, field_name, field_sign); if (J4A_ExceptionCheck__catchAll(env) || !field_id) { J4A_FUNC_FAIL_TRACE2(field_name, field_sign); field_id = NULL; goto fail; } fail: return field_id; } jfieldID J4A_GetStaticFieldID__catchAll(JNIEnv *env, jclass clazz, const char *field_name, const char *field_sign) { jfieldID field_id = (*env)->GetStaticFieldID(env, clazz, field_name, field_sign); if (J4A_ExceptionCheck__catchAll(env) || !field_id) { J4A_FUNC_FAIL_TRACE2(field_name, field_sign); field_id = NULL; goto fail; } fail: return field_id; } /******************** * Misc Functions ********************/ jbyteArray J4A_NewByteArray__catchAll(JNIEnv *env, jsize capacity) { jbyteArray local = (*env)->NewByteArray(env, capacity); if (J4A_ExceptionCheck__catchAll(env) || !local) return NULL; return local; } jbyteArray J4A_NewByteArray__asGlobalRef__catchAll(JNIEnv *env, jsize capacity) { jbyteArray local = (*env)->NewByteArray(env, capacity); if (J4A_ExceptionCheck__catchAll(env) || !local) return NULL; jbyteArray global = (*env)->NewGlobalRef(env, local); J4A_DeleteLocalRef__p(env, &local); return global; } int J4A_GetSystemAndroidApiLevel(JNIEnv *env) { static int SDK_INT = 0; if (SDK_INT > 0) return SDK_INT; SDK_INT = J4AC_android_os_Build__VERSION__SDK_INT__get__catchAll(env); J4A_ALOGI("API-Level: %d\n", SDK_INT); return SDK_INT; } ================================================ FILE: ijkmedia/ijkj4a/j4a/j4a_base.h ================================================ /* * copyright (c) 2015 Zhang Rui * * This file is part of jni4android. * * jni4android 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. * * jni4android 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 jni4android; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef J4A_BASE_H #define J4A_BASE_H #include #include #include #include #include #ifndef J4A_UNUSED #define J4A_UNUSED(x) x __attribute__((unused)) #endif #define J4A_LOG_TAG "J4A" #define J4A_VLOGV(...) __android_log_vprint(ANDROID_LOG_VERBOSE, J4A_LOG_TAG, __VA_ARGS__) #define J4A_VLOGD(...) __android_log_vprint(ANDROID_LOG_DEBUG, J4A_LOG_TAG, __VA_ARGS__) #define J4A_VLOGI(...) __android_log_vprint(ANDROID_LOG_INFO, J4A_LOG_TAG, __VA_ARGS__) #define J4A_VLOGW(...) __android_log_vprint(ANDROID_LOG_WARN, J4A_LOG_TAG, __VA_ARGS__) #define J4A_VLOGE(...) __android_log_vprint(ANDROID_LOG_ERROR, J4A_LOG_TAG, __VA_ARGS__) #define J4A_ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, J4A_LOG_TAG, __VA_ARGS__) #define J4A_ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, J4A_LOG_TAG, __VA_ARGS__) #define J4A_ALOGI(...) __android_log_print(ANDROID_LOG_INFO, J4A_LOG_TAG, __VA_ARGS__) #define J4A_ALOGW(...) __android_log_print(ANDROID_LOG_WARN, J4A_LOG_TAG, __VA_ARGS__) #define J4A_ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, J4A_LOG_TAG, __VA_ARGS__) #define J4A_FUNC_FAIL_TRACE() do {J4A_ALOGE("%s: failed\n", __func__);} while (0) #define J4A_FUNC_FAIL_TRACE1(x__) do {J4A_ALOGE("%s: failed: %s\n", __func__, x__);} while (0) #define J4A_FUNC_FAIL_TRACE2(x1__, x2__) do {J4A_ALOGE("%s: failed: %s %s\n", __func__, x1__, x2__);} while (0) #define J4A_LOAD_CLASS(class__) \ do { \ ret = J4A_loadClass__J4AC_##class__(env); \ if (ret) \ goto fail; \ } while (0) /******************** * Exception Handle ********************/ bool J4A_ExceptionCheck__throwAny(JNIEnv *env); bool J4A_ExceptionCheck__catchAll(JNIEnv *env); int J4A_ThrowExceptionOfClass(JNIEnv* env, jclass clazz, const char* msg); int J4A_ThrowException(JNIEnv* env, const char* class_sign, const char* msg); int J4A_ThrowIllegalStateException(JNIEnv *env, const char* msg); /******************** * References ********************/ jclass J4A_NewGlobalRef__catchAll(JNIEnv *env, jobject obj); void J4A_DeleteLocalRef(JNIEnv *env, jobject obj); void J4A_DeleteLocalRef__p(JNIEnv *env, jobject *obj); void J4A_DeleteGlobalRef(JNIEnv *env, jobject obj); void J4A_DeleteGlobalRef__p(JNIEnv *env, jobject *obj); void J4A_ReleaseStringUTFChars(JNIEnv *env, jstring str, const char *c_str); void J4A_ReleaseStringUTFChars__p(JNIEnv *env, jstring str, const char **c_str); /******************** * Class Load ********************/ int J4A_LoadAll__catchAll(JNIEnv *env); jclass J4A_FindClass__catchAll(JNIEnv *env, const char *class_sign); jclass J4A_FindClass__asGlobalRef__catchAll(JNIEnv *env, const char *class_sign); jmethodID J4A_GetMethodID__catchAll(JNIEnv *env, jclass clazz, const char *method_name, const char *method_sign); jmethodID J4A_GetStaticMethodID__catchAll(JNIEnv *env, jclass clazz, const char *method_name, const char *method_sign); jfieldID J4A_GetFieldID__catchAll(JNIEnv *env, jclass clazz, const char *field_name, const char *method_sign); jfieldID J4A_GetStaticFieldID__catchAll(JNIEnv *env, jclass clazz, const char *field_name, const char *method_sign); /******************** * Misc Functions ********************/ jbyteArray J4A_NewByteArray__catchAll(JNIEnv *env, jsize capacity); jbyteArray J4A_NewByteArray__asGlobalRef__catchAll(JNIEnv *env, jsize capacity); int J4A_GetSystemAndroidApiLevel(JNIEnv *env); #endif//J4A_INTERNAL_H ================================================ FILE: ijkmedia/ijkj4a/j4au/class/android/media/AudioTrack.util.c ================================================ /* * copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "AudioTrack.util.h" #include "j4a/class/android/media/PlaybackParams.h" #ifndef STREAM_MUSIC #define STREAM_MUSIC 3 #endif void J4AC_android_media_AudioTrack__setSpeed(JNIEnv *env, jobject thiz, jfloat speed) { if (J4A_GetSystemAndroidApiLevel(env) < 23) { jint sample_rate = J4AC_android_media_AudioTrack__getSampleRate(env,thiz); if (J4A_ExceptionCheck__throwAny(env)) { return; } J4AC_android_media_AudioTrack__setPlaybackRate__catchAll(env, thiz, (jint) (sample_rate * speed)); return; } jobject temp = NULL; jobject params = J4AC_android_media_AudioTrack__getPlaybackParams(env, thiz); if (J4A_ExceptionCheck__throwAny(env) || !params) goto fail; temp = J4AC_android_media_PlaybackParams__setSpeed(env, params, speed); J4A_DeleteLocalRef__p(env, &temp); if (J4A_ExceptionCheck__throwAny(env)) goto fail; J4A_ALOGE("%s %f", __func__, (double)speed); J4AC_android_media_AudioTrack__setPlaybackParams(env, thiz, params); if (J4A_ExceptionCheck__throwAny(env)) goto fail; fail: J4A_DeleteLocalRef__p(env, ¶ms); } void J4AC_android_media_AudioTrack__setSpeed__catchAll(JNIEnv *env, jobject thiz, jfloat speed) { J4A_ALOGE("%s", __func__); J4AC_android_media_AudioTrack__setSpeed(env, thiz, speed); if (J4A_ExceptionCheck__catchAll(env)) return; return; } ================================================ FILE: ijkmedia/ijkj4a/j4au/class/android/media/AudioTrack.util.h ================================================ /* * copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef J4AU__android_media_AudioTrack__UTIL__H #define J4AU__android_media_AudioTrack__UTIL__H #include "j4a/j4a_base.h" #include "j4a/class/android/media/AudioTrack.h" void J4AC_android_media_AudioTrack__setSpeed(JNIEnv *env, jobject thiz, jfloat speed); void J4AC_android_media_AudioTrack__setSpeed__catchAll(JNIEnv *env, jobject thiz, jfloat speed); #ifdef J4A_HAVE_SIMPLE__J4AC_android_media_AudioTrack #define J4AC_AudioTrack__setSpeed J4AC_android_media_AudioTrack__setSpeed #define J4AC_AudioTrack__setSpeed__catchAll J4AC_android_media_AudioTrack__setSpeed__catchAll #endif #endif ================================================ FILE: ijkmedia/ijkj4a/j4au/class/java/nio/ByteBuffer.util.c ================================================ /* * copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ByteBuffer.util.h" void *J4AC_java_nio_ByteBuffer__getDirectBufferAddress(JNIEnv *env, jobject thiz) { return (*env)->GetDirectBufferAddress(env, thiz); } void *J4AC_java_nio_ByteBuffer__getDirectBufferAddress__catchAll(JNIEnv *env, jobject thiz) { void *ret = (*env)->GetDirectBufferAddress(env, thiz); if (J4A_ExceptionCheck__catchAll(env) || !ret) return NULL; return ret; } int J4AC_java_nio_ByteBuffer__assignData__catchAll(JNIEnv *env, jobject thiz, void* data, size_t size) { jobject buffer = J4AC_java_nio_ByteBuffer__limit(env, thiz, size); if (J4A_ExceptionCheck__catchAll(env) || !buffer) return -1; J4A_DeleteLocalRef__p(env, &buffer); uint8_t *c_buffer = J4AC_java_nio_ByteBuffer__getDirectBufferAddress__catchAll(env, thiz); if (!c_buffer) return -1; memcpy(c_buffer, data, size); return 0; } ================================================ FILE: ijkmedia/ijkj4a/j4au/class/java/nio/ByteBuffer.util.h ================================================ /* * copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef J4A__java_nio_ByteBuffer__UTIL__H #define J4A__java_nio_ByteBuffer__UTIL__H #include "j4a/j4a_base.h" #include "j4a/class/java/nio/ByteBuffer.h" void *J4AC_java_nio_ByteBuffer__getDirectBufferAddress(JNIEnv *env, jobject thiz); void *J4AC_java_nio_ByteBuffer__getDirectBufferAddress__catchAll(JNIEnv *env, jobject thiz); int J4AC_java_nio_ByteBuffer__assignData__catchAll(JNIEnv *env, jobject thiz, void* data, size_t size); #ifdef J4A_HAVE_SIMPLE__J4AC_java_nio_ByteBuffer #define J4AC_ByteBuffer__getDirectBufferAddress J4AC_java_nio_ByteBuffer__getDirectBufferAddress #define J4AC_ByteBuffer__getDirectBufferAddress__catchAll J4AC_java_nio_ByteBuffer__getDirectBufferAddress__catchAll #define J4AC_ByteBuffer__assignData__catchAll J4AC_java_nio_ByteBuffer__assignData__catchAll #endif #endif ================================================ FILE: ijkmedia/ijkj4a/java/android/media/AudioTrack.java ================================================ package android.media; @SimpleCClassName @IncludeUtil public class AudioTrack { public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode); public static int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat); public static float getMaxVolume(); public static float getMinVolume(); public static int getNativeOutputSampleRate(int streamType); public void play(); public void pause(); public void stop(); public void flush(); public void release(); public int write(byte[] audioData, int offsetInBytes, int sizeInBytes); public int setStereoVolume(float leftGain, float rightGain); public int getAudioSessionId(); @MinApi(23) public PlaybackParams getPlaybackParams(); @MinApi(23) void setPlaybackParams(PlaybackParams params); int getStreamType(); int getSampleRate(); int getPlaybackRate(); int setPlaybackRate(int sampleRateInHz); } ================================================ FILE: ijkmedia/ijkj4a/java/android/media/MediaCodec.java ================================================ package android.media; import java.nio.ByteBuffer; import android.view.Surface; @SimpleCClassName @MinApi(16) public class MediaCodec { public static class BufferInfo { public int flags; public int offset; public long presentationTimeUs; public int size; public BufferInfo(); } public static MediaCodec createByCodecName(String name); public void configure(MediaFormat format, Surface surface, MediaCrypto crypto, int flags); public final MediaFormat getOutputFormat(); public ByteBuffer[] getInputBuffers(); public final int dequeueInputBuffer(long timeoutUs); public final void queueInputBuffer(int index, int offset, int size, long presentationTimeUs, int flags); public final int dequeueOutputBuffer(MediaCodec.BufferInfo info, long timeoutUs); public final void releaseOutputBuffer(int index, boolean render); public final void start(); public final void stop(); public final void flush(); public final void release(); } ================================================ FILE: ijkmedia/ijkj4a/java/android/media/MediaCrypto.java ================================================ package android.media; @Hide @MinApi(16) public class MediaCrypto { } ================================================ FILE: ijkmedia/ijkj4a/java/android/media/MediaFormat.java ================================================ package android.media; import java.nio.ByteBuffer; @SimpleCClassName @MinApi(16) public class MediaFormat { public MediaFormat(); public final static MediaFormat createVideoFormat(String mime, int width, int height); public final int getInteger(String name); public final void setInteger(String name, int value); public final void setByteBuffer(String name, ByteBuffer bytes); } ================================================ FILE: ijkmedia/ijkj4a/java/android/media/PlaybackParams.java ================================================ package android.media; @SimpleCClassName @MinApi(23) public class PlaybackParams { public PlaybackParams setSpeed(float speed); } ================================================ FILE: ijkmedia/ijkj4a/java/android/os/Build.java ================================================ package android.os; public class Build { public static class VERSION { public static final int SDK_INT; } } ================================================ FILE: ijkmedia/ijkj4a/java/android/os/Bundle.java ================================================ package android.os; import java.util.ArrayList; @SimpleCClassName public class Bundle { public Bundle(); public int getInt(String key, int defaultValue); public void putInt(String key, int value); public String getString(String key); public void putString(String key, String value); public void putParcelableArrayList(String key, ArrayList value); public long getLong(String key); public void putLong(String key, long value); } ================================================ FILE: ijkmedia/ijkj4a/java/java/nio/Buffer.java ================================================ package java.nio; public class Buffer { } ================================================ FILE: ijkmedia/ijkj4a/java/java/nio/ByteBuffer.java ================================================ package java.nio; import android.os.Build; @SimpleCClassName @IncludeUtil public class ByteBuffer { public static ByteBuffer allocate(int capacity); public static ByteBuffer allocateDirect(int capacity); public final Buffer limit(int newLimit); } ================================================ FILE: ijkmedia/ijkj4a/java/java/util/ArrayList.java ================================================ package java.util; @SimpleCClassName public class ArrayList { public ArrayList(); boolean add(Object object); } ================================================ FILE: ijkmedia/ijkj4a/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java ================================================ package tv.danmaku.ijk.media.player; import android.os.Bundle; @SimpleCClassName public class IjkMediaPlayer { private long mNativeMediaPlayer; private long mNativeMediaDataSource; private long mNativeAndroidIO; private static void postEventFromNative(Object weakThiz, int what, int arg1, int arg2, Object obj); private static String onSelectCodec(Object weakThiz, String mimeType, int profile, int level); private static boolean onNativeInvoke(Object weakThiz, int what, Bundle args); } ================================================ FILE: ijkmedia/ijkj4a/java/tv/danmaku/ijk/media/player/misc/IAndroidIO.java ================================================ package tv.danmaku.ijk.media.player.misc; @SimpleCClassName public interface IAndroidIO { int open(String url); int read(byte[] buffer, int size); long seek(long offset, int whence); int close(); } ================================================ FILE: ijkmedia/ijkj4a/java/tv/danmaku/ijk/media/player/misc/IMediaDataSource.java ================================================ package tv.danmaku.ijk.media.player.misc; @SimpleCClassName public interface IMediaDataSource { int readAt(long position, byte[] buffer, int offset, int size); long getSize(); void close(); } ================================================ FILE: ijkmedia/ijkplayer/.gitignore ================================================ ijkversion.h ================================================ FILE: ijkmedia/ijkplayer/Android.mk ================================================ # # Copyright (c) 2013 Bilibili # Copyright (c) 2013 Zhang Rui # # This file is part of ijkPlayer. # # ijkPlayer 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. # # ijkPlayer 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 ijkPlayer; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # -mfloat-abi=soft is a workaround for FP register corruption on Exynos 4210 # http://www.spinics.net/lists/arm-kernel/msg368417.html ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) LOCAL_CFLAGS += -mfloat-abi=soft endif LOCAL_CFLAGS += -std=c99 LOCAL_LDLIBS += -llog -landroid LOCAL_C_INCLUDES += $(LOCAL_PATH) LOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/..) LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) LOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/../ijkj4a) LOCAL_SRC_FILES += ff_cmdutils.c LOCAL_SRC_FILES += ff_ffplay.c LOCAL_SRC_FILES += ff_ffpipeline.c LOCAL_SRC_FILES += ff_ffpipenode.c LOCAL_SRC_FILES += ijkmeta.c LOCAL_SRC_FILES += ijkplayer.c LOCAL_SRC_FILES += pipeline/ffpipeline_ffplay.c LOCAL_SRC_FILES += pipeline/ffpipenode_ffplay_vdec.c LOCAL_SRC_FILES += android/ffmpeg_api_jni.c LOCAL_SRC_FILES += android/ijkplayer_android.c LOCAL_SRC_FILES += android/ijkplayer_jni.c LOCAL_SRC_FILES += android/pipeline/ffpipeline_android.c LOCAL_SRC_FILES += android/pipeline/ffpipenode_android_mediacodec_vdec.c LOCAL_SRC_FILES += ijkavformat/allformats.c LOCAL_SRC_FILES += ijkavformat/cJSON.c LOCAL_SRC_FILES += ijkavformat/ijklas.c LOCAL_SRC_FILES += ijkavformat/ijklivehook.c LOCAL_SRC_FILES += ijkavformat/ijkmediadatasource.c LOCAL_SRC_FILES += ijkavformat/ijkio.c LOCAL_SRC_FILES += ijkavformat/ijkiomanager.c LOCAL_SRC_FILES += ijkavformat/ijkiocache.c LOCAL_SRC_FILES += ijkavformat/ijkioffio.c LOCAL_SRC_FILES += ijkavformat/ijkioandroidio.c LOCAL_SRC_FILES += ijkavformat/ijkioprotocol.c LOCAL_SRC_FILES += ijkavformat/ijkioapplication.c LOCAL_SRC_FILES += ijkavformat/ijkiourlhook.c LOCAL_SRC_FILES += ijkavformat/ijkasync.c LOCAL_SRC_FILES += ijkavformat/ijkurlhook.c LOCAL_SRC_FILES += ijkavformat/ijklongurl.c LOCAL_SRC_FILES += ijkavformat/ijksegment.c LOCAL_SRC_FILES += ijkavutil/ijkdict.c LOCAL_SRC_FILES += ijkavutil/ijkutils.c LOCAL_SRC_FILES += ijkavutil/ijkthreadpool.c LOCAL_SRC_FILES += ijkavutil/ijktree.c LOCAL_SRC_FILES += ijkavutil/ijkfifo.c LOCAL_SRC_FILES += ijkavutil/ijkstl.cpp LOCAL_SHARED_LIBRARIES := ijkffmpeg ijksdl LOCAL_STATIC_LIBRARIES := android-ndk-profiler ijksoundtouch LOCAL_MODULE := ijkplayer VERSION_SH = $(LOCAL_PATH)/version.sh VERSION_H = ijkversion.h $(info $(shell ($(VERSION_SH) $(LOCAL_PATH) $(VERSION_H)))) include $(BUILD_SHARED_LIBRARY) ================================================ FILE: ijkmedia/ijkplayer/android/ffmpeg_api_jni.c ================================================ /* * ffmpeg_api_jni.c * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ffmpeg_api_jni.h" #include #include #include #include "../ff_ffinc.h" #include "ijksdl/ijksdl_log.h" #include "ijksdl/android/ijksdl_android_jni.h" #define JNI_CLASS_FFMPEG_API "tv/danmaku/ijk/media/player/ffmpeg/FFmpegApi" typedef struct ffmpeg_api_fields_t { jclass clazz; } ffmpeg_api_fields_t; static ffmpeg_api_fields_t g_clazz; static jstring FFmpegApi_av_base64_encode(JNIEnv *env, jclass clazz, jbyteArray in) { jstring ret_string = NULL; char* out_buffer = 0; int out_size = 0; jbyte* in_buffer = 0; jsize in_size = (*env)->GetArrayLength(env, in); if (in_size <= 0) goto fail; in_buffer = (*env)->GetByteArrayElements(env, in, NULL); if (!in_buffer) goto fail; out_size = AV_BASE64_SIZE(in_size); out_buffer = malloc(out_size + 1); if (!out_buffer) goto fail; out_buffer[out_size] = 0; if (!av_base64_encode(out_buffer, out_size, (const uint8_t *)in_buffer, in_size)) goto fail; ret_string = (*env)->NewStringUTF(env, out_buffer); fail: if (in_buffer) { (*env)->ReleaseByteArrayElements(env, in, in_buffer, JNI_ABORT); in_buffer = NULL; } if (out_buffer) { free(out_buffer); out_buffer = NULL; } return ret_string; } static JNINativeMethod g_methods[] = { {"av_base64_encode", "([B)Ljava/lang/String;", (void *) FFmpegApi_av_base64_encode}, }; int FFmpegApi_global_init(JNIEnv *env) { int ret = 0; IJK_FIND_JAVA_CLASS(env, g_clazz.clazz, JNI_CLASS_FFMPEG_API); (*env)->RegisterNatives(env, g_clazz.clazz, g_methods, NELEM(g_methods)); return ret; } ================================================ FILE: ijkmedia/ijkplayer/android/ffmpeg_api_jni.h ================================================ /* * ffmpeg_api_jni.h * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKPLAYER_ANDROID__FFMPEG_API_JNI_H #include int FFmpegApi_global_init(JNIEnv *env); #endif ================================================ FILE: ijkmedia/ijkplayer/android/ijkplayer_android.c ================================================ /* * ijkplayer_android.c * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijkplayer_android.h" #include #include "ijksdl/android/ijksdl_android.h" #include "../ff_fferror.h" #include "../ff_ffplay.h" #include "../ijkplayer_internal.h" #include "../pipeline/ffpipeline_ffplay.h" #include "pipeline/ffpipeline_android.h" IjkMediaPlayer *ijkmp_android_create(int(*msg_loop)(void*)) { IjkMediaPlayer *mp = ijkmp_create(msg_loop); if (!mp) goto fail; mp->ffplayer->vout = SDL_VoutAndroid_CreateForAndroidSurface(); if (!mp->ffplayer->vout) goto fail; mp->ffplayer->pipeline = ffpipeline_create_from_android(mp->ffplayer); if (!mp->ffplayer->pipeline) goto fail; ffpipeline_set_vout(mp->ffplayer->pipeline, mp->ffplayer->vout); return mp; fail: ijkmp_dec_ref_p(&mp); return NULL; } void ijkmp_android_set_surface_l(JNIEnv *env, IjkMediaPlayer *mp, jobject android_surface) { if (!mp || !mp->ffplayer || !mp->ffplayer->vout) return; SDL_VoutAndroid_SetAndroidSurface(env, mp->ffplayer->vout, android_surface); ffpipeline_set_surface(env, mp->ffplayer->pipeline, android_surface); } void ijkmp_android_set_surface(JNIEnv *env, IjkMediaPlayer *mp, jobject android_surface) { 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); pthread_mutex_unlock(&mp->mutex); MPTRACE("ijkmp_set_android_surface(surface=%p)=void", (void*)android_surface); } void ijkmp_android_set_volume(JNIEnv *env, IjkMediaPlayer *mp, float left, float right) { if (!mp) return; MPTRACE("ijkmp_android_set_volume(%f, %f)", left, right); pthread_mutex_lock(&mp->mutex); if (mp && mp->ffplayer && mp->ffplayer->pipeline) { ffpipeline_set_volume(mp->ffplayer->pipeline, left, right); } pthread_mutex_unlock(&mp->mutex); MPTRACE("ijkmp_android_set_volume(%f, %f)=void", left, right); } int ijkmp_android_get_audio_session_id(JNIEnv *env, IjkMediaPlayer *mp) { int audio_session_id = 0; if (!mp) return audio_session_id; MPTRACE("%s()", __func__); pthread_mutex_lock(&mp->mutex); if (mp && mp->ffplayer && mp->ffplayer->aout) { audio_session_id = SDL_AoutGetAudioSessionId(mp->ffplayer->aout); } pthread_mutex_unlock(&mp->mutex); MPTRACE("%s()=%d", __func__, audio_session_id); return audio_session_id; } void ijkmp_android_set_mediacodec_select_callback(IjkMediaPlayer *mp, bool (*callback)(void *opaque, ijkmp_mediacodecinfo_context *mcc), void *opaque) { if (!mp) return; MPTRACE("ijkmp_android_set_mediacodec_select_callback()"); pthread_mutex_lock(&mp->mutex); if (mp && mp->ffplayer && mp->ffplayer->pipeline) { ffpipeline_set_mediacodec_select_callback(mp->ffplayer->pipeline, callback, opaque); } pthread_mutex_unlock(&mp->mutex); MPTRACE("ijkmp_android_set_mediacodec_select_callback()=void"); } ================================================ FILE: ijkmedia/ijkplayer/android/ijkplayer_android.h ================================================ /* * ijkplayer_android.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKPLAYER_ANDROID__IJKPLAYER_ANDROID_H #define IJKPLAYER_ANDROID__IJKPLAYER_ANDROID_H #include #include "ijkplayer_android_def.h" #include "../ijkplayer.h" typedef struct ijkmp_android_media_format_context { const char *mime_type; int profile; int level; } 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_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); #endif ================================================ FILE: ijkmedia/ijkplayer/android/ijkplayer_android_def.h ================================================ /* * ijkplayer_android_def.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKPLAYER_ANDROID__IJKPLAYER_ANDROID_DEF_H #define IJKPLAYER_ANDROID__IJKPLAYER_ANDROID_DEF_H /* * frameworks/av/include/media/mediaplayer.h */ // enum media_event_type { MEDIA_NOP = 0, // interface test message MEDIA_PREPARED = 1, MEDIA_PLAYBACK_COMPLETE = 2, MEDIA_BUFFERING_UPDATE = 3, // arg1 = percentage, arg2 = cached duration MEDIA_SEEK_COMPLETE = 4, MEDIA_SET_VIDEO_SIZE = 5, // arg1 = width, arg2 = height MEDIA_GET_IMG_STATE = 6, // arg1 = timestamp, arg2 = result code, obj = file name MEDIA_TIMED_TEXT = 99, // not supported yet MEDIA_ERROR = 100, // arg1, arg2 MEDIA_INFO = 200, // arg1, arg2 MEDIA_SET_VIDEO_SAR = 10001, // arg1 = sar.num, arg2 = sar.den }; // Generic error codes for the media player framework. Errors are fatal, the // playback must abort. // // Errors are communicated back to the client using the // MediaPlayerListener::notify method defined below. // In this situation, 'notify' is invoked with the following: // 'msg' is set to MEDIA_ERROR. // 'ext1' should be a value from the enum media_error_type. // 'ext2' contains an implementation dependant error code to provide // more details. Should default to 0 when not used. // // The codes are distributed as follow: // 0xx: Reserved // 1xx: Android Player errors. Something went wrong inside the MediaPlayer. // 2xx: Media errors (e.g Codec not supported). There is a problem with the // media itself. // 3xx: Runtime errors. Some extraordinary condition arose making the playback // impossible. // enum media_error_type { // 0xx MEDIA_ERROR_UNKNOWN = 1, // 1xx MEDIA_ERROR_SERVER_DIED = 100, // 2xx MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200, // 3xx // -xx MEDIA_ERROR_IO = -1004, MEDIA_ERROR_MALFORMED = -1007, MEDIA_ERROR_UNSUPPORTED = -1010, MEDIA_ERROR_TIMED_OUT = -110, MEDIA_ERROR_IJK_PLAYER = -10000, }; // Info and warning codes for the media player framework. These are non fatal, // the playback is going on but there might be some user visible issues. // // Info and warning messages are communicated back to the client using the // MediaPlayerListener::notify method defined below. In this situation, // 'notify' is invoked with the following: // 'msg' is set to MEDIA_INFO. // 'ext1' should be a value from the enum media_info_type. // 'ext2' contains an implementation dependant info code to provide // more details. Should default to 0 when not used. // // The codes are distributed as follow: // 0xx: Reserved // 7xx: Android Player info/warning (e.g player lagging behind.) // 8xx: Media info/warning (e.g media badly interleaved.) // enum media_info_type { // 0xx MEDIA_INFO_UNKNOWN = 1, // The player was started because it was used as the next player for another // player, which just completed playback MEDIA_INFO_STARTED_AS_NEXT = 2, // The player just pushed the very first video frame for rendering MEDIA_INFO_VIDEO_RENDERING_START = 3, // 7xx // The video is too complex for the decoder: it can't decode frames fast // enough. Possibly only the audio plays fine at this stage. MEDIA_INFO_VIDEO_TRACK_LAGGING = 700, // MediaPlayer is temporarily pausing playback internally in order to // buffer more data. MEDIA_INFO_BUFFERING_START = 701, // MediaPlayer is resuming playback after filling buffers. MEDIA_INFO_BUFFERING_END = 702, // Bandwidth in recent past MEDIA_INFO_NETWORK_BANDWIDTH = 703, // 8xx // Bad interleaving means that a media has been improperly interleaved or not // interleaved at all, e.g has all the video samples first then all the audio // ones. Video is playing but a lot of disk seek may be happening. MEDIA_INFO_BAD_INTERLEAVING = 800, // The media is not seekable (e.g live stream). MEDIA_INFO_NOT_SEEKABLE = 801, // New media metadata is available. MEDIA_INFO_METADATA_UPDATE = 802, //9xx MEDIA_INFO_TIMED_TEXT_ERROR = 900, //100xx MEDIA_INFO_VIDEO_ROTATION_CHANGED = 10001, MEDIA_INFO_AUDIO_RENDERING_START = 10002, MEDIA_INFO_AUDIO_DECODED_START = 10003, MEDIA_INFO_VIDEO_DECODED_START = 10004, MEDIA_INFO_OPEN_INPUT = 10005, MEDIA_INFO_FIND_STREAM_INFO = 10006, MEDIA_INFO_COMPONENT_OPEN = 10007, MEDIA_INFO_VIDEO_SEEK_RENDERING_START = 10008, MEDIA_INFO_AUDIO_SEEK_RENDERING_START = 10009, MEDIA_INFO_MEDIA_ACCURATE_SEEK_COMPLETE = 10100, }; typedef struct ijkmp_mediacodecinfo_context { char mime_type[128]; //< in int profile; //< in int level; //< in char codec_name[128]; //< out } ijkmp_mediacodecinfo_context; #endif ================================================ FILE: ijkmedia/ijkplayer/android/ijkplayer_jni.c ================================================ /* * ijkplayer_jni.c * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; 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 "j4a/class/java/util/ArrayList.h" #include "j4a/class/android/os/Bundle.h" #include "j4a/class/tv/danmaku/ijk/media/player/IjkMediaPlayer.h" #include "j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.h" #include "j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.h" #include "ijksdl/ijksdl_log.h" #include "../ff_ffplay.h" #include "ffmpeg_api_jni.h" #include "ijkplayer_android_def.h" #include "ijkplayer_android.h" #include "ijksdl/android/ijksdl_android_jni.h" #include "ijksdl/android/ijksdl_codec_android_mediadef.h" #include "ijkavformat/ijkavformat.h" #define JNI_MODULE_PACKAGE "tv/danmaku/ijk/media/player" #define JNI_CLASS_IJKPLAYER "tv/danmaku/ijk/media/player/IjkMediaPlayer" #define JNI_IJK_MEDIA_EXCEPTION "tv/danmaku/ijk/media/player/exceptions/IjkMediaException" #define IJK_CHECK_MPRET_GOTO(retval, env, label) \ JNI_CHECK_GOTO((retval != EIJK_INVALID_STATE), env, "java/lang/IllegalStateException", NULL, label); \ JNI_CHECK_GOTO((retval != EIJK_OUT_OF_MEMORY), env, "java/lang/OutOfMemoryError", NULL, label); \ JNI_CHECK_GOTO((retval == 0), env, JNI_IJK_MEDIA_EXCEPTION, NULL, label); static JavaVM* g_jvm; typedef struct player_fields_t { pthread_mutex_t mutex; jclass clazz; } player_fields_t; static player_fields_t g_clazz; static int inject_callback(void *opaque, int type, void *data, size_t data_size); static bool mediacodec_select_callback(void *opaque, ijkmp_mediacodecinfo_context *mcc); static IjkMediaPlayer *jni_get_media_player(JNIEnv* env, jobject thiz) { pthread_mutex_lock(&g_clazz.mutex); IjkMediaPlayer *mp = (IjkMediaPlayer *) (intptr_t) J4AC_IjkMediaPlayer__mNativeMediaPlayer__get__catchAll(env, thiz); if (mp) { ijkmp_inc_ref(mp); } pthread_mutex_unlock(&g_clazz.mutex); return mp; } static IjkMediaPlayer *jni_set_media_player(JNIEnv* env, jobject thiz, IjkMediaPlayer *mp) { pthread_mutex_lock(&g_clazz.mutex); IjkMediaPlayer *old = (IjkMediaPlayer*) (intptr_t) J4AC_IjkMediaPlayer__mNativeMediaPlayer__get__catchAll(env, thiz); if (mp) { ijkmp_inc_ref(mp); } J4AC_IjkMediaPlayer__mNativeMediaPlayer__set__catchAll(env, thiz, (intptr_t) mp); pthread_mutex_unlock(&g_clazz.mutex); // NOTE: ijkmp_dec_ref may block thread if (old != NULL ) { ijkmp_dec_ref_p(&old); } return old; } static int64_t jni_set_media_data_source(JNIEnv* env, jobject thiz, jobject media_data_source) { int64_t nativeMediaDataSource = 0; pthread_mutex_lock(&g_clazz.mutex); jobject old = (jobject) (intptr_t) J4AC_IjkMediaPlayer__mNativeMediaDataSource__get__catchAll(env, thiz); if (old) { J4AC_IMediaDataSource__close__catchAll(env, old); J4A_DeleteGlobalRef__p(env, &old); J4AC_IjkMediaPlayer__mNativeMediaDataSource__set__catchAll(env, thiz, 0); } if (media_data_source) { jobject global_media_data_source = (*env)->NewGlobalRef(env, media_data_source); if (J4A_ExceptionCheck__catchAll(env) || !global_media_data_source) goto fail; nativeMediaDataSource = (int64_t) (intptr_t) global_media_data_source; J4AC_IjkMediaPlayer__mNativeMediaDataSource__set__catchAll(env, thiz, (jlong) nativeMediaDataSource); } fail: pthread_mutex_unlock(&g_clazz.mutex); return nativeMediaDataSource; } static int64_t jni_set_ijkio_androidio(JNIEnv* env, jobject thiz, jobject ijk_io) { int64_t nativeAndroidIO = 0; pthread_mutex_lock(&g_clazz.mutex); jobject old = (jobject) (intptr_t) J4AC_IjkMediaPlayer__mNativeAndroidIO__get__catchAll(env, thiz); if (old) { J4AC_IAndroidIO__close__catchAll(env, old); J4A_DeleteGlobalRef__p(env, &old); J4AC_IjkMediaPlayer__mNativeAndroidIO__set__catchAll(env, thiz, 0); } if (ijk_io) { jobject global_ijkio_androidio = (*env)->NewGlobalRef(env, ijk_io); if (J4A_ExceptionCheck__catchAll(env) || !global_ijkio_androidio) goto fail; nativeAndroidIO = (int64_t) (intptr_t) global_ijkio_androidio; J4AC_IjkMediaPlayer__mNativeAndroidIO__set__catchAll(env, thiz, (jlong) nativeAndroidIO); } fail: pthread_mutex_unlock(&g_clazz.mutex); return nativeAndroidIO; } static int message_loop(void *arg); static void IjkMediaPlayer_setDataSourceAndHeaders( JNIEnv *env, jobject thiz, jstring path, jobjectArray keys, jobjectArray values) { MPTRACE("%s\n", __func__); int retval = 0; const char *c_path = NULL; IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(path, env, "java/lang/IllegalArgumentException", "mpjni: setDataSource: null path", LABEL_RETURN); JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: setDataSource: null mp", LABEL_RETURN); c_path = (*env)->GetStringUTFChars(env, path, NULL ); JNI_CHECK_GOTO(c_path, env, "java/lang/OutOfMemoryError", "mpjni: setDataSource: path.string oom", LABEL_RETURN); ALOGV("setDataSource: path %s", c_path); retval = ijkmp_set_data_source(mp, c_path); (*env)->ReleaseStringUTFChars(env, path, c_path); IJK_CHECK_MPRET_GOTO(retval, env, LABEL_RETURN); LABEL_RETURN: ijkmp_dec_ref_p(&mp); } static void IjkMediaPlayer_setDataSourceFd(JNIEnv *env, jobject thiz, jint fd) { MPTRACE("%s\n", __func__); int retval = 0; int dupFd = 0; char uri[128]; IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(fd > 0, env, "java/lang/IllegalArgumentException", "mpjni: setDataSourceFd: null fd", LABEL_RETURN); JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: setDataSourceFd: null mp", LABEL_RETURN); dupFd = dup(fd); ALOGV("setDataSourceFd: dup(%d)=%d\n", fd, dupFd); snprintf(uri, sizeof(uri), "pipe:%d", dupFd); retval = ijkmp_set_data_source(mp, uri); IJK_CHECK_MPRET_GOTO(retval, env, LABEL_RETURN); LABEL_RETURN: ijkmp_dec_ref_p(&mp); } static void IjkMediaPlayer_setDataSourceCallback(JNIEnv *env, jobject thiz, jobject callback) { MPTRACE("%s\n", __func__); int retval = 0; char uri[128]; int64_t nativeMediaDataSource = 0; IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(callback, env, "java/lang/IllegalArgumentException", "mpjni: setDataSourceCallback: null fd", LABEL_RETURN); JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: setDataSourceCallback: null mp", LABEL_RETURN); nativeMediaDataSource = jni_set_media_data_source(env, thiz, callback); JNI_CHECK_GOTO(nativeMediaDataSource, env, "java/lang/IllegalStateException", "mpjni: jni_set_media_data_source: NewGlobalRef", LABEL_RETURN); ALOGV("setDataSourceCallback: %"PRId64"\n", nativeMediaDataSource); snprintf(uri, sizeof(uri), "ijkmediadatasource:%"PRId64, nativeMediaDataSource); retval = ijkmp_set_data_source(mp, uri); IJK_CHECK_MPRET_GOTO(retval, env, LABEL_RETURN); LABEL_RETURN: ijkmp_dec_ref_p(&mp); } static void IjkMediaPlayer_setAndroidIOCallback(JNIEnv *env, jobject thiz, jobject callback) { MPTRACE("%s\n", __func__); int64_t nativeAndroidIO = 0; IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(callback, env, "java/lang/IllegalArgumentException", "mpjni: setAndroidIOCallback: null fd", LABEL_RETURN); JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: setAndroidIOCallback: null mp", LABEL_RETURN); nativeAndroidIO = jni_set_ijkio_androidio(env, thiz, callback); JNI_CHECK_GOTO(nativeAndroidIO, env, "java/lang/IllegalStateException", "mpjni: jni_set_ijkio_androidio: NewGlobalRef", LABEL_RETURN); ijkmp_set_option_int(mp, FFP_OPT_CATEGORY_FORMAT, "androidio-inject-callback", nativeAndroidIO); LABEL_RETURN: ijkmp_dec_ref_p(&mp); } static void IjkMediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface) { 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); LABEL_RETURN: ijkmp_dec_ref_p(&mp); return; } static void IjkMediaPlayer_prepareAsync(JNIEnv *env, jobject thiz) { MPTRACE("%s\n", __func__); int retval = 0; IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: prepareAsync: null mp", LABEL_RETURN); retval = ijkmp_prepare_async(mp); IJK_CHECK_MPRET_GOTO(retval, env, LABEL_RETURN); LABEL_RETURN: ijkmp_dec_ref_p(&mp); } static void IjkMediaPlayer_start(JNIEnv *env, jobject thiz) { MPTRACE("%s\n", __func__); IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: start: null mp", LABEL_RETURN); ijkmp_start(mp); LABEL_RETURN: ijkmp_dec_ref_p(&mp); } static void IjkMediaPlayer_stop(JNIEnv *env, jobject thiz) { IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: stop: null mp", LABEL_RETURN); ijkmp_stop(mp); LABEL_RETURN: ijkmp_dec_ref_p(&mp); } static void IjkMediaPlayer_pause(JNIEnv *env, jobject thiz) { IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: pause: null mp", LABEL_RETURN); ijkmp_pause(mp); LABEL_RETURN: ijkmp_dec_ref_p(&mp); } static void IjkMediaPlayer_seekTo(JNIEnv *env, jobject thiz, jlong msec) { MPTRACE("%s\n", __func__); IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: seekTo: null mp", LABEL_RETURN); ijkmp_seek_to(mp, msec); LABEL_RETURN: ijkmp_dec_ref_p(&mp); } static jboolean IjkMediaPlayer_isPlaying(JNIEnv *env, jobject thiz) { jboolean retval = JNI_FALSE; IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, NULL, "mpjni: isPlaying: null mp", LABEL_RETURN); retval = ijkmp_is_playing(mp) ? JNI_TRUE : JNI_FALSE; LABEL_RETURN: ijkmp_dec_ref_p(&mp); return retval; } static jlong IjkMediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz) { jlong retval = 0; IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, NULL, "mpjni: getCurrentPosition: null mp", LABEL_RETURN); retval = ijkmp_get_current_position(mp); LABEL_RETURN: ijkmp_dec_ref_p(&mp); return retval; } static jlong IjkMediaPlayer_getDuration(JNIEnv *env, jobject thiz) { jlong retval = 0; IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, NULL, "mpjni: getDuration: null mp", LABEL_RETURN); retval = ijkmp_get_duration(mp); LABEL_RETURN: ijkmp_dec_ref_p(&mp); return retval; } static void IjkMediaPlayer_release(JNIEnv *env, jobject thiz) { MPTRACE("%s\n", __func__); IjkMediaPlayer *mp = jni_get_media_player(env, thiz); if (!mp) return; ijkmp_android_set_surface(env, mp, NULL); // explicit shutdown mp, in case it is not the last mp-ref here ijkmp_shutdown(mp); //only delete weak_thiz at release jobject weak_thiz = (jobject) ijkmp_set_weak_thiz(mp, NULL ); (*env)->DeleteGlobalRef(env, weak_thiz); jni_set_media_player(env, thiz, NULL); jni_set_media_data_source(env, thiz, NULL); ijkmp_dec_ref_p(&mp); } static void IjkMediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this); static void IjkMediaPlayer_reset(JNIEnv *env, jobject thiz) { MPTRACE("%s\n", __func__); IjkMediaPlayer *mp = jni_get_media_player(env, thiz); if (!mp) return; jobject weak_thiz = (jobject) ijkmp_set_weak_thiz(mp, NULL ); IjkMediaPlayer_release(env, thiz); IjkMediaPlayer_native_setup(env, thiz, weak_thiz); ijkmp_dec_ref_p(&mp); } static void IjkMediaPlayer_setLoopCount(JNIEnv *env, jobject thiz, jint loop_count) { MPTRACE("%s\n", __func__); IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, NULL, "mpjni: setLoopCount: null mp", LABEL_RETURN); ijkmp_set_loop(mp, loop_count); LABEL_RETURN: ijkmp_dec_ref_p(&mp); } static jint IjkMediaPlayer_getLoopCount(JNIEnv *env, jobject thiz) { jint loop_count = 1; MPTRACE("%s\n", __func__); IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, NULL, "mpjni: getLoopCount: null mp", LABEL_RETURN); loop_count = ijkmp_get_loop(mp); LABEL_RETURN: ijkmp_dec_ref_p(&mp); return loop_count; } static jfloat ijkMediaPlayer_getPropertyFloat(JNIEnv *env, jobject thiz, jint id, jfloat default_value) { jfloat value = default_value; IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, NULL, "mpjni: getPropertyFloat: null mp", LABEL_RETURN); value = ijkmp_get_property_float(mp, id, default_value); LABEL_RETURN: ijkmp_dec_ref_p(&mp); return value; } static void ijkMediaPlayer_setPropertyFloat(JNIEnv *env, jobject thiz, jint id, jfloat value) { IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, NULL, "mpjni: setPropertyFloat: null mp", LABEL_RETURN); ijkmp_set_property_float(mp, id, value); LABEL_RETURN: ijkmp_dec_ref_p(&mp); return; } static jlong ijkMediaPlayer_getPropertyLong(JNIEnv *env, jobject thiz, jint id, jlong default_value) { jlong value = default_value; IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, NULL, "mpjni: getPropertyLong: null mp", LABEL_RETURN); value = ijkmp_get_property_int64(mp, id, default_value); LABEL_RETURN: ijkmp_dec_ref_p(&mp); return value; } static void ijkMediaPlayer_setPropertyLong(JNIEnv *env, jobject thiz, jint id, jlong value) { IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, NULL, "mpjni: setPropertyLong: null mp", LABEL_RETURN); ijkmp_set_property_int64(mp, id, value); LABEL_RETURN: ijkmp_dec_ref_p(&mp); return; } static void ijkMediaPlayer_setStreamSelected(JNIEnv *env, jobject thiz, jint stream, jboolean selected) { IjkMediaPlayer *mp = jni_get_media_player(env, thiz); int ret = 0; JNI_CHECK_GOTO(mp, env, NULL, "mpjni: setStreamSelected: null mp", LABEL_RETURN); ret = ijkmp_set_stream_selected(mp, stream, selected); if (ret < 0) { ALOGE("failed to %s %d", selected ? "select" : "deselect", stream); goto LABEL_RETURN; } LABEL_RETURN: ijkmp_dec_ref_p(&mp); return; } static void IjkMediaPlayer_setVolume(JNIEnv *env, jobject thiz, jfloat leftVolume, jfloat rightVolume) { MPTRACE("%s\n", __func__); IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, NULL, "mpjni: setVolume: null mp", LABEL_RETURN); ijkmp_android_set_volume(env, mp, leftVolume, rightVolume); LABEL_RETURN: ijkmp_dec_ref_p(&mp); } static jint IjkMediaPlayer_getAudioSessionId(JNIEnv *env, jobject thiz) { jint audio_session_id = 0; MPTRACE("%s\n", __func__); IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, NULL, "mpjni: getAudioSessionId: null mp", LABEL_RETURN); audio_session_id = ijkmp_android_get_audio_session_id(env, mp); LABEL_RETURN: ijkmp_dec_ref_p(&mp); return audio_session_id; } static void IjkMediaPlayer_setOption(JNIEnv *env, jobject thiz, jint category, jobject name, jobject value) { MPTRACE("%s\n", __func__); IjkMediaPlayer *mp = jni_get_media_player(env, thiz); const char *c_name = NULL; const char *c_value = NULL; JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: setOption: null mp", LABEL_RETURN); if (!name) { goto LABEL_RETURN; } c_name = (*env)->GetStringUTFChars(env, name, NULL ); JNI_CHECK_GOTO(c_name, env, "java/lang/OutOfMemoryError", "mpjni: setOption: name.string oom", LABEL_RETURN); JNI_CHECK_GOTO(mp, env, NULL, "mpjni: IjkMediaPlayer_setOption: null name", LABEL_RETURN); if (value) { c_value = (*env)->GetStringUTFChars(env, value, NULL ); JNI_CHECK_GOTO(c_name, env, "java/lang/OutOfMemoryError", "mpjni: setOption: name.string oom", LABEL_RETURN); } ijkmp_set_option(mp, category, c_name, c_value); LABEL_RETURN: if (c_name) (*env)->ReleaseStringUTFChars(env, name, c_name); if (c_value) (*env)->ReleaseStringUTFChars(env, value, c_value); ijkmp_dec_ref_p(&mp); } static void IjkMediaPlayer_setOptionLong(JNIEnv *env, jobject thiz, jint category, jobject name, jlong value) { MPTRACE("%s\n", __func__); IjkMediaPlayer *mp = jni_get_media_player(env, thiz); const char *c_name = NULL; JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: setOptionLong: null mp", LABEL_RETURN); c_name = (*env)->GetStringUTFChars(env, name, NULL ); JNI_CHECK_GOTO(c_name, env, "java/lang/OutOfMemoryError", "mpjni: setOptionLong: name.string oom", LABEL_RETURN); ijkmp_set_option_int(mp, category, c_name, value); LABEL_RETURN: if (c_name) (*env)->ReleaseStringUTFChars(env, name, c_name); ijkmp_dec_ref_p(&mp); } static jstring IjkMediaPlayer_getColorFormatName(JNIEnv *env, jclass clazz, jint mediaCodecColorFormat) { const char *codec_name = SDL_AMediaCodec_getColorFormatName(mediaCodecColorFormat); if (!codec_name) return NULL ; return (*env)->NewStringUTF(env, codec_name); } static jstring IjkMediaPlayer_getVideoCodecInfo(JNIEnv *env, jobject thiz) { MPTRACE("%s\n", __func__); jstring jcodec_info = NULL; int ret = 0; char *codec_info = NULL; IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: getVideoCodecInfo: null mp", LABEL_RETURN); ret = ijkmp_get_video_codec_info(mp, &codec_info); if (ret < 0 || !codec_info) goto LABEL_RETURN; jcodec_info = (*env)->NewStringUTF(env, codec_info); LABEL_RETURN: if (codec_info) free(codec_info); ijkmp_dec_ref_p(&mp); return jcodec_info; } static jstring IjkMediaPlayer_getAudioCodecInfo(JNIEnv *env, jobject thiz) { MPTRACE("%s\n", __func__); jstring jcodec_info = NULL; int ret = 0; char *codec_info = NULL; IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: getAudioCodecInfo: null mp", LABEL_RETURN); ret = ijkmp_get_audio_codec_info(mp, &codec_info); if (ret < 0 || !codec_info) goto LABEL_RETURN; jcodec_info = (*env)->NewStringUTF(env, codec_info); LABEL_RETURN: if (codec_info) free(codec_info); ijkmp_dec_ref_p(&mp); return jcodec_info; } inline static void fillMetaInternal(JNIEnv *env, jobject jbundle, IjkMediaMeta *meta, const char *key, const char *default_value) { const char *value = ijkmeta_get_string_l(meta, key); if (value == NULL ) value = default_value; J4AC_Bundle__putString__withCString__catchAll(env, jbundle, key, value); } static jobject IjkMediaPlayer_getMediaMeta(JNIEnv *env, jobject thiz) { MPTRACE("%s\n", __func__); bool is_locked = false; jobject jret_bundle = NULL; jobject jlocal_bundle = NULL; jobject jstream_bundle = NULL; jobject jarray_list = NULL; IjkMediaMeta *meta = NULL; IjkMediaPlayer *mp = jni_get_media_player(env, thiz); JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: getMediaMeta: null mp", LABEL_RETURN); meta = ijkmp_get_meta_l(mp); if (!meta) goto LABEL_RETURN; ijkmeta_lock(meta); is_locked = true; jlocal_bundle = J4AC_Bundle__Bundle(env); if (J4A_ExceptionCheck__throwAny(env)) { goto LABEL_RETURN; } fillMetaInternal(env, jlocal_bundle, meta, IJKM_KEY_FORMAT, NULL ); fillMetaInternal(env, jlocal_bundle, meta, IJKM_KEY_DURATION_US, NULL ); fillMetaInternal(env, jlocal_bundle, meta, IJKM_KEY_START_US, NULL ); fillMetaInternal(env, jlocal_bundle, meta, IJKM_KEY_BITRATE, NULL ); fillMetaInternal(env, jlocal_bundle, meta, IJKM_KEY_VIDEO_STREAM, "-1"); fillMetaInternal(env, jlocal_bundle, meta, IJKM_KEY_AUDIO_STREAM, "-1"); fillMetaInternal(env, jlocal_bundle, meta, IJKM_KEY_TIMEDTEXT_STREAM, "-1"); jarray_list = J4AC_ArrayList__ArrayList(env); if (J4A_ExceptionCheck__throwAny(env)) { goto LABEL_RETURN; } size_t count = ijkmeta_get_children_count_l(meta); for (size_t i = 0; i < count; ++i) { IjkMediaMeta *streamRawMeta = ijkmeta_get_child_l(meta, i); if (streamRawMeta) { jstream_bundle = J4AC_Bundle__Bundle(env); if (J4A_ExceptionCheck__throwAny(env)) { goto LABEL_RETURN; } fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_TYPE, IJKM_VAL_TYPE__UNKNOWN); fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_LANGUAGE, NULL); const char *type = ijkmeta_get_string_l(streamRawMeta, IJKM_KEY_TYPE); if (type) { fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_CODEC_NAME, NULL ); fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_CODEC_PROFILE, NULL ); fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_CODEC_LEVEL, NULL ); fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_CODEC_LONG_NAME, NULL ); fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_CODEC_PIXEL_FORMAT, NULL ); fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_BITRATE, NULL ); fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_CODEC_PROFILE_ID, NULL ); if (0 == strcmp(type, IJKM_VAL_TYPE__VIDEO)) { fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_WIDTH, NULL ); fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_HEIGHT, NULL ); fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_FPS_NUM, NULL ); fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_FPS_DEN, NULL ); fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_TBR_NUM, NULL ); fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_TBR_DEN, NULL ); fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_SAR_NUM, NULL ); fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_SAR_DEN, NULL ); } else if (0 == strcmp(type, IJKM_VAL_TYPE__AUDIO)) { fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_SAMPLE_RATE, NULL ); fillMetaInternal(env, jstream_bundle, streamRawMeta, IJKM_KEY_CHANNEL_LAYOUT, NULL ); } J4AC_ArrayList__add(env, jarray_list, jstream_bundle); if (J4A_ExceptionCheck__throwAny(env)) { goto LABEL_RETURN; } } SDL_JNI_DeleteLocalRefP(env, &jstream_bundle); } } J4AC_Bundle__putParcelableArrayList__withCString__catchAll(env, jlocal_bundle, IJKM_KEY_STREAMS, jarray_list); jret_bundle = jlocal_bundle; jlocal_bundle = NULL; LABEL_RETURN: if (is_locked && meta) ijkmeta_unlock(meta); SDL_JNI_DeleteLocalRefP(env, &jstream_bundle); SDL_JNI_DeleteLocalRefP(env, &jlocal_bundle); SDL_JNI_DeleteLocalRefP(env, &jarray_list); ijkmp_dec_ref_p(&mp); return jret_bundle; } static void IjkMediaPlayer_native_init(JNIEnv *env) { MPTRACE("%s\n", __func__); } static void IjkMediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) { MPTRACE("%s\n", __func__); IjkMediaPlayer *mp = ijkmp_android_create(message_loop); JNI_CHECK_GOTO(mp, env, "java/lang/OutOfMemoryError", "mpjni: native_setup: ijkmp_create() failed", LABEL_RETURN); jni_set_media_player(env, thiz, mp); ijkmp_set_weak_thiz(mp, (*env)->NewGlobalRef(env, weak_this)); ijkmp_set_inject_opaque(mp, ijkmp_get_weak_thiz(mp)); ijkmp_set_ijkio_inject_opaque(mp, ijkmp_get_weak_thiz(mp)); ijkmp_android_set_mediacodec_select_callback(mp, mediacodec_select_callback, ijkmp_get_weak_thiz(mp)); LABEL_RETURN: ijkmp_dec_ref_p(&mp); } static void IjkMediaPlayer_native_finalize(JNIEnv *env, jobject thiz, jobject name, jobject value) { MPTRACE("%s\n", __func__); IjkMediaPlayer_release(env, thiz); } // NOTE: support to be called from read_thread static int inject_callback(void *opaque, int what, void *data, size_t data_size) { JNIEnv *env = NULL; jobject jbundle = NULL; int ret = -1; SDL_JNI_SetupThreadEnv(&env); jobject weak_thiz = (jobject) opaque; if (weak_thiz == NULL ) goto fail; switch (what) { case AVAPP_CTRL_WILL_HTTP_OPEN: case AVAPP_CTRL_WILL_LIVE_OPEN: case AVAPP_CTRL_WILL_CONCAT_SEGMENT_OPEN: { AVAppIOControl *real_data = (AVAppIOControl *)data; real_data->is_handled = 0; jbundle = J4AC_Bundle__Bundle__catchAll(env); if (!jbundle) { ALOGE("%s: J4AC_Bundle__Bundle__catchAll failed for case %d\n", __func__, what); goto fail; } J4AC_Bundle__putString__withCString__catchAll(env, jbundle, "url", real_data->url); J4AC_Bundle__putInt__withCString__catchAll(env, jbundle, "segment_index", real_data->segment_index); J4AC_Bundle__putInt__withCString__catchAll(env, jbundle, "retry_counter", real_data->retry_counter); real_data->is_handled = J4AC_IjkMediaPlayer__onNativeInvoke(env, weak_thiz, what, jbundle); if (J4A_ExceptionCheck__catchAll(env)) { goto fail; } J4AC_Bundle__getString__withCString__asCBuffer(env, jbundle, "url", real_data->url, sizeof(real_data->url)); if (J4A_ExceptionCheck__catchAll(env)) { goto fail; } ret = 0; break; } case AVAPP_EVENT_WILL_HTTP_OPEN: case AVAPP_EVENT_DID_HTTP_OPEN: case AVAPP_EVENT_WILL_HTTP_SEEK: case AVAPP_EVENT_DID_HTTP_SEEK: { AVAppHttpEvent *real_data = (AVAppHttpEvent *) data; jbundle = J4AC_Bundle__Bundle__catchAll(env); if (!jbundle) { ALOGE("%s: J4AC_Bundle__Bundle__catchAll failed for case %d\n", __func__, what); goto fail; } J4AC_Bundle__putString__withCString__catchAll(env, jbundle, "url", real_data->url); J4AC_Bundle__putLong__withCString__catchAll(env, jbundle, "offset", real_data->offset); J4AC_Bundle__putInt__withCString__catchAll(env, jbundle, "error", real_data->error); J4AC_Bundle__putInt__withCString__catchAll(env, jbundle, "http_code", real_data->http_code); J4AC_Bundle__putLong__withCString__catchAll(env, jbundle, "file_size", real_data->filesize); J4AC_IjkMediaPlayer__onNativeInvoke(env, weak_thiz, what, jbundle); if (J4A_ExceptionCheck__catchAll(env)) goto fail; ret = 0; break; } case AVAPP_CTRL_DID_TCP_OPEN: case AVAPP_CTRL_WILL_TCP_OPEN: { AVAppTcpIOControl *real_data = (AVAppTcpIOControl *)data; jbundle = J4AC_Bundle__Bundle__catchAll(env); if (!jbundle) { ALOGE("%s: J4AC_Bundle__Bundle__catchAll failed for case %d\n", __func__, what); goto fail; } J4AC_Bundle__putInt__withCString__catchAll(env, jbundle, "error", real_data->error); J4AC_Bundle__putInt__withCString__catchAll(env, jbundle, "family", real_data->family); J4AC_Bundle__putString__withCString__catchAll(env, jbundle, "ip", real_data->ip); J4AC_Bundle__putInt__withCString__catchAll(env, jbundle, "port", real_data->port); J4AC_Bundle__putInt__withCString__catchAll(env, jbundle, "fd", real_data->fd); J4AC_IjkMediaPlayer__onNativeInvoke(env, weak_thiz, what, jbundle); if (J4A_ExceptionCheck__catchAll(env)) goto fail; ret = 0; break; } default: { ret = 0; } } fail: SDL_JNI_DeleteLocalRefP(env, &jbundle); return ret; } static bool mediacodec_select_callback(void *opaque, ijkmp_mediacodecinfo_context *mcc) { JNIEnv *env = NULL; jobject weak_this = (jobject) opaque; const char *found_codec_name = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SetupThreadEnv failed\n", __func__); return -1; } found_codec_name = J4AC_IjkMediaPlayer__onSelectCodec__withCString__asCBuffer(env, weak_this, mcc->mime_type, mcc->profile, mcc->level, mcc->codec_name, sizeof(mcc->codec_name)); if (J4A_ExceptionCheck__catchAll(env) || !found_codec_name) { ALOGE("%s: onSelectCodec failed\n", __func__); goto fail; } fail: return found_codec_name; } inline static void post_event(JNIEnv *env, jobject weak_this, int what, int arg1, int arg2) { // MPTRACE("post_event(%p, %p, %d, %d, %d)", (void*)env, (void*) weak_this, what, arg1, arg2); J4AC_IjkMediaPlayer__postEventFromNative(env, weak_this, what, arg1, arg2, NULL); // MPTRACE("post_event()=void"); } inline static void post_event2(JNIEnv *env, jobject weak_this, int what, int arg1, int arg2, jobject obj) { // MPTRACE("post_event2(%p, %p, %d, %d, %d, %p)", (void*)env, (void*) weak_this, what, arg1, arg2, (void*)obj); J4AC_IjkMediaPlayer__postEventFromNative(env, weak_this, what, arg1, arg2, obj); // MPTRACE("post_event2()=void"); } static void message_loop_n(JNIEnv *env, IjkMediaPlayer *mp) { jobject weak_thiz = (jobject) ijkmp_get_weak_thiz(mp); JNI_CHECK_GOTO(weak_thiz, env, NULL, "mpjni: message_loop_n: null weak_thiz", LABEL_RETURN); while (1) { AVMessage msg; int retval = ijkmp_get_msg(mp, &msg, 1); if (retval < 0) break; // block-get should never return 0 assert(retval > 0); switch (msg.what) { case FFP_MSG_FLUSH: MPTRACE("FFP_MSG_FLUSH:\n"); post_event(env, weak_thiz, MEDIA_NOP, 0, 0); break; case FFP_MSG_ERROR: MPTRACE("FFP_MSG_ERROR: %d\n", msg.arg1); post_event(env, weak_thiz, MEDIA_ERROR, MEDIA_ERROR_IJK_PLAYER, msg.arg1); break; case FFP_MSG_PREPARED: MPTRACE("FFP_MSG_PREPARED:\n"); post_event(env, weak_thiz, MEDIA_PREPARED, 0, 0); break; case FFP_MSG_COMPLETED: MPTRACE("FFP_MSG_COMPLETED:\n"); post_event(env, weak_thiz, MEDIA_PLAYBACK_COMPLETE, 0, 0); break; case FFP_MSG_VIDEO_SIZE_CHANGED: MPTRACE("FFP_MSG_VIDEO_SIZE_CHANGED: %d, %d\n", msg.arg1, msg.arg2); post_event(env, weak_thiz, MEDIA_SET_VIDEO_SIZE, msg.arg1, msg.arg2); break; case FFP_MSG_SAR_CHANGED: MPTRACE("FFP_MSG_SAR_CHANGED: %d, %d\n", msg.arg1, msg.arg2); post_event(env, weak_thiz, MEDIA_SET_VIDEO_SAR, msg.arg1, msg.arg2); break; case FFP_MSG_VIDEO_RENDERING_START: MPTRACE("FFP_MSG_VIDEO_RENDERING_START:\n"); post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_VIDEO_RENDERING_START, 0); break; case FFP_MSG_AUDIO_RENDERING_START: MPTRACE("FFP_MSG_AUDIO_RENDERING_START:\n"); post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_AUDIO_RENDERING_START, 0); break; case FFP_MSG_VIDEO_ROTATION_CHANGED: MPTRACE("FFP_MSG_VIDEO_ROTATION_CHANGED: %d\n", msg.arg1); post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_VIDEO_ROTATION_CHANGED, msg.arg1); break; case FFP_MSG_AUDIO_DECODED_START: MPTRACE("FFP_MSG_AUDIO_DECODED_START:\n"); post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_AUDIO_DECODED_START, 0); break; case FFP_MSG_VIDEO_DECODED_START: MPTRACE("FFP_MSG_VIDEO_DECODED_START:\n"); post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_VIDEO_DECODED_START, 0); break; case FFP_MSG_OPEN_INPUT: MPTRACE("FFP_MSG_OPEN_INPUT:\n"); post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_OPEN_INPUT, 0); break; case FFP_MSG_FIND_STREAM_INFO: MPTRACE("FFP_MSG_FIND_STREAM_INFO:\n"); post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_FIND_STREAM_INFO, 0); break; case FFP_MSG_COMPONENT_OPEN: MPTRACE("FFP_MSG_COMPONENT_OPEN:\n"); post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_COMPONENT_OPEN, 0); break; case FFP_MSG_BUFFERING_START: MPTRACE("FFP_MSG_BUFFERING_START:\n"); post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_BUFFERING_START, msg.arg1); break; case FFP_MSG_BUFFERING_END: MPTRACE("FFP_MSG_BUFFERING_END:\n"); post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_BUFFERING_END, msg.arg1); break; case FFP_MSG_BUFFERING_UPDATE: // MPTRACE("FFP_MSG_BUFFERING_UPDATE: %d, %d", msg.arg1, msg.arg2); post_event(env, weak_thiz, MEDIA_BUFFERING_UPDATE, msg.arg1, msg.arg2); break; case FFP_MSG_BUFFERING_BYTES_UPDATE: break; case FFP_MSG_BUFFERING_TIME_UPDATE: break; case FFP_MSG_SEEK_COMPLETE: MPTRACE("FFP_MSG_SEEK_COMPLETE:\n"); post_event(env, weak_thiz, MEDIA_SEEK_COMPLETE, 0, 0); break; case FFP_MSG_ACCURATE_SEEK_COMPLETE: MPTRACE("FFP_MSG_ACCURATE_SEEK_COMPLETE:\n"); post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_MEDIA_ACCURATE_SEEK_COMPLETE, msg.arg1); break; case FFP_MSG_PLAYBACK_STATE_CHANGED: break; case FFP_MSG_TIMED_TEXT: if (msg.obj) { jstring text = (*env)->NewStringUTF(env, (char *)msg.obj); post_event2(env, weak_thiz, MEDIA_TIMED_TEXT, 0, 0, text); J4A_DeleteLocalRef__p(env, &text); } else { post_event2(env, weak_thiz, MEDIA_TIMED_TEXT, 0, 0, NULL); } break; case FFP_MSG_GET_IMG_STATE: if (msg.obj) { jstring file_name = (*env)->NewStringUTF(env, (char *)msg.obj); post_event2(env, weak_thiz, MEDIA_GET_IMG_STATE, msg.arg1, msg.arg2, file_name); J4A_DeleteLocalRef__p(env, &file_name); } else { post_event2(env, weak_thiz, MEDIA_GET_IMG_STATE, msg.arg1, msg.arg2, NULL); } break; case FFP_MSG_VIDEO_SEEK_RENDERING_START: MPTRACE("FFP_MSG_VIDEO_SEEK_RENDERING_START:\n"); post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_VIDEO_SEEK_RENDERING_START, msg.arg1); break; case FFP_MSG_AUDIO_SEEK_RENDERING_START: MPTRACE("FFP_MSG_AUDIO_SEEK_RENDERING_START:\n"); post_event(env, weak_thiz, MEDIA_INFO, MEDIA_INFO_AUDIO_SEEK_RENDERING_START, msg.arg1); break; default: ALOGE("unknown FFP_MSG_xxx(%d)\n", msg.what); break; } msg_free_res(&msg); } LABEL_RETURN: ; } static int message_loop(void *arg) { MPTRACE("%s\n", __func__); JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SetupThreadEnv failed\n", __func__); return -1; } IjkMediaPlayer *mp = (IjkMediaPlayer*) arg; JNI_CHECK_GOTO(mp, env, NULL, "mpjni: native_message_loop: null mp", LABEL_RETURN); message_loop_n(env, mp); LABEL_RETURN: ijkmp_dec_ref_p(&mp); MPTRACE("message_loop exit"); return 0; } // ---------------------------------------------------------------------------- void monstartup(const char *libname); void moncleanup(void); static void IjkMediaPlayer_native_profileBegin(JNIEnv *env, jclass clazz, jstring libName) { MPTRACE("%s\n", __func__); const char *c_lib_name = NULL; static int s_monstartup = 0; if (!libName) return; if (s_monstartup) { ALOGW("monstartup already called\b"); return; } c_lib_name = (*env)->GetStringUTFChars(env, libName, NULL ); JNI_CHECK_GOTO(c_lib_name, env, "java/lang/OutOfMemoryError", "mpjni: monstartup: libName.string oom", LABEL_RETURN); s_monstartup = 1; monstartup(c_lib_name); ALOGD("monstartup: %s\n", c_lib_name); LABEL_RETURN: if (c_lib_name) (*env)->ReleaseStringUTFChars(env, libName, c_lib_name); } static void IjkMediaPlayer_native_profileEnd(JNIEnv *env, jclass clazz) { MPTRACE("%s\n", __func__); static int s_moncleanup = 0; if (s_moncleanup) { ALOGW("moncleanu already called\b"); return; } s_moncleanup = 1; moncleanup(); ALOGD("moncleanup\n"); } static void IjkMediaPlayer_native_setLogLevel(JNIEnv *env, jclass clazz, jint level) { MPTRACE("%s(%d)\n", __func__, level); ijkmp_global_set_log_level(level); ALOGD("moncleanup\n"); } static void IjkMediaPlayer_setFrameAtTime(JNIEnv *env, jobject thiz, jstring path, jlong start_time, jlong end_time, jint num, jint definition) { IjkMediaPlayer *mp = jni_get_media_player(env, thiz); const char *c_path = NULL; JNI_CHECK_GOTO(path, env, "java/lang/IllegalArgumentException", "mpjni: setFrameAtTime: null path", LABEL_RETURN); JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: setFrameAtTime: null mp", LABEL_RETURN); c_path = (*env)->GetStringUTFChars(env, path, NULL ); JNI_CHECK_GOTO(c_path, env, "java/lang/OutOfMemoryError", "mpjni: setFrameAtTime: path.string oom", LABEL_RETURN); ALOGV("setFrameAtTime: path %s", c_path); ijkmp_set_frame_at_time(mp, c_path, start_time, end_time, num, definition); (*env)->ReleaseStringUTFChars(env, path, c_path); LABEL_RETURN: ijkmp_dec_ref_p(&mp); return; } // ---------------------------------------------------------------------------- static JNINativeMethod g_methods[] = { { "_setDataSource", "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V", (void *) IjkMediaPlayer_setDataSourceAndHeaders }, { "_setDataSourceFd", "(I)V", (void *) IjkMediaPlayer_setDataSourceFd }, { "_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 }, { "_prepareAsync", "()V", (void *) IjkMediaPlayer_prepareAsync }, { "_start", "()V", (void *) IjkMediaPlayer_start }, { "_stop", "()V", (void *) IjkMediaPlayer_stop }, { "seekTo", "(J)V", (void *) IjkMediaPlayer_seekTo }, { "_pause", "()V", (void *) IjkMediaPlayer_pause }, { "isPlaying", "()Z", (void *) IjkMediaPlayer_isPlaying }, { "getCurrentPosition", "()J", (void *) IjkMediaPlayer_getCurrentPosition }, { "getDuration", "()J", (void *) IjkMediaPlayer_getDuration }, { "_release", "()V", (void *) IjkMediaPlayer_release }, { "_reset", "()V", (void *) IjkMediaPlayer_reset }, { "setVolume", "(FF)V", (void *) IjkMediaPlayer_setVolume }, { "getAudioSessionId", "()I", (void *) IjkMediaPlayer_getAudioSessionId }, { "native_init", "()V", (void *) IjkMediaPlayer_native_init }, { "native_setup", "(Ljava/lang/Object;)V", (void *) IjkMediaPlayer_native_setup }, { "native_finalize", "()V", (void *) IjkMediaPlayer_native_finalize }, { "_setOption", "(ILjava/lang/String;Ljava/lang/String;)V", (void *) IjkMediaPlayer_setOption }, { "_setOption", "(ILjava/lang/String;J)V", (void *) IjkMediaPlayer_setOptionLong }, { "_getColorFormatName", "(I)Ljava/lang/String;", (void *) IjkMediaPlayer_getColorFormatName }, { "_getVideoCodecInfo", "()Ljava/lang/String;", (void *) IjkMediaPlayer_getVideoCodecInfo }, { "_getAudioCodecInfo", "()Ljava/lang/String;", (void *) IjkMediaPlayer_getAudioCodecInfo }, { "_getMediaMeta", "()Landroid/os/Bundle;", (void *) IjkMediaPlayer_getMediaMeta }, { "_setLoopCount", "(I)V", (void *) IjkMediaPlayer_setLoopCount }, { "_getLoopCount", "()I", (void *) IjkMediaPlayer_getLoopCount }, { "_getPropertyFloat", "(IF)F", (void *) ijkMediaPlayer_getPropertyFloat }, { "_setPropertyFloat", "(IF)V", (void *) ijkMediaPlayer_setPropertyFloat }, { "_getPropertyLong", "(IJ)J", (void *) ijkMediaPlayer_getPropertyLong }, { "_setPropertyLong", "(IJ)V", (void *) ijkMediaPlayer_setPropertyLong }, { "_setStreamSelected", "(IZ)V", (void *) ijkMediaPlayer_setStreamSelected }, { "native_profileBegin", "(Ljava/lang/String;)V", (void *) IjkMediaPlayer_native_profileBegin }, { "native_profileEnd", "()V", (void *) IjkMediaPlayer_native_profileEnd }, { "native_setLogLevel", "(I)V", (void *) IjkMediaPlayer_native_setLogLevel }, { "_setFrameAtTime", "(Ljava/lang/String;JJII)V", (void *) IjkMediaPlayer_setFrameAtTime }, }; JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv* env = NULL; g_jvm = vm; if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) { return -1; } assert(env != NULL); pthread_mutex_init(&g_clazz.mutex, NULL ); // FindClass returns LocalReference IJK_FIND_JAVA_CLASS(env, g_clazz.clazz, JNI_CLASS_IJKPLAYER); (*env)->RegisterNatives(env, g_clazz.clazz, g_methods, NELEM(g_methods) ); ijkmp_global_init(); ijkmp_global_set_inject_callback(inject_callback); FFmpegApi_global_init(env); return JNI_VERSION_1_4; } JNIEXPORT void JNI_OnUnload(JavaVM *jvm, void *reserved) { ijkmp_global_uninit(); pthread_mutex_destroy(&g_clazz.mutex); } ================================================ FILE: ijkmedia/ijkplayer/android/pipeline/ffpipeline_android.c ================================================ /* * ffpipeline_android.c * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ffpipeline_android.h" #include #include "ffpipenode_android_mediacodec_vdec.h" #include "../../pipeline/ffpipenode_ffplay_vdec.h" #include "../../ff_ffplay.h" #include "ijksdl/android/ijksdl_android_jni.h" #include "ijksdl/android/ijksdl_android.h" static SDL_Class g_pipeline_class = { .name = "ffpipeline_android_media", }; typedef struct IJKFF_Pipeline_Opaque { FFPlayer *ffp; SDL_mutex *surface_mutex; jobject jsurface; volatile bool is_surface_need_reconfigure; bool (*mediacodec_select_callback)(void *opaque, ijkmp_mediacodecinfo_context *mcc); void *mediacodec_select_callback_opaque; SDL_Vout *weak_vout; float left_volume; float right_volume; } IJKFF_Pipeline_Opaque; static void func_destroy(IJKFF_Pipeline *pipeline) { IJKFF_Pipeline_Opaque *opaque = pipeline->opaque; JNIEnv *env = NULL; SDL_DestroyMutexP(&opaque->surface_mutex); if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("amediacodec-pipeline:destroy: SetupThreadEnv failed\n"); goto fail; } SDL_JNI_DeleteGlobalRefP(env, &opaque->jsurface); fail: return; } static IJKFF_Pipenode *func_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp) { IJKFF_Pipeline_Opaque *opaque = pipeline->opaque; IJKFF_Pipenode *node = NULL; if (ffp->mediacodec_all_videos || ffp->mediacodec_avc || ffp->mediacodec_hevc || ffp->mediacodec_mpeg2) node = ffpipenode_create_video_decoder_from_android_mediacodec(ffp, pipeline, opaque->weak_vout); if (!node) { node = ffpipenode_create_video_decoder_from_ffplay(ffp); } return node; } static SDL_Aout *func_open_audio_output(IJKFF_Pipeline *pipeline, FFPlayer *ffp) { SDL_Aout *aout = NULL; if (ffp->opensles) { aout = SDL_AoutAndroid_CreateForOpenSLES(); } else { aout = SDL_AoutAndroid_CreateForAudioTrack(); } if (aout) SDL_AoutSetStereoVolume(aout, pipeline->opaque->left_volume, pipeline->opaque->right_volume); return aout; } static IJKFF_Pipenode *func_init_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp) { IJKFF_Pipeline_Opaque *opaque = pipeline->opaque; IJKFF_Pipenode *node = NULL; if (ffp->mediacodec_all_videos || ffp->mediacodec_avc || ffp->mediacodec_hevc || ffp->mediacodec_mpeg2) node = ffpipenode_init_decoder_from_android_mediacodec(ffp, pipeline, opaque->weak_vout); return node; } static int func_config_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp) { IJKFF_Pipeline_Opaque *opaque = pipeline->opaque; int ret = NULL; if (ffp->node_vdec) { ret = ffpipenode_config_from_android_mediacodec(ffp, pipeline, opaque->weak_vout, ffp->node_vdec); } return ret; } inline static bool check_ffpipeline(IJKFF_Pipeline* pipeline, const char *func_name) { if (!pipeline || !pipeline->opaque || !pipeline->opaque_class) { ALOGE("%s.%s: invalid pipeline\n", pipeline->opaque_class->name, func_name); return false; } if (pipeline->opaque_class != &g_pipeline_class) { ALOGE("%s.%s: unsupported method\n", pipeline->opaque_class->name, func_name); return false; } return true; } IJKFF_Pipeline *ffpipeline_create_from_android(FFPlayer *ffp) { ALOGD("ffpipeline_create_from_android()\n"); IJKFF_Pipeline *pipeline = ffpipeline_alloc(&g_pipeline_class, sizeof(IJKFF_Pipeline_Opaque)); if (!pipeline) return pipeline; IJKFF_Pipeline_Opaque *opaque = pipeline->opaque; opaque->ffp = ffp; opaque->surface_mutex = SDL_CreateMutex(); opaque->left_volume = 1.0f; opaque->right_volume = 1.0f; if (!opaque->surface_mutex) { ALOGE("ffpipeline-android:create SDL_CreateMutex failed\n"); goto fail; } pipeline->func_destroy = func_destroy; pipeline->func_open_video_decoder = func_open_video_decoder; pipeline->func_open_audio_output = func_open_audio_output; pipeline->func_init_video_decoder = func_init_video_decoder; pipeline->func_config_video_decoder = func_config_video_decoder; return pipeline; fail: ffpipeline_free_p(&pipeline); return NULL; } int ffpipeline_lock_surface(IJKFF_Pipeline* pipeline) { IJKFF_Pipeline_Opaque *opaque = pipeline->opaque; return SDL_LockMutex(opaque->surface_mutex); } int ffpipeline_unlock_surface(IJKFF_Pipeline* pipeline) { IJKFF_Pipeline_Opaque *opaque = pipeline->opaque; return SDL_UnlockMutex(opaque->surface_mutex); } jobject ffpipeline_get_surface_as_global_ref_l(JNIEnv *env, IJKFF_Pipeline* pipeline) { if (!check_ffpipeline(pipeline, __func__)) return NULL; IJKFF_Pipeline_Opaque *opaque = pipeline->opaque; if (!opaque->surface_mutex) return NULL; jobject global_ref = NULL; if (opaque->jsurface) global_ref = (*env)->NewGlobalRef(env, opaque->jsurface); return global_ref; } jobject ffpipeline_get_surface_as_global_ref(JNIEnv *env, IJKFF_Pipeline* pipeline) { ffpipeline_lock_surface(pipeline); jobject new_surface = ffpipeline_get_surface_as_global_ref_l(env, pipeline); ffpipeline_unlock_surface(pipeline); return new_surface; } void ffpipeline_set_vout(IJKFF_Pipeline* pipeline, SDL_Vout *vout) { if (!check_ffpipeline(pipeline, __func__)) return; IJKFF_Pipeline_Opaque *opaque = pipeline->opaque; opaque->weak_vout = vout; } int ffpipeline_set_surface(JNIEnv *env, IJKFF_Pipeline* pipeline, jobject surface) { ALOGD("%s()\n", __func__); if (!check_ffpipeline(pipeline, __func__)) return -1; IJKFF_Pipeline_Opaque *opaque = pipeline->opaque; if (!opaque->surface_mutex) return -1; ffpipeline_lock_surface(pipeline); { jobject prev_surface = opaque->jsurface; if ((surface == prev_surface) || (surface && prev_surface && (*env)->IsSameObject(env, surface, prev_surface))) { // same object, no need to reconfigure } else { SDL_VoutAndroid_setAMediaCodec(opaque->weak_vout, NULL); if (surface) { opaque->jsurface = (*env)->NewGlobalRef(env, surface); } else { opaque->jsurface = NULL; } opaque->is_surface_need_reconfigure = true; if (prev_surface != NULL) { SDL_JNI_DeleteGlobalRefP(env, &prev_surface); } } } ffpipeline_unlock_surface(pipeline); return 0; } bool ffpipeline_is_surface_need_reconfigure_l(IJKFF_Pipeline* pipeline) { if (!check_ffpipeline(pipeline, __func__)) return false; return pipeline->opaque->is_surface_need_reconfigure; } void ffpipeline_set_surface_need_reconfigure_l(IJKFF_Pipeline* pipeline, bool need_reconfigure) { ALOGD("%s(%d)\n", __func__, (int)need_reconfigure); if (!check_ffpipeline(pipeline, __func__)) return; pipeline->opaque->is_surface_need_reconfigure = need_reconfigure; } void ffpipeline_set_mediacodec_select_callback(IJKFF_Pipeline* pipeline, bool (*callback)(void *opaque, ijkmp_mediacodecinfo_context *mcc), void *opaque) { ALOGD("%s\n", __func__); if (!check_ffpipeline(pipeline, __func__)) return; pipeline->opaque->mediacodec_select_callback = callback; pipeline->opaque->mediacodec_select_callback_opaque = opaque; } bool ffpipeline_select_mediacodec_l(IJKFF_Pipeline* pipeline, ijkmp_mediacodecinfo_context *mcc) { ALOGD("%s\n", __func__); if (!check_ffpipeline(pipeline, __func__)) return false; if (!mcc || !pipeline->opaque->mediacodec_select_callback) return false; return pipeline->opaque->mediacodec_select_callback(pipeline->opaque->mediacodec_select_callback_opaque, mcc); } void ffpipeline_set_volume(IJKFF_Pipeline* pipeline, float left, float right) { ALOGD("%s\n", __func__); if (!check_ffpipeline(pipeline, __func__)) return; IJKFF_Pipeline_Opaque *opaque = pipeline->opaque; opaque->left_volume = left; opaque->right_volume = right; if (opaque->ffp && opaque->ffp->aout) { SDL_AoutSetStereoVolume(opaque->ffp->aout, left, right); } } ================================================ FILE: ijkmedia/ijkplayer/android/pipeline/ffpipeline_android.h ================================================ /* * ffpipeline_android.h * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__FF_FFPIPELINE_ANDROID_H #define FFPLAY__FF_FFPIPELINE_ANDROID_H #include #include #include "../ijkplayer_android_def.h" #include "../../ff_ffpipeline.h" #include "ijksdl/ijksdl_vout.h" typedef struct FFPlayer FFPlayer; typedef struct IJKFF_Pipeline IJKFF_Pipeline; IJKFF_Pipeline *ffpipeline_create_from_android(FFPlayer *ffp); void ffpipeline_set_vout(IJKFF_Pipeline* pipeline, SDL_Vout *vout); int ffpipeline_set_surface(JNIEnv *env, IJKFF_Pipeline* pipeline, jobject surface); int ffpipeline_lock_surface(IJKFF_Pipeline* pipeline); int ffpipeline_unlock_surface(IJKFF_Pipeline* pipeline); jobject ffpipeline_get_surface_as_global_ref_l(JNIEnv *env, IJKFF_Pipeline* pipeline); jobject ffpipeline_get_surface_as_global_ref(JNIEnv *env, IJKFF_Pipeline* pipeline); bool ffpipeline_is_surface_need_reconfigure_l(IJKFF_Pipeline* pipeline); void ffpipeline_set_surface_need_reconfigure_l(IJKFF_Pipeline* pipeline, bool need_reconfigure); void ffpipeline_set_mediacodec_select_callback(IJKFF_Pipeline* pipeline, bool (*callback)(void *opaque, ijkmp_mediacodecinfo_context *mcc), void *opaque); bool ffpipeline_select_mediacodec_l(IJKFF_Pipeline* pipeline, ijkmp_mediacodecinfo_context *mcc); void ffpipeline_set_volume(IJKFF_Pipeline* pipeline, float left, float right); #endif ================================================ FILE: ijkmedia/ijkplayer/android/pipeline/ffpipenode_android_mediacodec_vdec.c ================================================ /* * ffpipenode_android_mediacodec_vdec.c * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ffpipenode_android_mediacodec_vdec.h" #include "ijksdl/android/ijksdl_android_jni.h" #include "ijksdl/android/ijksdl_codec_android_mediaformat_java.h" #include "ijksdl/android/ijksdl_codec_android_mediacodec_java.h" #include "ijksdl/android/ijksdl_codec_android_mediacodec_dummy.h" #include "ijksdl/android/ijksdl_vout_android_nativewindow.h" #include "ijksdl/android/ijksdl_vout_overlay_android_mediacodec.h" #include "ijkplayer/ff_ffpipenode.h" #include "ijkplayer/ff_ffplay.h" #include "ijkplayer/ff_ffplay_debug.h" #include "h264_nal.h" #include "hevc_nal.h" #include "mpeg4_esds.h" #include "ffpipeline_android.h" #define AMC_USE_AVBITSTREAM_FILTER 0 #ifndef AMCTRACE //#define AMCTRACE(...) #define AMCTRACE ALOGE #endif #define AMC_INPUT_TIMEOUT_US (100 * 1000) #define AMC_OUTPUT_TIMEOUT_US (100 * 1000) #define AMC_SYNC_INPUT_TIMEOUT_US (30 * 1000) #define AMC_SYNC_OUTPUT_TIMEOUT_US (30 * 1000) #define MAX_FAKE_FRAMES (2) #define ACODEC_RETRY -1 #define ACODEC_EXIT -2 typedef struct AMC_Buf_Out { int port; int acodec_serial; SDL_AMediaCodecBufferInfo info; double pts; } AMC_Buf_Out; typedef struct IJKFF_Pipenode_Opaque { FFPlayer *ffp; IJKFF_Pipeline *pipeline; Decoder *decoder; SDL_Vout *weak_vout; ijkmp_mediacodecinfo_context mcc; jobject jsurface; SDL_AMediaFormat *input_aformat; SDL_AMediaCodec *acodec; SDL_AMediaFormat *output_aformat; char acodec_name[128]; int frame_width; int frame_height; int frame_rotate_degrees; AVCodecContext *avctx; // not own AVCodecParameters *codecpar; AVBitStreamFilterContext *bsfc; // own #if AMC_USE_AVBITSTREAM_FILTER uint8_t *orig_extradata; int orig_extradata_size; #else size_t nal_size; #endif SDL_Thread _enqueue_thread; SDL_Thread *enqueue_thread; SDL_mutex *acodec_mutex; SDL_cond *acodec_cond; volatile bool acodec_flush_request; volatile bool acodec_reconfigure_request; SDL_mutex *acodec_first_dequeue_output_mutex; SDL_cond *acodec_first_dequeue_output_cond; volatile bool acodec_first_dequeue_output_request; bool aformat_need_recreate; SDL_mutex *any_input_mutex; SDL_cond *any_input_cond; int input_packet_count; int input_error_count; int output_error_count; bool quirk_reconfigure_with_new_codec; int n_buf_out; AMC_Buf_Out *amc_buf_out; int off_buf_out; double last_queued_pts; SDL_SpeedSampler sampler; volatile bool abort; } IJKFF_Pipenode_Opaque; static SDL_AMediaCodec *create_codec_l(JNIEnv *env, IJKFF_Pipenode *node) { IJKFF_Pipenode_Opaque *opaque = node->opaque; ijkmp_mediacodecinfo_context *mcc = &opaque->mcc; SDL_AMediaCodec *acodec = NULL; if (opaque->jsurface == NULL) { // we don't need real codec if we don't have a surface acodec = SDL_AMediaCodecDummy_create(); } else { acodec = SDL_AMediaCodecJava_createByCodecName(env, mcc->codec_name); if (acodec) { strncpy(opaque->acodec_name, mcc->codec_name, sizeof(opaque->acodec_name) / sizeof(*opaque->acodec_name)); opaque->acodec_name[sizeof(opaque->acodec_name) / sizeof(*opaque->acodec_name) - 1] = 0; } } #if 0 if (!acodec) acodec = SDL_AMediaCodecJava_createDecoderByType(env, mcc->mime_type); #endif if (acodec) { // QUIRK: always recreate MediaCodec for reconfigure opaque->quirk_reconfigure_with_new_codec = true; /*- if (0 == strncasecmp(mcc->codec_name, "OMX.TI.DUCATI1.", 15)) { opaque->quirk_reconfigure_with_new_codec = true; } */ /* delaying output makes it possible to correct frame order, hopefully */ if (0 == strncasecmp(mcc->codec_name, "OMX.TI.DUCATI1.", 15)) { /* this is the only acceptable value on Nexus S */ opaque->n_buf_out = 1; ALOGD("using buffered output for %s", mcc->codec_name); } } if (opaque->frame_rotate_degrees == 90 || opaque->frame_rotate_degrees == 270) { opaque->frame_width = opaque->codecpar->height; opaque->frame_height = opaque->codecpar->width; } else { opaque->frame_width = opaque->codecpar->width; opaque->frame_height = opaque->codecpar->height; } return acodec; } static int recreate_format_l(JNIEnv *env, IJKFF_Pipenode *node) { IJKFF_Pipenode_Opaque *opaque = node->opaque; FFPlayer *ffp = opaque->ffp; int rotate_degrees = 0; ALOGI("AMediaFormat: %s, %dx%d\n", opaque->mcc.mime_type, opaque->codecpar->width, opaque->codecpar->height); SDL_AMediaFormat_deleteP(&opaque->output_aformat); opaque->input_aformat = SDL_AMediaFormatJava_createVideoFormat(env, opaque->mcc.mime_type, opaque->codecpar->width, opaque->codecpar->height); if (opaque->codecpar->extradata && opaque->codecpar->extradata_size > 0) { if ((opaque->codecpar->codec_id == AV_CODEC_ID_H264 && opaque->codecpar->extradata[0] == 1) || (opaque->codecpar->codec_id == AV_CODEC_ID_HEVC && opaque->codecpar->extradata_size > 3 && (opaque->codecpar->extradata[0] == 1 || opaque->codecpar->extradata[1] == 1))) { #if AMC_USE_AVBITSTREAM_FILTER if (opaque->codecpar->codec_id == AV_CODEC_ID_H264) { opaque->bsfc = av_bitstream_filter_init("h264_mp4toannexb"); if (!opaque->bsfc) { ALOGE("Cannot open the h264_mp4toannexb BSF!\n"); goto fail; } } else { opaque->bsfc = av_bitstream_filter_init("hevc_mp4toannexb"); if (!opaque->bsfc) { ALOGE("Cannot open the hevc_mp4toannexb BSF!\n"); goto fail; } } opaque->orig_extradata_size = opaque->codecpar->extradata_size; opaque->orig_extradata = (uint8_t*) av_mallocz(opaque->codecpar->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); if (!opaque->orig_extradata) { goto fail; } memcpy(opaque->orig_extradata, opaque->codecpar->extradata, opaque->codecpar->extradata_size); for(int i = 0; i < opaque->codecpar->extradata_size; i+=4) { ALOGE("csd-0[%d]: %02x%02x%02x%02x\n", opaque->codecpar->extradata_size, (int)opaque->codecpar->extradata[i+0], (int)opaque->codecpar->extradata[i+1], (int)opaque->codecpar->extradata[i+2], (int)opaque->codecpar->extradata[i+3]); } SDL_AMediaFormat_setBuffer(opaque->input_aformat, "csd-0", opaque->codecpar->extradata, opaque->codecpar->extradata_size); #else size_t sps_pps_size = 0; size_t convert_size = opaque->codecpar->extradata_size + 20; uint8_t *convert_buffer = (uint8_t *)calloc(1, convert_size); if (!convert_buffer) { ALOGE("%s:sps_pps_buffer: alloc failed\n", __func__); goto fail; } if (opaque->codecpar->codec_id == AV_CODEC_ID_H264) { if (0 != convert_sps_pps(opaque->codecpar->extradata, opaque->codecpar->extradata_size, convert_buffer, convert_size, &sps_pps_size, &opaque->nal_size)) { ALOGE("%s:convert_sps_pps: failed\n", __func__); goto fail; } } else { if (0 != convert_hevc_nal_units(opaque->codecpar->extradata, opaque->codecpar->extradata_size, convert_buffer, convert_size, &sps_pps_size, &opaque->nal_size)) { ALOGE("%s:convert_hevc_nal_units: failed\n", __func__); goto fail; } } SDL_AMediaFormat_setBuffer(opaque->input_aformat, "csd-0", convert_buffer, sps_pps_size); for(int i = 0; i < sps_pps_size; i+=4) { ALOGE("csd-0[%d]: %02x%02x%02x%02x\n", (int)sps_pps_size, (int)convert_buffer[i+0], (int)convert_buffer[i+1], (int)convert_buffer[i+2], (int)convert_buffer[i+3]); } free(convert_buffer); #endif } else if (opaque->codecpar->codec_id == AV_CODEC_ID_MPEG4) { size_t esds_dec_dscr_type_length = opaque->codecpar->extradata_size + 0x18; size_t esds_es_dscr_type_length = esds_dec_dscr_type_length + 0x08; size_t esds_size = esds_es_dscr_type_length + 0x05; uint8_t *convert_buffer = (uint8_t *)calloc(1, esds_size); restore_mpeg4_esds(opaque->codecpar, opaque->codecpar->extradata, opaque->codecpar->extradata_size, esds_es_dscr_type_length, esds_dec_dscr_type_length, convert_buffer); SDL_AMediaFormat_setBuffer(opaque->input_aformat, "csd-0", convert_buffer, esds_size); free(convert_buffer); } else { // Codec specific data // SDL_AMediaFormat_setBuffer(opaque->aformat, "csd-0", opaque->codecpar->extradata, opaque->codecpar->extradata_size); ALOGE("csd-0: naked\n"); } } else { ALOGE("no buffer(%d)\n", opaque->codecpar->extradata_size); } rotate_degrees = ffp_get_video_rotate_degrees(ffp); if (ffp->mediacodec_auto_rotate && rotate_degrees != 0 && SDL_Android_GetApiLevel() >= IJK_API_21_LOLLIPOP) { ALOGI("amc: rotate in decoder: %d\n", rotate_degrees); opaque->frame_rotate_degrees = rotate_degrees; SDL_AMediaFormat_setInt32(opaque->input_aformat, "rotation-degrees", rotate_degrees); ffp_notify_msg2(ffp, FFP_MSG_VIDEO_ROTATION_CHANGED, 0); } else { ALOGI("amc: rotate notify: %d\n", rotate_degrees); ffp_notify_msg2(ffp, FFP_MSG_VIDEO_ROTATION_CHANGED, rotate_degrees); } return 0; fail: return -1; } static int reconfigure_codec_l(JNIEnv *env, IJKFF_Pipenode *node, jobject new_surface) { IJKFF_Pipenode_Opaque *opaque = node->opaque; int ret = 0; sdl_amedia_status_t amc_ret = 0; jobject prev_jsurface = NULL; prev_jsurface = opaque->jsurface; if (new_surface) { opaque->jsurface = (*env)->NewGlobalRef(env, new_surface); if (J4A_ExceptionCheck__catchAll(env) || !opaque->jsurface) goto fail; } else { opaque->jsurface = NULL; } SDL_JNI_DeleteGlobalRefP(env, &prev_jsurface); if (!opaque->acodec) { opaque->acodec = create_codec_l(env, node); if (!opaque->acodec) { ALOGE("%s:open_video_decoder: create_codec failed\n", __func__); ret = -1; goto fail; } } if (SDL_AMediaCodec_isConfigured(opaque->acodec)) { if (opaque->acodec) { if (SDL_AMediaCodec_isStarted(opaque->acodec)) { SDL_VoutAndroid_invalidateAllBuffers(opaque->weak_vout); SDL_AMediaCodec_stop(opaque->acodec); } if (opaque->quirk_reconfigure_with_new_codec) { ALOGI("quirk: reconfigure with new codec"); SDL_AMediaCodec_decreaseReferenceP(&opaque->acodec); SDL_VoutAndroid_setAMediaCodec(opaque->weak_vout, NULL); opaque->acodec = create_codec_l(env, node); if (!opaque->acodec) { ALOGE("%s:open_video_decoder: create_codec failed\n", __func__); ret = -1; goto fail; } } } assert(opaque->weak_vout); } amc_ret = SDL_AMediaCodec_configure_surface(env, opaque->acodec, opaque->input_aformat, opaque->jsurface, NULL, 0); if (amc_ret != SDL_AMEDIA_OK) { ALOGE("%s:configure_surface: failed\n", __func__); ret = -1; goto fail; } amc_ret = SDL_AMediaCodec_start(opaque->acodec); if (amc_ret != SDL_AMEDIA_OK) { ALOGE("%s:SDL_AMediaCodec_start: failed\n", __func__); ret = -1; goto fail; } opaque->acodec_first_dequeue_output_request = true; ALOGI("%s:new acodec: %p\n", __func__, opaque->acodec); SDL_VoutAndroid_setAMediaCodec(opaque->weak_vout, opaque->acodec); ret = 0; fail: return ret; } static int configure_codec_l(JNIEnv *env, IJKFF_Pipenode *node, jobject new_surface) { IJKFF_Pipenode_Opaque *opaque = node->opaque; int ret = 0; sdl_amedia_status_t amc_ret = 0; jobject prev_jsurface = NULL; ijkmp_mediacodecinfo_context *mcc = &opaque->mcc; prev_jsurface = opaque->jsurface; if (new_surface) { opaque->jsurface = (*env)->NewGlobalRef(env, new_surface); if (J4A_ExceptionCheck__catchAll(env) || !opaque->jsurface) goto fail; } else { opaque->jsurface = NULL; } SDL_JNI_DeleteGlobalRefP(env, &prev_jsurface); if (!opaque->acodec || !mcc) { goto fail; } strncpy(opaque->acodec_name, mcc->codec_name, sizeof(opaque->acodec_name) / sizeof(*opaque->acodec_name)); opaque->acodec_name[sizeof(opaque->acodec_name) / sizeof(*opaque->acodec_name) - 1] = 0; // QUIRK: always recreate MediaCodec for reconfigure opaque->quirk_reconfigure_with_new_codec = true; /* delaying output makes it possible to correct frame order, hopefully */ if (0 == strncasecmp(mcc->codec_name, "OMX.TI.DUCATI1.", 15)) { /* this is the only acceptable value on Nexus S */ opaque->n_buf_out = 1; ALOGD("using buffered output for %s", mcc->codec_name); } if (opaque->frame_rotate_degrees == 90 || opaque->frame_rotate_degrees == 270) { opaque->frame_width = opaque->codecpar->height; opaque->frame_height = opaque->codecpar->width; } else { opaque->frame_width = opaque->codecpar->width; opaque->frame_height = opaque->codecpar->height; } amc_ret = SDL_AMediaCodec_configure_surface(env, opaque->acodec, opaque->input_aformat, opaque->jsurface, NULL, 0); if (amc_ret != SDL_AMEDIA_OK) { ALOGE("%s:configure_surface: failed\n", __func__); ret = -1; goto fail; } amc_ret = SDL_AMediaCodec_start(opaque->acodec); if (amc_ret != SDL_AMEDIA_OK) { ALOGE("%s:SDL_AMediaCodec_start: failed\n", __func__); ret = -1; goto fail; } opaque->acodec_first_dequeue_output_request = true; ALOGI("%s:new acodec: %p\n", __func__, opaque->acodec); SDL_VoutAndroid_setAMediaCodec(opaque->weak_vout, opaque->acodec); ret = 0; fail: return ret; } #if 0 static int reconfigure_codec(JNIEnv *env, IJKFF_Pipenode *node) { IJKFF_Pipenode_Opaque *opaque = node->opaque; SDL_LockMutex(opaque->acodec_mutex); int ret = reconfigure_codec_l(env, node); SDL_UnlockMutex(opaque->acodec_mutex); return ret; } #endif static int amc_fill_frame( IJKFF_Pipenode *node, AVFrame *frame, int *got_frame, int output_buffer_index, int acodec_serial, SDL_AMediaCodecBufferInfo *buffer_info) { IJKFF_Pipenode_Opaque *opaque = node->opaque; FFPlayer *ffp = opaque->ffp; VideoState *is = ffp->is; frame->opaque = SDL_VoutAndroid_obtainBufferProxy(opaque->weak_vout, acodec_serial, output_buffer_index, buffer_info); if (!frame->opaque) goto fail; frame->width = opaque->frame_width; frame->height = opaque->frame_height; frame->format = IJK_AV_PIX_FMT__ANDROID_MEDIACODEC; frame->sample_aspect_ratio = opaque->codecpar->sample_aspect_ratio; frame->pts = av_rescale_q(buffer_info->presentationTimeUs, AV_TIME_BASE_Q, is->video_st->time_base); if (frame->pts < 0) frame->pts = AV_NOPTS_VALUE; // ALOGE("%s: %f", __func__, (float)frame->pts); *got_frame = 1; return 0; fail: *got_frame = 0; return -1; } static int feed_input_buffer2(JNIEnv *env, IJKFF_Pipenode *node, int64_t timeUs, int *enqueue_count) { IJKFF_Pipenode_Opaque *opaque = node->opaque; FFPlayer *ffp = opaque->ffp; IJKFF_Pipeline *pipeline = opaque->pipeline; VideoState *is = ffp->is; Decoder *d = &is->viddec; PacketQueue *q = d->queue; sdl_amedia_status_t amc_ret = 0; int ret = 0; ssize_t input_buffer_index = 0; ssize_t copy_size = 0; int64_t time_stamp = 0; uint32_t queue_flags = 0; if (enqueue_count) *enqueue_count = 0; if (d->queue->abort_request) { ret = ACODEC_EXIT; goto fail; } if (!d->packet_pending || d->queue->serial != d->pkt_serial) { #if AMC_USE_AVBITSTREAM_FILTER #else H264ConvertState convert_state = {0, 0}; #endif AVPacket pkt; do { if (d->queue->nb_packets == 0) SDL_CondSignal(d->empty_queue_cond); if (ffp_packet_queue_get_or_buffering(ffp, d->queue, &pkt, &d->pkt_serial, &d->finished) < 0) { ret = -1; goto fail; } if (ffp_is_flush_packet(&pkt) || opaque->acodec_flush_request) { // request flush before lock, or never get mutex opaque->acodec_flush_request = true; if (SDL_AMediaCodec_isStarted(opaque->acodec)) { if (opaque->input_packet_count > 0) { // flush empty queue cause error on OMX.SEC.AVC.Decoder (Nexus S) SDL_VoutAndroid_invalidateAllBuffers(opaque->weak_vout); SDL_AMediaCodec_flush(opaque->acodec); opaque->input_packet_count = 0; } // If codec is configured in synchronous mode, codec will resume automatically // SDL_AMediaCodec_start(opaque->acodec); } opaque->acodec_flush_request = false; d->finished = 0; d->next_pts = d->start_pts; d->next_pts_tb = d->start_pts_tb; } } while (ffp_is_flush_packet(&pkt) || d->queue->serial != d->pkt_serial); av_packet_split_side_data(&pkt); av_packet_unref(&d->pkt); d->pkt_temp = d->pkt = pkt; d->packet_pending = 1; if (opaque->ffp->mediacodec_handle_resolution_change && opaque->codecpar->codec_id == AV_CODEC_ID_H264) { uint8_t *size_data = NULL; int size_data_size = 0; AVPacket *avpkt = &d->pkt_temp; size_data = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &size_data_size); // minimum avcC(sps,pps) = 7 if (size_data && size_data_size >= 7) { int got_picture = 0; AVFrame *frame = av_frame_alloc(); AVDictionary *codec_opts = NULL; const AVCodec *codec = opaque->decoder->avctx->codec; AVCodecContext *new_avctx = avcodec_alloc_context3(codec); int change_ret = 0; if (!new_avctx) return AVERROR(ENOMEM); avcodec_parameters_to_context(new_avctx, opaque->codecpar); av_freep(&new_avctx->extradata); new_avctx->extradata = av_mallocz(size_data_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!new_avctx->extradata) { avcodec_free_context(&new_avctx); return AVERROR(ENOMEM); } memcpy(new_avctx->extradata, size_data, size_data_size); new_avctx->extradata_size = size_data_size; av_dict_set(&codec_opts, "threads", "1", 0); change_ret = avcodec_open2(new_avctx, codec, &codec_opts); av_dict_free(&codec_opts); if (change_ret < 0) { avcodec_free_context(&new_avctx); return change_ret; } change_ret = avcodec_decode_video2(new_avctx, frame, &got_picture, avpkt); if (change_ret < 0) { avcodec_free_context(&new_avctx); return change_ret; } else { if (opaque->codecpar->width != new_avctx->width && opaque->codecpar->height != new_avctx->height) { ALOGW("AV_PKT_DATA_NEW_EXTRADATA: %d x %d\n", new_avctx->width, new_avctx->height); avcodec_parameters_from_context(opaque->codecpar, new_avctx); opaque->aformat_need_recreate = true; ffpipeline_set_surface_need_reconfigure_l(pipeline, true); } } av_frame_unref(frame); avcodec_free_context(&new_avctx); } } if (opaque->codecpar->codec_id == AV_CODEC_ID_H264 || opaque->codecpar->codec_id == AV_CODEC_ID_HEVC) { convert_h264_to_annexb(d->pkt_temp.data, d->pkt_temp.size, opaque->nal_size, &convert_state); int64_t time_stamp = d->pkt_temp.pts; if (!time_stamp && d->pkt_temp.dts) time_stamp = d->pkt_temp.dts; if (time_stamp > 0) { time_stamp = av_rescale_q(time_stamp, is->video_st->time_base, AV_TIME_BASE_Q); } else { time_stamp = 0; } } } if (d->pkt_temp.data) { // reconfigure surface if surface changed // NULL surface cause no display if (ffpipeline_is_surface_need_reconfigure_l(pipeline)) { jobject new_surface = NULL; // request reconfigure before lock, or never get mutex ffpipeline_lock_surface(pipeline); ffpipeline_set_surface_need_reconfigure_l(pipeline, false); new_surface = ffpipeline_get_surface_as_global_ref_l(env, pipeline); ffpipeline_unlock_surface(pipeline); if (!opaque->aformat_need_recreate && (opaque->jsurface == new_surface || (opaque->jsurface && new_surface && (*env)->IsSameObject(env, new_surface, opaque->jsurface)))) { ALOGI("%s: same surface, reuse previous surface\n", __func__); J4A_DeleteGlobalRef__p(env, &new_surface); } else { if (d->queue->abort_request) { ret = ACODEC_EXIT; goto fail; } if (opaque->aformat_need_recreate) { ALOGI("%s: recreate aformat\n", __func__); ret = recreate_format_l(env, node); if (ret) { ALOGE("amc: recreate_format_l failed\n"); goto fail; } opaque->aformat_need_recreate = false; } ret = reconfigure_codec_l(env, node, new_surface); J4A_DeleteGlobalRef__p(env, &new_surface); if (ret != 0) { ALOGE("%s: reconfigure_codec failed\n", __func__); ret = 0; goto fail; } if (q->abort_request || opaque->acodec_flush_request) { ret = 0; goto fail; } } } queue_flags = 0; input_buffer_index = SDL_AMediaCodec_dequeueInputBuffer(opaque->acodec, timeUs); if (input_buffer_index < 0) { if (SDL_AMediaCodec_isInputBuffersValid(opaque->acodec)) { // timeout ret = 0; goto fail; } else { // enqueue fake frame queue_flags |= AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME; copy_size = d->pkt_temp.size; } } else { SDL_AMediaCodecFake_flushFakeFrames(opaque->acodec); copy_size = SDL_AMediaCodec_writeInputData(opaque->acodec, input_buffer_index, d->pkt_temp.data, d->pkt_temp.size); if (!copy_size) { ALOGE("%s: SDL_AMediaCodec_getInputBuffer failed\n", __func__); ret = -1; goto fail; } } time_stamp = d->pkt_temp.pts; if (time_stamp == AV_NOPTS_VALUE && d->pkt_temp.dts != AV_NOPTS_VALUE) time_stamp = d->pkt_temp.dts; if (time_stamp >= 0) { time_stamp = av_rescale_q(time_stamp, is->video_st->time_base, AV_TIME_BASE_Q); } else { time_stamp = 0; } // ALOGE("queueInputBuffer, %lld\n", time_stamp); amc_ret = SDL_AMediaCodec_queueInputBuffer(opaque->acodec, input_buffer_index, 0, copy_size, time_stamp, queue_flags); if (amc_ret != SDL_AMEDIA_OK) { ALOGE("%s: SDL_AMediaCodec_getInputBuffer failed\n", __func__); ret = -1; goto fail; } // ALOGE("%s: queue %d/%d", __func__, (int)copy_size, (int)input_buffer_size); opaque->input_packet_count++; if (enqueue_count) ++*enqueue_count; } if (copy_size < 0) { d->packet_pending = 0; } else { d->pkt_temp.dts = d->pkt_temp.pts = AV_NOPTS_VALUE; if (d->pkt_temp.data) { d->pkt_temp.data += copy_size; d->pkt_temp.size -= copy_size; if (d->pkt_temp.size <= 0) d->packet_pending = 0; } else { // FIXME: detect if decode finished // if (!got_frame) { d->packet_pending = 0; d->finished = d->pkt_serial; // } } } fail: return ret; } static int feed_input_buffer(JNIEnv *env, IJKFF_Pipenode *node, int64_t timeUs, int *enqueue_count) { IJKFF_Pipenode_Opaque *opaque = node->opaque; FFPlayer *ffp = opaque->ffp; IJKFF_Pipeline *pipeline = opaque->pipeline; VideoState *is = ffp->is; Decoder *d = &is->viddec; PacketQueue *q = d->queue; sdl_amedia_status_t amc_ret = 0; int ret = 0; ssize_t input_buffer_index = 0; ssize_t copy_size = 0; int64_t time_stamp = 0; uint32_t queue_flags = 0; if (enqueue_count) *enqueue_count = 0; if (d->queue->abort_request) { ret = 0; goto fail; } if (!d->packet_pending || d->queue->serial != d->pkt_serial) { #if AMC_USE_AVBITSTREAM_FILTER #else H264ConvertState convert_state = {0, 0}; #endif AVPacket pkt; do { if (d->queue->nb_packets == 0) SDL_CondSignal(d->empty_queue_cond); if (ffp_packet_queue_get_or_buffering(ffp, d->queue, &pkt, &d->pkt_serial, &d->finished) < 0) { ret = -1; goto fail; } if (ffp_is_flush_packet(&pkt) || opaque->acodec_flush_request) { // request flush before lock, or never get mutex opaque->acodec_flush_request = true; SDL_LockMutex(opaque->acodec_mutex); if (SDL_AMediaCodec_isStarted(opaque->acodec)) { if (opaque->input_packet_count > 0) { // flush empty queue cause error on OMX.SEC.AVC.Decoder (Nexus S) SDL_VoutAndroid_invalidateAllBuffers(opaque->weak_vout); SDL_AMediaCodec_flush(opaque->acodec); opaque->input_packet_count = 0; } // If codec is configured in synchronous mode, codec will resume automatically // SDL_AMediaCodec_start(opaque->acodec); } opaque->acodec_flush_request = false; SDL_CondSignal(opaque->acodec_cond); SDL_UnlockMutex(opaque->acodec_mutex); d->finished = 0; d->next_pts = d->start_pts; d->next_pts_tb = d->start_pts_tb; } } while (ffp_is_flush_packet(&pkt) || d->queue->serial != d->pkt_serial); av_packet_split_side_data(&pkt); av_packet_unref(&d->pkt); d->pkt_temp = d->pkt = pkt; d->packet_pending = 1; if (opaque->ffp->mediacodec_handle_resolution_change && opaque->codecpar->codec_id == AV_CODEC_ID_H264) { uint8_t *size_data = NULL; int size_data_size = 0; AVPacket *avpkt = &d->pkt_temp; size_data = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &size_data_size); // minimum avcC(sps,pps) = 7 if (size_data && size_data_size >= 7) { int got_picture = 0; AVFrame *frame = av_frame_alloc(); AVDictionary *codec_opts = NULL; const AVCodec *codec = opaque->decoder->avctx->codec; AVCodecContext *new_avctx = avcodec_alloc_context3(codec); int change_ret = 0; if (!new_avctx) return AVERROR(ENOMEM); avcodec_parameters_to_context(new_avctx, opaque->codecpar); av_freep(&new_avctx->extradata); new_avctx->extradata = av_mallocz(size_data_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!new_avctx->extradata) { avcodec_free_context(&new_avctx); return AVERROR(ENOMEM); } memcpy(new_avctx->extradata, size_data, size_data_size); new_avctx->extradata_size = size_data_size; av_dict_set(&codec_opts, "threads", "1", 0); change_ret = avcodec_open2(new_avctx, codec, &codec_opts); av_dict_free(&codec_opts); if (change_ret < 0) { avcodec_free_context(&new_avctx); return change_ret; } change_ret = avcodec_decode_video2(new_avctx, frame, &got_picture, avpkt); if (change_ret < 0) { avcodec_free_context(&new_avctx); return change_ret; } else { if (opaque->codecpar->width != new_avctx->width && opaque->codecpar->height != new_avctx->height) { ALOGW("AV_PKT_DATA_NEW_EXTRADATA: %d x %d\n", new_avctx->width, new_avctx->height); avcodec_parameters_from_context(opaque->codecpar, new_avctx); opaque->aformat_need_recreate = true; ffpipeline_set_surface_need_reconfigure_l(pipeline, true); } } av_frame_unref(frame); avcodec_free_context(&new_avctx); } } #if AMC_USE_AVBITSTREAM_FILTER // d->pkt_temp->data could be allocated by av_bitstream_filter_filter if (d->bfsc_ret > 0) { if (d->bfsc_data) av_freep(&d->bfsc_data); d->bfsc_ret = 0; } d->bfsc_ret = av_bitstream_filter_filter(opaque->bsfc, opaque->avctx, NULL, &d->pkt_temp.data, &d->pkt_temp.size, d->pkt.data, d->pkt.size, d->pkt.flags & AV_PKT_FLAG_KEY); if (d->bfsc_ret > 0) { d->bfsc_data = d->pkt_temp.data; } else if (d->bfsc_ret < 0) { ALOGE("%s: av_bitstream_filter_filter failed\n", __func__); ret = -1; goto fail; } if (d->pkt_temp.size == d->pkt.size + opaque->avctx->extradata_size) { d->pkt_temp.data += opaque->avctx->extradata_size; d->pkt_temp.size = d->pkt.size; } AMCTRACE("bsfc->filter(%d): %p[%d] -> %p[%d]", d->bfsc_ret, d->pkt.data, (int)d->pkt.size, d->pkt_temp.data, (int)d->pkt_temp.size); #else #if 0 AMCTRACE("raw [%d][%d] %02x%02x%02x%02x%02x%02x%02x%02x", (int)d->pkt_temp.size, (int)opaque->nal_size, d->pkt_temp.data[0], d->pkt_temp.data[1], d->pkt_temp.data[2], d->pkt_temp.data[3], d->pkt_temp.data[4], d->pkt_temp.data[5], d->pkt_temp.data[6], d->pkt_temp.data[7]); #endif if (opaque->codecpar->codec_id == AV_CODEC_ID_H264 || opaque->codecpar->codec_id == AV_CODEC_ID_HEVC) { convert_h264_to_annexb(d->pkt_temp.data, d->pkt_temp.size, opaque->nal_size, &convert_state); int64_t time_stamp = d->pkt_temp.pts; if (!time_stamp && d->pkt_temp.dts) time_stamp = d->pkt_temp.dts; if (time_stamp > 0) { time_stamp = av_rescale_q(time_stamp, is->video_st->time_base, AV_TIME_BASE_Q); } else { time_stamp = 0; } } #if 0 AMCTRACE("input[%d][%d][%lld,%lld (%d, %d) -> %lld] %02x%02x%02x%02x%02x%02x%02x%02x", (int)d->pkt_temp.size, (int)opaque->nal_size, (int64_t)d->pkt_temp.pts, (int64_t)d->pkt_temp.dts, (int)is->video_st->time_base.num, (int)is->video_st->time_base.den, (int64_t)time_stamp, d->pkt_temp.data[0], d->pkt_temp.data[1], d->pkt_temp.data[2], d->pkt_temp.data[3], d->pkt_temp.data[4], d->pkt_temp.data[5], d->pkt_temp.data[6], d->pkt_temp.data[7]); #endif #endif } if (d->pkt_temp.data) { // reconfigure surface if surface changed // NULL surface cause no display if (ffpipeline_is_surface_need_reconfigure_l(pipeline)) { jobject new_surface = NULL; // request reconfigure before lock, or never get mutex ffpipeline_lock_surface(pipeline); ffpipeline_set_surface_need_reconfigure_l(pipeline, false); new_surface = ffpipeline_get_surface_as_global_ref_l(env, pipeline); ffpipeline_unlock_surface(pipeline); if (!opaque->aformat_need_recreate && (opaque->jsurface == new_surface || (opaque->jsurface && new_surface && (*env)->IsSameObject(env, new_surface, opaque->jsurface)))) { ALOGI("%s: same surface, reuse previous surface\n", __func__); J4A_DeleteGlobalRef__p(env, &new_surface); } else { if (opaque->aformat_need_recreate) { ALOGI("%s: recreate aformat\n", __func__); ret = recreate_format_l(env, node); if (ret) { ALOGE("amc: recreate_format_l failed\n"); goto fail; } opaque->aformat_need_recreate = false; } opaque->acodec_reconfigure_request = true; SDL_LockMutex(opaque->acodec_mutex); ret = reconfigure_codec_l(env, node, new_surface); opaque->acodec_reconfigure_request = false; SDL_CondSignal(opaque->acodec_cond); SDL_UnlockMutex(opaque->acodec_mutex); J4A_DeleteGlobalRef__p(env, &new_surface); if (ret != 0) { ALOGE("%s: reconfigure_codec failed\n", __func__); ret = 0; goto fail; } SDL_LockMutex(opaque->acodec_first_dequeue_output_mutex); while (!q->abort_request && !opaque->acodec_reconfigure_request && !opaque->acodec_flush_request && opaque->acodec_first_dequeue_output_request) { SDL_CondWaitTimeout(opaque->acodec_first_dequeue_output_cond, opaque->acodec_first_dequeue_output_mutex, 100); } SDL_UnlockMutex(opaque->acodec_first_dequeue_output_mutex); if (q->abort_request || opaque->acodec_reconfigure_request || opaque->acodec_flush_request) { ret = 0; goto fail; } } } #if 0 // no need to decode without surface if (!opaque->jsurface) { ret = amc_decode_picture_fake(node, 1000); goto fail; } #endif queue_flags = 0; input_buffer_index = SDL_AMediaCodec_dequeueInputBuffer(opaque->acodec, timeUs); if (input_buffer_index < 0) { if (SDL_AMediaCodec_isInputBuffersValid(opaque->acodec)) { // timeout ret = 0; goto fail; } else { // enqueue fake frame queue_flags |= AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME; copy_size = d->pkt_temp.size; } } else { SDL_AMediaCodecFake_flushFakeFrames(opaque->acodec); copy_size = SDL_AMediaCodec_writeInputData(opaque->acodec, input_buffer_index, d->pkt_temp.data, d->pkt_temp.size); if (!copy_size) { ALOGE("%s: SDL_AMediaCodec_getInputBuffer failed\n", __func__); ret = -1; goto fail; } } time_stamp = d->pkt_temp.pts; if (time_stamp == AV_NOPTS_VALUE && d->pkt_temp.dts != AV_NOPTS_VALUE) time_stamp = d->pkt_temp.dts; if (time_stamp >= 0) { time_stamp = av_rescale_q(time_stamp, is->video_st->time_base, AV_TIME_BASE_Q); } else { time_stamp = 0; } // ALOGE("queueInputBuffer, %lld\n", time_stamp); amc_ret = SDL_AMediaCodec_queueInputBuffer(opaque->acodec, input_buffer_index, 0, copy_size, time_stamp, queue_flags); if (amc_ret != SDL_AMEDIA_OK) { ALOGE("%s: SDL_AMediaCodec_getInputBuffer failed\n", __func__); ret = -1; goto fail; } // ALOGE("%s: queue %d/%d", __func__, (int)copy_size, (int)input_buffer_size); opaque->input_packet_count++; if (enqueue_count) ++*enqueue_count; } if (copy_size < 0) { d->packet_pending = 0; } else { d->pkt_temp.dts = d->pkt_temp.pts = AV_NOPTS_VALUE; if (d->pkt_temp.data) { d->pkt_temp.data += copy_size; d->pkt_temp.size -= copy_size; if (d->pkt_temp.size <= 0) d->packet_pending = 0; } else { // FIXME: detect if decode finished // if (!got_frame) { d->packet_pending = 0; d->finished = d->pkt_serial; // } } } fail: return ret; } static int enqueue_thread_func(void *arg) { JNIEnv *env = NULL; IJKFF_Pipenode *node = arg; IJKFF_Pipenode_Opaque *opaque = node->opaque; FFPlayer *ffp = opaque->ffp; VideoState *is = ffp->is; Decoder *d = &is->viddec; PacketQueue *q = d->queue; int ret = -1; int dequeue_count = 0; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SetupThreadEnv failed\n", __func__); goto fail; } while (!q->abort_request && !opaque->abort) { ret = feed_input_buffer(env, node, AMC_INPUT_TIMEOUT_US, &dequeue_count); if (ret != 0) { goto fail; } } ret = 0; fail: SDL_AMediaCodecFake_abort(opaque->acodec); ALOGI("MediaCodec: %s: exit: %d", __func__, ret); return ret; } static double pts_from_buffer_info(IJKFF_Pipenode *node, SDL_AMediaCodecBufferInfo *buffer_info) { IJKFF_Pipenode_Opaque *opaque = node->opaque; FFPlayer *ffp = opaque->ffp; VideoState *is = ffp->is; AVRational tb = is->video_st->time_base; int64_t amc_pts = av_rescale_q(buffer_info->presentationTimeUs, AV_TIME_BASE_Q, is->video_st->time_base); double pts = amc_pts < 0 ? NAN : amc_pts * av_q2d(tb); return pts; } /* it's OK here */ static void sort_amc_buf_out(AMC_Buf_Out *buf_out, int size) { AMC_Buf_Out *a, *b, tmp; int i, j; for (i = 0; i < size; i++) { for (j = i + 1; j < size; j++) { a = buf_out + i; b = buf_out + j; if (a->pts < b->pts) { tmp = *a; *a = *b; *b = tmp; } } } } static int drain_output_buffer_l(JNIEnv *env, IJKFF_Pipenode *node, int64_t timeUs, int *dequeue_count, AVFrame *frame, int *got_frame) { IJKFF_Pipenode_Opaque *opaque = node->opaque; FFPlayer *ffp = opaque->ffp; int ret = 0; SDL_AMediaCodecBufferInfo bufferInfo; ssize_t output_buffer_index = 0; if (dequeue_count) *dequeue_count = 0; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s:create: SetupThreadEnv failed\n", __func__); goto fail; } output_buffer_index = SDL_AMediaCodecFake_dequeueOutputBuffer(opaque->acodec, &bufferInfo, timeUs); if (output_buffer_index == AMEDIACODEC__INFO_OUTPUT_BUFFERS_CHANGED) { ALOGI("AMEDIACODEC__INFO_OUTPUT_BUFFERS_CHANGED\n"); // continue; } else if (output_buffer_index == AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED) { ALOGI("AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED\n"); SDL_AMediaFormat_deleteP(&opaque->output_aformat); opaque->output_aformat = SDL_AMediaCodec_getOutputFormat(opaque->acodec); if (opaque->output_aformat) { int width = 0; int height = 0; int color_format = 0; int stride = 0; int slice_height = 0; int crop_left = 0; int crop_top = 0; int crop_right = 0; int crop_bottom = 0; SDL_AMediaFormat_getInt32(opaque->output_aformat, "width", &width); SDL_AMediaFormat_getInt32(opaque->output_aformat, "height", &height); SDL_AMediaFormat_getInt32(opaque->output_aformat, "color-format", &color_format); SDL_AMediaFormat_getInt32(opaque->output_aformat, "stride", &stride); SDL_AMediaFormat_getInt32(opaque->output_aformat, "slice-height", &slice_height); SDL_AMediaFormat_getInt32(opaque->output_aformat, "crop-left", &crop_left); SDL_AMediaFormat_getInt32(opaque->output_aformat, "crop-top", &crop_top); SDL_AMediaFormat_getInt32(opaque->output_aformat, "crop-right", &crop_right); SDL_AMediaFormat_getInt32(opaque->output_aformat, "crop-bottom", &crop_bottom); // TI decoder could crash after reconfigure // ffp_notify_msg3(ffp, FFP_MSG_VIDEO_SIZE_CHANGED, width, height); // opaque->frame_width = width; // opaque->frame_height = height; ALOGI( "AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED\n" " width-height: (%d x %d)\n" " color-format: (%s: 0x%x)\n" " stride: (%d)\n" " slice-height: (%d)\n" " crop: (%d, %d, %d, %d)\n" , width, height, SDL_AMediaCodec_getColorFormatName(color_format), color_format, stride, slice_height, crop_left, crop_top, crop_right, crop_bottom); } // continue; } else if (output_buffer_index == AMEDIACODEC__INFO_TRY_AGAIN_LATER) { AMCTRACE("AMEDIACODEC__INFO_TRY_AGAIN_LATER\n"); // continue; } else if (output_buffer_index < 0) { SDL_LockMutex(opaque->any_input_mutex); SDL_CondWaitTimeout(opaque->any_input_cond, opaque->any_input_mutex, 1000); SDL_UnlockMutex(opaque->any_input_mutex); goto done; } else if (output_buffer_index >= 0) { ffp->stat.vdps = SDL_SpeedSamplerAdd(&opaque->sampler, FFP_SHOW_VDPS_MEDIACODEC, "vdps[MediaCodec]"); if (dequeue_count) ++*dequeue_count; #ifdef FFP_SHOW_AMC_VDPS { if (opaque->benchmark_start_time == 0) { opaque->benchmark_start_time = SDL_GetTickHR(); } opaque->benchmark_frame_count += 1; if (0 == (opaque->benchmark_frame_count % 240)) { Uint64 diff = SDL_GetTickHR() - opaque->benchmark_start_time; double per_frame_ms = ((double) diff) / opaque->benchmark_frame_count; double fps = ((double) opaque->benchmark_frame_count) * 1000 / diff; ALOGE("%lf fps, %lf ms/frame, %"PRIu64" frames\n", fps, per_frame_ms, opaque->benchmark_frame_count); } } #endif #ifdef FFP_AMC_DISABLE_OUTPUT if (!(bufferInfo.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME)) { SDL_AMediaCodec_releaseOutputBuffer(opaque->acodec, output_buffer_index, false); } goto done; #endif if (opaque->n_buf_out) { AMC_Buf_Out *buf_out; if (opaque->off_buf_out < opaque->n_buf_out) { // ALOGD("filling buffer... %d", opaque->off_buf_out); buf_out = &opaque->amc_buf_out[opaque->off_buf_out++]; buf_out->acodec_serial = SDL_AMediaCodec_getSerial(opaque->acodec); buf_out->port = output_buffer_index; buf_out->info = bufferInfo; buf_out->pts = pts_from_buffer_info(node, &bufferInfo); sort_amc_buf_out(opaque->amc_buf_out, opaque->off_buf_out); } else { double pts; pts = pts_from_buffer_info(node, &bufferInfo); if (opaque->last_queued_pts != AV_NOPTS_VALUE && pts < opaque->last_queued_pts) { // FIXME: drop unordered picture to avoid dither // ALOGE("early picture, drop!"); // SDL_AMediaCodec_releaseOutputBuffer(opaque->acodec, output_buffer_index, false); // goto done; } /* already sorted */ buf_out = &opaque->amc_buf_out[opaque->off_buf_out - 1]; /* new picture is the most aged, send now */ if (pts < buf_out->pts) { ret = amc_fill_frame(node, frame, got_frame, output_buffer_index, SDL_AMediaCodec_getSerial(opaque->acodec), &bufferInfo); opaque->last_queued_pts = pts; // ALOGD("pts = %f", pts); } else { int i; /* find one to send */ for (i = opaque->off_buf_out - 1; i >= 0; i--) { buf_out = &opaque->amc_buf_out[i]; if (pts > buf_out->pts) { ret = amc_fill_frame(node, frame, got_frame, buf_out->port, buf_out->acodec_serial, &buf_out->info); opaque->last_queued_pts = buf_out->pts; // ALOGD("pts = %f", buf_out->pts); /* replace for sort later */ buf_out->acodec_serial = SDL_AMediaCodec_getSerial(opaque->acodec); buf_out->port = output_buffer_index; buf_out->info = bufferInfo; buf_out->pts = pts_from_buffer_info(node, &bufferInfo); sort_amc_buf_out(opaque->amc_buf_out, opaque->n_buf_out); break; } } /* need to discard current buffer */ if (i < 0) { // ALOGE("buffer too small, drop picture!"); if (!(bufferInfo.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME)) { SDL_AMediaCodec_releaseOutputBuffer(opaque->acodec, output_buffer_index, false); goto done; } } } } } else { ret = amc_fill_frame(node, frame, got_frame, output_buffer_index, SDL_AMediaCodec_getSerial(opaque->acodec), &bufferInfo); } } done: if (opaque->decoder->queue->abort_request) ret = -1; else ret = 0; fail: return ret; } static int drain_output_buffer2_l(JNIEnv *env, IJKFF_Pipenode *node, int64_t timeUs, int *dequeue_count, AVFrame *frame, int *got_frame) { IJKFF_Pipenode_Opaque *opaque = node->opaque; FFPlayer *ffp = opaque->ffp; SDL_AMediaCodecBufferInfo bufferInfo; ssize_t output_buffer_index = 0; if (dequeue_count) *dequeue_count = 0; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s:create: SetupThreadEnv failed\n", __func__); return ACODEC_RETRY; } output_buffer_index = SDL_AMediaCodecFake_dequeueOutputBuffer(opaque->acodec, &bufferInfo, timeUs); if (output_buffer_index == AMEDIACODEC__INFO_OUTPUT_BUFFERS_CHANGED) { ALOGD("AMEDIACODEC__INFO_OUTPUT_BUFFERS_CHANGED\n"); return ACODEC_RETRY; } else if (output_buffer_index == AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED) { ALOGD("AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED\n"); SDL_AMediaFormat_deleteP(&opaque->output_aformat); opaque->output_aformat = SDL_AMediaCodec_getOutputFormat(opaque->acodec); if (opaque->output_aformat) { int width = 0; int height = 0; int color_format = 0; int stride = 0; int slice_height = 0; int crop_left = 0; int crop_top = 0; int crop_right = 0; int crop_bottom = 0; SDL_AMediaFormat_getInt32(opaque->output_aformat, "width", &width); SDL_AMediaFormat_getInt32(opaque->output_aformat, "height", &height); SDL_AMediaFormat_getInt32(opaque->output_aformat, "color-format", &color_format); SDL_AMediaFormat_getInt32(opaque->output_aformat, "stride", &stride); SDL_AMediaFormat_getInt32(opaque->output_aformat, "slice-height", &slice_height); SDL_AMediaFormat_getInt32(opaque->output_aformat, "crop-left", &crop_left); SDL_AMediaFormat_getInt32(opaque->output_aformat, "crop-top", &crop_top); SDL_AMediaFormat_getInt32(opaque->output_aformat, "crop-right", &crop_right); SDL_AMediaFormat_getInt32(opaque->output_aformat, "crop-bottom", &crop_bottom); // TI decoder could crash after reconfigure // ffp_notify_msg3(ffp, FFP_MSG_VIDEO_SIZE_CHANGED, width, height); // opaque->frame_width = width; // opaque->frame_height = height; ALOGI( "AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED\n" " width-height: (%d x %d)\n" " color-format: (%s: 0x%x)\n" " stride: (%d)\n" " slice-height: (%d)\n" " crop: (%d, %d, %d, %d)\n" , width, height, SDL_AMediaCodec_getColorFormatName(color_format), color_format, stride, slice_height, crop_left, crop_top, crop_right, crop_bottom); } return ACODEC_RETRY; // continue; } else if (output_buffer_index == AMEDIACODEC__INFO_TRY_AGAIN_LATER) { return 0; // continue; } else if (output_buffer_index < 0) { return 0; } else if (output_buffer_index >= 0) { ffp->stat.vdps = SDL_SpeedSamplerAdd(&opaque->sampler, FFP_SHOW_VDPS_MEDIACODEC, "vdps[MediaCodec]"); if (dequeue_count) ++*dequeue_count; if (opaque->n_buf_out) { AMC_Buf_Out *buf_out; if (opaque->off_buf_out < opaque->n_buf_out) { // ALOGD("filling buffer... %d", opaque->off_buf_out); buf_out = &opaque->amc_buf_out[opaque->off_buf_out++]; buf_out->acodec_serial = SDL_AMediaCodec_getSerial(opaque->acodec); buf_out->port = output_buffer_index; buf_out->info = bufferInfo; buf_out->pts = pts_from_buffer_info(node, &bufferInfo); sort_amc_buf_out(opaque->amc_buf_out, opaque->off_buf_out); } else { double pts; pts = pts_from_buffer_info(node, &bufferInfo); if (opaque->last_queued_pts != AV_NOPTS_VALUE && pts < opaque->last_queued_pts) { // FIXME: drop unordered picture to avoid dither // ALOGE("early picture, drop!"); // SDL_AMediaCodec_releaseOutputBuffer(opaque->acodec, output_buffer_index, false); // goto done; } /* already sorted */ buf_out = &opaque->amc_buf_out[opaque->off_buf_out - 1]; /* new picture is the most aged, send now */ if (pts < buf_out->pts) { amc_fill_frame(node, frame, got_frame, output_buffer_index, SDL_AMediaCodec_getSerial(opaque->acodec), &bufferInfo); opaque->last_queued_pts = pts; // ALOGD("pts = %f", pts); } else { int i; /* find one to send */ for (i = opaque->off_buf_out - 1; i >= 0; i--) { buf_out = &opaque->amc_buf_out[i]; if (pts > buf_out->pts) { amc_fill_frame(node, frame, got_frame, buf_out->port, buf_out->acodec_serial, &buf_out->info); opaque->last_queued_pts = buf_out->pts; // ALOGD("pts = %f", buf_out->pts); /* replace for sort later */ buf_out->acodec_serial = SDL_AMediaCodec_getSerial(opaque->acodec); buf_out->port = output_buffer_index; buf_out->info = bufferInfo; buf_out->pts = pts_from_buffer_info(node, &bufferInfo); sort_amc_buf_out(opaque->amc_buf_out, opaque->n_buf_out); break; } } /* need to discard current buffer */ if (i < 0) { // ALOGE("buffer too small, drop picture!"); if (!(bufferInfo.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME)) { SDL_AMediaCodec_releaseOutputBuffer(opaque->acodec, output_buffer_index, false); return 0; } } } } } else { amc_fill_frame(node, frame, got_frame, output_buffer_index, SDL_AMediaCodec_getSerial(opaque->acodec), &bufferInfo); } } return 0; } static int drain_output_buffer(JNIEnv *env, IJKFF_Pipenode *node, int64_t timeUs, int *dequeue_count, AVFrame *frame, int *got_frame) { IJKFF_Pipenode_Opaque *opaque = node->opaque; SDL_LockMutex(opaque->acodec_mutex); if (opaque->acodec_flush_request || opaque->acodec_reconfigure_request) { // TODO: invalid picture here? // let feed_input_buffer() get mutex SDL_CondWaitTimeout(opaque->acodec_cond, opaque->acodec_mutex, 100); } int ret = drain_output_buffer_l(env, node, timeUs, dequeue_count, frame, got_frame); SDL_UnlockMutex(opaque->acodec_mutex); return ret; } static void func_destroy(IJKFF_Pipenode *node) { if (!node || !node->opaque) return; IJKFF_Pipenode_Opaque *opaque = node->opaque; SDL_DestroyCondP(&opaque->any_input_cond); SDL_DestroyMutexP(&opaque->any_input_mutex); SDL_DestroyCondP(&opaque->acodec_cond); SDL_DestroyMutexP(&opaque->acodec_mutex); SDL_DestroyCondP(&opaque->acodec_first_dequeue_output_cond); SDL_DestroyMutexP(&opaque->acodec_first_dequeue_output_mutex); SDL_AMediaCodec_decreaseReferenceP(&opaque->acodec); SDL_AMediaFormat_deleteP(&opaque->input_aformat); SDL_AMediaFormat_deleteP(&opaque->output_aformat); #if AMC_USE_AVBITSTREAM_FILTER av_freep(&opaque->orig_extradata); if (opaque->bsfc) { av_bitstream_filter_close(opaque->bsfc); opaque->bsfc = NULL; } #endif avcodec_parameters_free(&opaque->codecpar); JNIEnv *env = NULL; if (JNI_OK == SDL_JNI_SetupThreadEnv(&env)) { if (opaque->jsurface != NULL) { SDL_JNI_DeleteGlobalRefP(env, &opaque->jsurface); } } } static int drain_output_buffer2(JNIEnv *env, IJKFF_Pipenode *node, int64_t timeUs, int *dequeue_count, AVFrame *frame, AVRational frame_rate) { IJKFF_Pipenode_Opaque *opaque = node->opaque; FFPlayer *ffp = opaque->ffp; VideoState *is = ffp->is; AVRational tb = is->video_st->time_base; int got_frame = 0; int ret = -1; double duration; double pts; while (ret) { got_frame = 0; ret = drain_output_buffer2_l(env, node, timeUs, dequeue_count, frame, &got_frame); if (opaque->decoder->queue->abort_request) { if (got_frame && frame->opaque) SDL_VoutAndroid_releaseBufferProxyP(opaque->weak_vout, (SDL_AMediaCodecBufferProxy **)&frame->opaque, false); return ACODEC_EXIT; } if (ret != 0) { if (got_frame && frame->opaque) SDL_VoutAndroid_releaseBufferProxyP(opaque->weak_vout, (SDL_AMediaCodecBufferProxy **)&frame->opaque, false); } } if (got_frame) { duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0); pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb); if (ffp->framedrop > 0 || (ffp->framedrop && ffp_get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) { ffp->stat.decode_frame_count++; if (frame->pts != AV_NOPTS_VALUE) { double dpts = pts; double diff = dpts - ffp_get_master_clock(is); if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD && diff - is->frame_last_filter_delay < 0 && is->viddec.pkt_serial == is->vidclk.serial && is->videoq.nb_packets) { is->frame_drops_early++; is->continuous_frame_drops_early++; if (is->continuous_frame_drops_early > ffp->framedrop) { is->continuous_frame_drops_early = 0; } else { ffp->stat.drop_frame_count++; ffp->stat.drop_frame_rate = (float)(ffp->stat.drop_frame_count) / (float)(ffp->stat.decode_frame_count); if (frame->opaque) { SDL_VoutAndroid_releaseBufferProxyP(opaque->weak_vout, (SDL_AMediaCodecBufferProxy **)&frame->opaque, false); } av_frame_unref(frame); return ret; } } } } ret = ffp_queue_picture(ffp, frame, pts, duration, av_frame_get_pkt_pos(frame), is->viddec.pkt_serial); if (ret) { if (frame->opaque) SDL_VoutAndroid_releaseBufferProxyP(opaque->weak_vout, (SDL_AMediaCodecBufferProxy **)&frame->opaque, false); } av_frame_unref(frame); } return ret; } static int func_run_sync_loop(IJKFF_Pipenode *node) { JNIEnv *env = NULL; IJKFF_Pipenode_Opaque *opaque = node->opaque; FFPlayer *ffp = opaque->ffp; VideoState *is = ffp->is; Decoder *d = &is->viddec; PacketQueue *q = d->queue; int ret = 0; int dequeue_count = 0; int enqueue_count = 0; AVFrame *frame = NULL; AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL); if (!opaque->acodec) { return ffp_video_thread(ffp); } if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SetupThreadEnv failed\n", __func__); return -1; } frame = av_frame_alloc(); if (!frame) goto fail; while (!q->abort_request) { ret = drain_output_buffer2(env, node, AMC_SYNC_OUTPUT_TIMEOUT_US, &dequeue_count, frame, frame_rate); ret = feed_input_buffer2(env, node, AMC_SYNC_INPUT_TIMEOUT_US, &enqueue_count); } fail: av_frame_free(&frame); opaque->abort = true; if (opaque->n_buf_out) { free(opaque->amc_buf_out); opaque->n_buf_out = 0; opaque->amc_buf_out = NULL; opaque->off_buf_out = 0; opaque->last_queued_pts = AV_NOPTS_VALUE; } if (opaque->acodec) { SDL_VoutAndroid_invalidateAllBuffers(opaque->weak_vout); } SDL_AMediaCodec_stop(opaque->acodec); SDL_AMediaCodec_decreaseReferenceP(&opaque->acodec); ALOGI("MediaCodec: %s: exit: %d", __func__, ret); return ret; } static int func_run_sync(IJKFF_Pipenode *node) { JNIEnv *env = NULL; IJKFF_Pipenode_Opaque *opaque = node->opaque; FFPlayer *ffp = opaque->ffp; VideoState *is = ffp->is; Decoder *d = &is->viddec; PacketQueue *q = d->queue; int ret = 0; int dequeue_count = 0; AVFrame *frame = NULL; int got_frame = 0; AVRational tb = is->video_st->time_base; AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL); double duration; double pts; if (!opaque->acodec) { return ffp_video_thread(ffp); } if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SetupThreadEnv failed\n", __func__); return -1; } frame = av_frame_alloc(); if (!frame) goto fail; opaque->enqueue_thread = SDL_CreateThreadEx(&opaque->_enqueue_thread, enqueue_thread_func, node, "amediacodec_input_thread"); if (!opaque->enqueue_thread) { ALOGE("%s: SDL_CreateThreadEx failed\n", __func__); ret = -1; goto fail; } while (!q->abort_request) { int64_t timeUs = opaque->acodec_first_dequeue_output_request ? 0 : AMC_OUTPUT_TIMEOUT_US; got_frame = 0; ret = drain_output_buffer(env, node, timeUs, &dequeue_count, frame, &got_frame); if (opaque->acodec_first_dequeue_output_request) { SDL_LockMutex(opaque->acodec_first_dequeue_output_mutex); opaque->acodec_first_dequeue_output_request = false; SDL_CondSignal(opaque->acodec_first_dequeue_output_cond); SDL_UnlockMutex(opaque->acodec_first_dequeue_output_mutex); } if (ret != 0) { ret = -1; if (got_frame && frame->opaque) SDL_VoutAndroid_releaseBufferProxyP(opaque->weak_vout, (SDL_AMediaCodecBufferProxy **)&frame->opaque, false); goto fail; } if (got_frame) { duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0); pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb); if (ffp->framedrop > 0 || (ffp->framedrop && ffp_get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) { ffp->stat.decode_frame_count++; if (frame->pts != AV_NOPTS_VALUE) { double dpts = pts; double diff = dpts - ffp_get_master_clock(is); if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD && diff - is->frame_last_filter_delay < 0 && is->viddec.pkt_serial == is->vidclk.serial && is->videoq.nb_packets) { is->frame_drops_early++; is->continuous_frame_drops_early++; if (is->continuous_frame_drops_early > ffp->framedrop) { is->continuous_frame_drops_early = 0; } else { ffp->stat.drop_frame_count++; ffp->stat.drop_frame_rate = (float)(ffp->stat.drop_frame_count) / (float)(ffp->stat.decode_frame_count); if (frame->opaque) { SDL_VoutAndroid_releaseBufferProxyP(opaque->weak_vout, (SDL_AMediaCodecBufferProxy **)&frame->opaque, false); } av_frame_unref(frame); continue; } } } } ret = ffp_queue_picture(ffp, frame, pts, duration, av_frame_get_pkt_pos(frame), is->viddec.pkt_serial); if (ret) { if (frame->opaque) SDL_VoutAndroid_releaseBufferProxyP(opaque->weak_vout, (SDL_AMediaCodecBufferProxy **)&frame->opaque, false); } av_frame_unref(frame); } } fail: av_frame_free(&frame); opaque->abort = true; SDL_WaitThread(opaque->enqueue_thread, NULL); SDL_AMediaCodecFake_abort(opaque->acodec); if (opaque->n_buf_out) { free(opaque->amc_buf_out); opaque->n_buf_out = 0; opaque->amc_buf_out = NULL; opaque->off_buf_out = 0; opaque->last_queued_pts = AV_NOPTS_VALUE; } if (opaque->acodec) { SDL_VoutAndroid_invalidateAllBuffers(opaque->weak_vout); SDL_LockMutex(opaque->acodec_mutex); SDL_UnlockMutex(opaque->acodec_mutex); } SDL_AMediaCodec_stop(opaque->acodec); SDL_AMediaCodec_decreaseReferenceP(&opaque->acodec); ALOGI("MediaCodec: %s: exit: %d", __func__, ret); return ret; #if 0 fallback_to_ffplay: ALOGW("fallback to ffplay decoder\n"); return ffp_video_thread(opaque->ffp); #endif } static int func_flush(IJKFF_Pipenode *node) { IJKFF_Pipenode_Opaque *opaque = node->opaque; if (!opaque) return -1; opaque->acodec_flush_request = true; return 0; } int ffpipenode_config_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pipeline, SDL_Vout *vout, IJKFF_Pipenode *node) { int ret = 0; VideoState *is = ffp->is; IJKFF_Pipenode_Opaque *opaque = node->opaque; JNIEnv *env = NULL; jobject jsurface = NULL; opaque->decoder = &is->viddec; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s:create: SetupThreadEnv failed\n", __func__); goto fail; } ret = avcodec_parameters_from_context(opaque->codecpar, opaque->decoder->avctx); if (ret) goto fail; switch (opaque->codecpar->codec_id) { case AV_CODEC_ID_H264: if (!ffp->mediacodec_avc && !ffp->mediacodec_all_videos) { ALOGE("%s: MediaCodec: AVC/H264 is disabled. codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } switch (opaque->codecpar->profile) { case FF_PROFILE_H264_BASELINE: ALOGI("%s: MediaCodec: H264_BASELINE: enabled\n", __func__); break; case FF_PROFILE_H264_CONSTRAINED_BASELINE: ALOGI("%s: MediaCodec: H264_CONSTRAINED_BASELINE: enabled\n", __func__); break; case FF_PROFILE_H264_MAIN: ALOGI("%s: MediaCodec: H264_MAIN: enabled\n", __func__); break; case FF_PROFILE_H264_EXTENDED: ALOGI("%s: MediaCodec: H264_EXTENDED: enabled\n", __func__); break; case FF_PROFILE_H264_HIGH: ALOGI("%s: MediaCodec: H264_HIGH: enabled\n", __func__); break; case FF_PROFILE_H264_HIGH_10: ALOGW("%s: MediaCodec: H264_HIGH_10: disabled\n", __func__); goto fail; case FF_PROFILE_H264_HIGH_10_INTRA: ALOGW("%s: MediaCodec: H264_HIGH_10_INTRA: disabled\n", __func__); goto fail; case FF_PROFILE_H264_HIGH_422: ALOGW("%s: MediaCodec: H264_HIGH_10_422: disabled\n", __func__); goto fail; case FF_PROFILE_H264_HIGH_422_INTRA: ALOGW("%s: MediaCodec: H264_HIGH_10_INTRA: disabled\n", __func__); goto fail; case FF_PROFILE_H264_HIGH_444: ALOGW("%s: MediaCodec: H264_HIGH_10_444: disabled\n", __func__); goto fail; case FF_PROFILE_H264_HIGH_444_PREDICTIVE: ALOGW("%s: MediaCodec: H264_HIGH_444_PREDICTIVE: disabled\n", __func__); goto fail; case FF_PROFILE_H264_HIGH_444_INTRA: ALOGW("%s: MediaCodec: H264_HIGH_444_INTRA: disabled\n", __func__); goto fail; case FF_PROFILE_H264_CAVLC_444: ALOGW("%s: MediaCodec: H264_CAVLC_444: disabled\n", __func__); goto fail; default: ALOGW("%s: MediaCodec: (%d) unknown profile: disabled\n", __func__, opaque->codecpar->profile); goto fail; } strcpy(opaque->mcc.mime_type, SDL_AMIME_VIDEO_AVC); opaque->mcc.profile = opaque->codecpar->profile; opaque->mcc.level = opaque->codecpar->level; break; case AV_CODEC_ID_HEVC: if (!ffp->mediacodec_hevc && !ffp->mediacodec_all_videos) { ALOGE("%s: MediaCodec/HEVC is disabled. codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } strcpy(opaque->mcc.mime_type, SDL_AMIME_VIDEO_HEVC); opaque->mcc.profile = opaque->codecpar->profile; opaque->mcc.level = opaque->codecpar->level; break; case AV_CODEC_ID_MPEG2VIDEO: if (!ffp->mediacodec_mpeg2 && !ffp->mediacodec_all_videos) { ALOGE("%s: MediaCodec/MPEG2VIDEO is disabled. codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } strcpy(opaque->mcc.mime_type, SDL_AMIME_VIDEO_MPEG2VIDEO); opaque->mcc.profile = opaque->codecpar->profile; opaque->mcc.level = opaque->codecpar->level; break; case AV_CODEC_ID_MPEG4: if (!ffp->mediacodec_mpeg4 && !ffp->mediacodec_all_videos) { ALOGE("%s: MediaCodec/MPEG4 is disabled. codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } if ((opaque->codecpar->codec_tag & 0x0000FFFF) == 0x00005844) { ALOGE("%s: divx is not supported \n", __func__); goto fail; } strcpy(opaque->mcc.mime_type, SDL_AMIME_VIDEO_MPEG4); opaque->mcc.profile = opaque->codecpar->profile >= 0 ? opaque->codecpar->profile : 0; opaque->mcc.level = opaque->codecpar->level >= 0 ? opaque->codecpar->level : 1; break; default: ALOGE("%s:create: not H264 or H265/HEVC, codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } if (strcmp(opaque->mcc.mime_type, ffp->video_mime_type)) { ALOGW("amc: video_mime_type error opaque->mcc.mime_type = %s\n", opaque->mcc.mime_type); goto fail; } ret = recreate_format_l(env, node); if (ret) { ALOGE("amc: recreate_format_l failed\n"); goto fail; } jsurface = ffpipeline_get_surface_as_global_ref(env, pipeline); ret = configure_codec_l(env, node, jsurface); J4A_DeleteGlobalRef__p(env, &jsurface); if (ret != 0) goto fail; ffp_set_video_codec_info(ffp, MEDIACODEC_MODULE_NAME, opaque->mcc.codec_name); opaque->off_buf_out = 0; if (opaque->n_buf_out) { int i; opaque->amc_buf_out = calloc(opaque->n_buf_out, sizeof(*opaque->amc_buf_out)); assert(opaque->amc_buf_out != NULL); for (i = 0; i < opaque->n_buf_out; i++) opaque->amc_buf_out[i].pts = AV_NOPTS_VALUE; } SDL_SpeedSamplerReset(&opaque->sampler); ffp->stat.vdec_type = FFP_PROPV_DECODER_MEDIACODEC; return 0; fail: ret = -1; ffpipenode_free_p(&node); return ret; } IJKFF_Pipenode *ffpipenode_init_decoder_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pipeline, SDL_Vout *vout) { if (SDL_Android_GetApiLevel() < IJK_API_16_JELLY_BEAN) return NULL; if (!ffp || !ffp->is) return NULL; IJKFF_Pipenode *node = ffpipenode_alloc(sizeof(IJKFF_Pipenode_Opaque)); if (!node) return node; VideoState *is = ffp->is; IJKFF_Pipenode_Opaque *opaque = node->opaque; JNIEnv *env = NULL; node->func_destroy = func_destroy; if (ffp->mediacodec_sync) { node->func_run_sync = func_run_sync_loop; } else { node->func_run_sync = func_run_sync; } node->func_flush = func_flush; opaque->pipeline = pipeline; opaque->ffp = ffp; opaque->decoder = &is->viddec; opaque->weak_vout = vout; opaque->acodec_mutex = SDL_CreateMutex(); opaque->acodec_cond = SDL_CreateCond(); opaque->acodec_first_dequeue_output_mutex = SDL_CreateMutex(); opaque->acodec_first_dequeue_output_cond = SDL_CreateCond(); opaque->any_input_mutex = SDL_CreateMutex(); opaque->any_input_cond = SDL_CreateCond(); if (!opaque->acodec_cond || !opaque->acodec_cond || !opaque->acodec_first_dequeue_output_mutex || !opaque->acodec_first_dequeue_output_cond) { ALOGE("%s:open_video_decoder: SDL_CreateCond() failed\n", __func__); goto fail; } opaque->codecpar = avcodec_parameters_alloc(); if (!opaque->codecpar) goto fail; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s:create: SetupThreadEnv failed\n", __func__); goto fail; } ALOGI("%s:use default mediacodec name: %s\n", __func__, ffp->mediacodec_default_name); strcpy(opaque->mcc.codec_name, ffp->mediacodec_default_name); opaque->acodec = SDL_AMediaCodecJava_createByCodecName(env, ffp->mediacodec_default_name); if (!opaque->acodec) { goto fail; } return node; fail: ALOGW("%s: init fail\n", __func__); ffpipenode_free_p(&node); return NULL; } IJKFF_Pipenode *ffpipenode_create_video_decoder_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pipeline, SDL_Vout *vout) { ALOGD("ffpipenode_create_video_decoder_from_android_mediacodec()\n"); if (SDL_Android_GetApiLevel() < IJK_API_16_JELLY_BEAN) return NULL; if (!ffp || !ffp->is) return NULL; IJKFF_Pipenode *node = ffpipenode_alloc(sizeof(IJKFF_Pipenode_Opaque)); if (!node) return node; VideoState *is = ffp->is; IJKFF_Pipenode_Opaque *opaque = node->opaque; JNIEnv *env = NULL; int ret = 0; jobject jsurface = NULL; node->func_destroy = func_destroy; if (ffp->mediacodec_sync) { node->func_run_sync = func_run_sync_loop; } else { node->func_run_sync = func_run_sync; } node->func_flush = func_flush; opaque->pipeline = pipeline; opaque->ffp = ffp; opaque->decoder = &is->viddec; opaque->weak_vout = vout; opaque->codecpar = avcodec_parameters_alloc(); if (!opaque->codecpar) goto fail; ret = avcodec_parameters_from_context(opaque->codecpar, opaque->decoder->avctx); if (ret) goto fail; switch (opaque->codecpar->codec_id) { case AV_CODEC_ID_H264: if (!ffp->mediacodec_avc && !ffp->mediacodec_all_videos) { ALOGE("%s: MediaCodec: AVC/H264 is disabled. codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } switch (opaque->codecpar->profile) { case FF_PROFILE_H264_BASELINE: ALOGI("%s: MediaCodec: H264_BASELINE: enabled\n", __func__); break; case FF_PROFILE_H264_CONSTRAINED_BASELINE: ALOGI("%s: MediaCodec: H264_CONSTRAINED_BASELINE: enabled\n", __func__); break; case FF_PROFILE_H264_MAIN: ALOGI("%s: MediaCodec: H264_MAIN: enabled\n", __func__); break; case FF_PROFILE_H264_EXTENDED: ALOGI("%s: MediaCodec: H264_EXTENDED: enabled\n", __func__); break; case FF_PROFILE_H264_HIGH: ALOGI("%s: MediaCodec: H264_HIGH: enabled\n", __func__); break; case FF_PROFILE_H264_HIGH_10: ALOGW("%s: MediaCodec: H264_HIGH_10: disabled\n", __func__); goto fail; case FF_PROFILE_H264_HIGH_10_INTRA: ALOGW("%s: MediaCodec: H264_HIGH_10_INTRA: disabled\n", __func__); goto fail; case FF_PROFILE_H264_HIGH_422: ALOGW("%s: MediaCodec: H264_HIGH_10_422: disabled\n", __func__); goto fail; case FF_PROFILE_H264_HIGH_422_INTRA: ALOGW("%s: MediaCodec: H264_HIGH_10_INTRA: disabled\n", __func__); goto fail; case FF_PROFILE_H264_HIGH_444: ALOGW("%s: MediaCodec: H264_HIGH_10_444: disabled\n", __func__); goto fail; case FF_PROFILE_H264_HIGH_444_PREDICTIVE: ALOGW("%s: MediaCodec: H264_HIGH_444_PREDICTIVE: disabled\n", __func__); goto fail; case FF_PROFILE_H264_HIGH_444_INTRA: ALOGW("%s: MediaCodec: H264_HIGH_444_INTRA: disabled\n", __func__); goto fail; case FF_PROFILE_H264_CAVLC_444: ALOGW("%s: MediaCodec: H264_CAVLC_444: disabled\n", __func__); goto fail; default: ALOGW("%s: MediaCodec: (%d) unknown profile: disabled\n", __func__, opaque->codecpar->profile); goto fail; } strcpy(opaque->mcc.mime_type, SDL_AMIME_VIDEO_AVC); opaque->mcc.profile = opaque->codecpar->profile; opaque->mcc.level = opaque->codecpar->level; break; case AV_CODEC_ID_HEVC: if (!ffp->mediacodec_hevc && !ffp->mediacodec_all_videos) { ALOGE("%s: MediaCodec/HEVC is disabled. codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } strcpy(opaque->mcc.mime_type, SDL_AMIME_VIDEO_HEVC); opaque->mcc.profile = opaque->codecpar->profile; opaque->mcc.level = opaque->codecpar->level; break; case AV_CODEC_ID_MPEG2VIDEO: if (!ffp->mediacodec_mpeg2 && !ffp->mediacodec_all_videos) { ALOGE("%s: MediaCodec/MPEG2VIDEO is disabled. codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } strcpy(opaque->mcc.mime_type, SDL_AMIME_VIDEO_MPEG2VIDEO); opaque->mcc.profile = opaque->codecpar->profile; opaque->mcc.level = opaque->codecpar->level; break; case AV_CODEC_ID_MPEG4: if (!ffp->mediacodec_mpeg4 && !ffp->mediacodec_all_videos) { ALOGE("%s: MediaCodec/MPEG4 is disabled. codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } if ((opaque->codecpar->codec_tag & 0x0000FFFF) == 0x00005844) { ALOGE("%s: divx is not supported \n", __func__); goto fail; } strcpy(opaque->mcc.mime_type, SDL_AMIME_VIDEO_MPEG4); opaque->mcc.profile = opaque->codecpar->profile >= 0 ? opaque->codecpar->profile : 0; opaque->mcc.level = opaque->codecpar->level >= 0 ? opaque->codecpar->level : 1; break; default: ALOGE("%s:create: not H264 or H265/HEVC, codec_id:%d \n", __func__, opaque->codecpar->codec_id); goto fail; } if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s:create: SetupThreadEnv failed\n", __func__); goto fail; } opaque->acodec_mutex = SDL_CreateMutex(); opaque->acodec_cond = SDL_CreateCond(); opaque->acodec_first_dequeue_output_mutex = SDL_CreateMutex(); opaque->acodec_first_dequeue_output_cond = SDL_CreateCond(); opaque->any_input_mutex = SDL_CreateMutex(); opaque->any_input_cond = SDL_CreateCond(); if (!opaque->acodec_cond || !opaque->acodec_cond || !opaque->acodec_first_dequeue_output_mutex || !opaque->acodec_first_dequeue_output_cond) { ALOGE("%s:open_video_decoder: SDL_CreateCond() failed\n", __func__); goto fail; } ret = recreate_format_l(env, node); if (ret) { ALOGE("amc: recreate_format_l failed\n"); goto fail; } if (!ffpipeline_select_mediacodec_l(pipeline, &opaque->mcc) || !opaque->mcc.codec_name[0]) { ALOGE("amc: no suitable codec\n"); goto fail; } jsurface = ffpipeline_get_surface_as_global_ref(env, pipeline); ret = reconfigure_codec_l(env, node, jsurface); J4A_DeleteGlobalRef__p(env, &jsurface); if (ret != 0) goto fail; ffp_set_video_codec_info(ffp, MEDIACODEC_MODULE_NAME, opaque->mcc.codec_name); opaque->off_buf_out = 0; if (opaque->n_buf_out) { int i; opaque->amc_buf_out = calloc(opaque->n_buf_out, sizeof(*opaque->amc_buf_out)); assert(opaque->amc_buf_out != NULL); for (i = 0; i < opaque->n_buf_out; i++) opaque->amc_buf_out[i].pts = AV_NOPTS_VALUE; } SDL_SpeedSamplerReset(&opaque->sampler); ffp->stat.vdec_type = FFP_PROPV_DECODER_MEDIACODEC; return node; fail: ffpipenode_free_p(&node); return NULL; } ================================================ FILE: ijkmedia/ijkplayer/android/pipeline/ffpipenode_android_mediacodec_vdec.h ================================================ /* * ffpipenode_android_mediacodec_vdec.h * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__FF_FFPIPENODE_ANDROID_MEDIACODEC_VDEC_H #define FFPLAY__FF_FFPIPENODE_ANDROID_MEDIACODEC_VDEC_H #include "../../ff_ffpipenode.h" #include "../../ff_ffpipeline.h" #include "ijksdl/ijksdl_vout.h" typedef struct FFPlayer FFPlayer; IJKFF_Pipenode *ffpipenode_create_video_decoder_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pipeline, SDL_Vout *vout); IJKFF_Pipenode *ffpipenode_init_decoder_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pipeline, SDL_Vout *vout); int ffpipenode_config_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pipeline, SDL_Vout *vout, IJKFF_Pipenode *node); #endif ================================================ FILE: ijkmedia/ijkplayer/android/pipeline/h264_nal.h ================================================ /* * h264_nal.h * * Copyright (c) 2010-2011 Bilibili * Copyright (c) 2010-2011 Jean-Baptiste Kempf * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "libavcodec/avcodec.h" #include "ijksdl/ijksdl_log.h" #if 1 /* Parse the SPS/PPS Metadata and convert it to annex b format */ static int convert_sps_pps( const uint8_t *p_buf, size_t i_buf_size, uint8_t *p_out_buf, size_t i_out_buf_size, size_t *p_sps_pps_size, size_t *p_nal_size) { // int i_profile; uint32_t i_data_size = i_buf_size, i_nal_size, i_sps_pps_size = 0; unsigned int i_loop_end; /* */ if( i_data_size < 7 ) { ALOGE( "Input Metadata too small" ); return -1; } /* Read infos in first 6 bytes */ // i_profile = (p_buf[1] << 16) | (p_buf[2] << 8) | p_buf[3]; if (p_nal_size) *p_nal_size = (p_buf[4] & 0x03) + 1; p_buf += 5; i_data_size -= 5; for ( unsigned int j = 0; j < 2; j++ ) { /* First time is SPS, Second is PPS */ if( i_data_size < 1 ) { ALOGE( "PPS too small after processing SPS/PPS %u", i_data_size ); return -1; } i_loop_end = p_buf[0] & (j == 0 ? 0x1f : 0xff); p_buf++; i_data_size--; for ( unsigned int i = 0; i < i_loop_end; i++) { if( i_data_size < 2 ) { ALOGE( "SPS is too small %u", i_data_size ); return -1; } i_nal_size = (p_buf[0] << 8) | p_buf[1]; p_buf += 2; i_data_size -= 2; if( i_data_size < i_nal_size ) { ALOGE( "SPS size does not match NAL specified size %u", i_data_size ); return -1; } if( i_sps_pps_size + 4 + i_nal_size > i_out_buf_size ) { ALOGE( "Output SPS/PPS buffer too small" ); return -1; } p_out_buf[i_sps_pps_size++] = 0; p_out_buf[i_sps_pps_size++] = 0; p_out_buf[i_sps_pps_size++] = 0; p_out_buf[i_sps_pps_size++] = 1; memcpy( p_out_buf + i_sps_pps_size, p_buf, i_nal_size ); i_sps_pps_size += i_nal_size; p_buf += i_nal_size; i_data_size -= i_nal_size; } } *p_sps_pps_size = i_sps_pps_size; return 0; } #endif #if 1 /* Convert H.264 NAL format to annex b in-place */ typedef struct H264ConvertState { uint32_t nal_len; uint32_t nal_pos; } H264ConvertState; static void convert_h264_to_annexb( uint8_t *p_buf, size_t i_len, size_t i_nal_size, H264ConvertState *state ) { if( i_nal_size < 3 || i_nal_size > 4 ) return; /* This only works for NAL sizes 3-4 */ while( i_len > 0 ) { if( state->nal_pos < i_nal_size ) { unsigned int i; for( i = 0; state->nal_pos < i_nal_size && i < i_len; i++, state->nal_pos++ ) { state->nal_len = (state->nal_len << 8) | p_buf[i]; p_buf[i] = 0; } if( state->nal_pos < i_nal_size ) return; p_buf[i - 1] = 1; p_buf += i; i_len -= i; } if( state->nal_len > INT_MAX ) return; if( state->nal_len > i_len ) { state->nal_len -= i_len; return; } else { p_buf += state->nal_len; i_len -= state->nal_len; state->nal_len = 0; state->nal_pos = 0; } } } #endif ================================================ FILE: ijkmedia/ijkplayer/android/pipeline/hevc_nal.h ================================================ /* * hevc_nal.h * * Copyright (c) 2015 Chodison Chen * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "libavcodec/avcodec.h" #include "ijksdl/ijksdl_log.h" /* Inspired by libavcodec/hevc.c */ int convert_hevc_nal_units(const uint8_t *p_buf,size_t i_buf_size, uint8_t *p_out_buf,size_t i_out_buf_size, size_t *p_sps_pps_size,size_t *p_nal_size) { int i, num_arrays; const uint8_t *p_end = p_buf + i_buf_size; uint32_t i_sps_pps_size = 0; if( i_buf_size <= 3 || ( !p_buf[0] && !p_buf[1] && p_buf[2] <= 1 ) ) return -1; if( p_end - p_buf < 23 ) { ALOGE( "Input Metadata too small" ); return -1; } p_buf += 21; if( p_nal_size ) *p_nal_size = (*p_buf & 0x03) + 1; p_buf++; num_arrays = *p_buf++; for( i = 0; i < num_arrays; i++ ) { int type, cnt, j; if( p_end - p_buf < 3 ) { ALOGE( "Input Metadata too small" ); return -1; } type = *(p_buf++) & 0x3f; (void)(type); cnt = p_buf[0] << 8 | p_buf[1]; p_buf += 2; for( j = 0; j < cnt; j++ ) { int i_nal_size; if( p_end - p_buf < 2 ) { ALOGE( "Input Metadata too small" ); return -1; } i_nal_size = p_buf[0] << 8 | p_buf[1]; p_buf += 2; if( i_nal_size < 0 || p_end - p_buf < i_nal_size ) { ALOGE( "NAL unit size does not match Input Metadata size" ); return -1; } if( i_sps_pps_size + 4 + i_nal_size > i_out_buf_size ) { ALOGE( "Output buffer too small" ); return -1; } p_out_buf[i_sps_pps_size++] = 0; p_out_buf[i_sps_pps_size++] = 0; p_out_buf[i_sps_pps_size++] = 0; p_out_buf[i_sps_pps_size++] = 1; memcpy(p_out_buf + i_sps_pps_size, p_buf, i_nal_size); p_buf += i_nal_size; i_sps_pps_size += i_nal_size; } } *p_sps_pps_size = i_sps_pps_size; return 0; } ================================================ FILE: ijkmedia/ijkplayer/android/pipeline/mpeg4_esds.h ================================================ /* * mpeg4_esds.h * * Copyright (c) 2015 yuazhen * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "libavcodec/avcodec.h" static void restore_mpeg4_esds(AVCodecParameters *codecpar, uint8_t *p_buf, size_t i_buf_size, size_t i_es_dscr_length, size_t i_dec_dscr_length, uint8_t *p_esds_buf) { p_esds_buf[0] = 0x03; p_esds_buf[1] = 0x80; p_esds_buf[2] = 0x80; p_esds_buf[3] = 0x80; p_esds_buf[4] = i_es_dscr_length; uint16_t *es_id = (uint16_t *)&p_esds_buf[5]; *es_id = htobe16(1); p_esds_buf[8] = 0x04; p_esds_buf[9] = 0x80; p_esds_buf[10] = 0x80; p_esds_buf[11] = 0x80; p_esds_buf[12] = i_dec_dscr_length; p_esds_buf[13] = 0x20; p_esds_buf[14] = 0x11; uint32_t *max_br = (uint32_t *)&p_esds_buf[18]; uint32_t *avg_br = (uint32_t *)&p_esds_buf[22]; *max_br = *avg_br = htobe32(codecpar->bit_rate); p_esds_buf[26] = 0x05; p_esds_buf[27] = 0x80; p_esds_buf[28] = 0x80; p_esds_buf[29] = 0x80; p_esds_buf[30] = i_buf_size; memcpy(&p_esds_buf[31], p_buf, i_buf_size); p_esds_buf[31+i_buf_size] = 0x06; p_esds_buf[31+i_buf_size+1] = 0x80; p_esds_buf[31+i_buf_size+2] = 0x80; p_esds_buf[31+i_buf_size+3] = 0x80; p_esds_buf[31+i_buf_size+4] = 0x01; p_esds_buf[31+i_buf_size+5] = 0x02; } ================================================ FILE: ijkmedia/ijkplayer/config.h ================================================ /* * Copyright (c) 2015 Bilibili * Copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__CONFIG_H #define FFPLAY__CONFIG_H #include "libffmpeg/config.h" // FIXME: merge filter related code and enable it // remove these lines to enable avfilter #ifdef CONFIG_AVFILTER #undef CONFIG_AVFILTER #endif #define CONFIG_AVFILTER 0 #ifdef FFP_MERGE #undef FFP_MERGE #endif #ifdef FFP_SUB #undef FFP_SUB #endif #ifndef FFMPEG_LOG_TAG #define FFMPEG_LOG_TAG "IJKFFMPEG" #endif #endif//FFPLAY__CONFIG_H ================================================ FILE: ijkmedia/ijkplayer/ff_cmdutils.c ================================================ /* * ff_cmdutils.c * based on ffmpeg/cmdutils.c * * Copyright (c) 2000-2003 Bilibili * Copyright (c) 2000-2003 Fabrice Bellard * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ff_cmdutils.h" #include "libavutil/display.h" #include "libavutil/eval.h" // MERGE: sws_opts // MERGE: swr_opts // MERGE: format_opts, codec_opts, resample_opts // MERGE: this_year // MERGE: report_file; // MERGE: init_opts // MERGE: uninit_opts // MERGE: log_callback_help // MERGE: log_callback_report(void *ptr, int level, const char *fmt, va_list vl) // MERGE: parse_number_or_die // MERGE: parse_time_or_die // MERGE: show_help_options // MERGE: show_help_children // MERGE: find_option // MERGE: #include // MERGE: #include // MERGE: win32_argv_utf8 // MERGE: win32_argc // MERGE: prepare_app_arguments // MERGE: write_option // MERGE: parse_option // MERGE: parse_options // MERGE: parse_optgroup // MERGE: locate_option // MERGE: dump_argument // MERGE: parse_loglevel // MERGE: #define FLAGS // MERGE: opt_default // MERGE: match_group_separator // MERGE: finish_group // MERGE: add_opt // MERGE: init_parse_context // MERGE: uninit_parse_context // MERGE: split_commandline // MERGE: opt_loglevel // MERGE: expand_filename_template // MERGE: init_report // MERGE: opt_report // MERGE: opt_max_alloc // MERGE: opt_cpuflags // MERGE: opt_timelimit void print_error(const char *filename, int err) { char errbuf[128]; const char *errbuf_ptr = errbuf; if (av_strerror(err, errbuf, sizeof(errbuf)) < 0) errbuf_ptr = strerror(AVUNERROR(err)); av_log(NULL, AV_LOG_ERROR, "%s: %s\n", filename, errbuf_ptr); } // MERGE: warned_cfg // MERGE: INDENT // MERGE: SHOW_VERSION // MERGE: SHOW_CONFIG // MERGE: SHOW_COPYRIGHT // MERGE: PRINT_LIB_INFO // MERGE: print_all_libs_info // MERGE: print_program_info // MERGE: show_banner // MERGE: show_version // MERGE: show_license // MERGE: show_formats // MERGE: PRINT_CODEC_SUPPORTED // MERGE: print_codec // MERGE: get_media_type_char // MERGE: next_codec_for_id // MERGE: compare_codec_desc // MERGE: get_codecs_sorted // MERGE: print_codecs_for_id // MERGE: show_codecs // MERGE: print_codecs // MERGE: show_decoders // MERGE: show_encoders // MERGE: show_bsfs // MERGE: show_protocols // MERGE: show_filters // MERGE: show_pix_fmts // MERGE: show_layouts // MERGE: show_sample_fmts // MERGE: show_help_codec // MERGE: show_help_demuxer // MERGE: show_help_muxer // MERGE: show_help // MERGE: read_yesno // MERGE: cmdutils_read_file // MERGE: get_preset_file static int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec) { int ret = avformat_match_stream_specifier(s, st, spec); if (ret < 0) av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec); return ret; } AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id, AVFormatContext *s, AVStream *st, AVCodec *codec) { AVDictionary *ret = NULL; AVDictionaryEntry *t = NULL; int flags = s->oformat ? AV_OPT_FLAG_ENCODING_PARAM : AV_OPT_FLAG_DECODING_PARAM; char prefix = 0; const AVClass *cc = avcodec_get_class(); if (!codec) codec = s->oformat ? avcodec_find_encoder(codec_id) : avcodec_find_decoder(codec_id); switch (st->codecpar->codec_type) { case AVMEDIA_TYPE_VIDEO: prefix = 'v'; flags |= AV_OPT_FLAG_VIDEO_PARAM; break; case AVMEDIA_TYPE_AUDIO: prefix = 'a'; flags |= AV_OPT_FLAG_AUDIO_PARAM; break; case AVMEDIA_TYPE_SUBTITLE: prefix = 's'; flags |= AV_OPT_FLAG_SUBTITLE_PARAM; break; default: break; } while ((t = av_dict_get(opts, "", t, AV_DICT_IGNORE_SUFFIX))) { char *p = strchr(t->key, ':'); /* check stream specification in opt name */ if (p) switch (check_stream_specifier(s, st, p + 1)) { case 1: *p = 0; break; case 0: continue; default: return NULL; } if (av_opt_find(&cc, t->key, NULL, flags, AV_OPT_SEARCH_FAKE_OBJ) || (codec && codec->priv_class && av_opt_find(&codec->priv_class, t->key, NULL, flags, AV_OPT_SEARCH_FAKE_OBJ))) av_dict_set(&ret, t->key, t->value, 0); else if (t->key[0] == prefix && av_opt_find(&cc, t->key + 1, NULL, flags, AV_OPT_SEARCH_FAKE_OBJ)) av_dict_set(&ret, t->key + 1, t->value, 0); if (p) *p = ':'; } return ret; } AVDictionary **setup_find_stream_info_opts(AVFormatContext *s, AVDictionary *codec_opts) { int i; AVDictionary **opts; if (!s->nb_streams) return NULL; opts = av_mallocz(s->nb_streams * sizeof(*opts)); if (!opts) { av_log(NULL, AV_LOG_ERROR, "Could not alloc memory for stream options.\n"); return NULL; } for (i = 0; i < s->nb_streams; i++) opts[i] = filter_codec_opts(codec_opts, s->streams[i]->codecpar->codec_id, s, s->streams[i], NULL); return opts; } void *grow_array(void *array, int elem_size, int *size, int new_size) { if (new_size >= INT_MAX / elem_size) { av_log(NULL, AV_LOG_ERROR, "Array too big.\n"); return NULL; } if (*size < new_size) { uint8_t *tmp = av_realloc_array(array, new_size, elem_size); if (!tmp) { av_log(NULL, AV_LOG_ERROR, "Could not alloc buffer.\n"); return NULL; } memset(tmp + *size*elem_size, 0, (new_size-*size) * elem_size); *size = new_size; return tmp; } return array; } double get_rotation(AVStream *st) { AVDictionaryEntry *rotate_tag = av_dict_get(st->metadata, "rotate", NULL, 0); uint8_t* displaymatrix = av_stream_get_side_data(st, AV_PKT_DATA_DISPLAYMATRIX, NULL); double theta = 0; if (rotate_tag && *rotate_tag->value && strcmp(rotate_tag->value, "0")) { char *tail; theta = av_strtod(rotate_tag->value, &tail); if (*tail) theta = 0; } if (displaymatrix && !theta) theta = -av_display_rotation_get((int32_t*) displaymatrix); theta -= 360*floor(theta/360 + 0.9/360); if (fabs(theta - 90*round(theta/90)) > 2) av_log(NULL, AV_LOG_WARNING, "Odd rotation angle.\n" "If you want to help, upload a sample " "of this file to ftp://upload.ffmpeg.org/incoming/ " "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)"); return theta; } ================================================ FILE: ijkmedia/ijkplayer/ff_cmdutils.h ================================================ /* * ff_cmdutils.h * based on ffmpeg/cmdutils.h * * Copyright (c) 2000-2003 Bilibili * Copyright (c) 2000-2003 Fabrice Bellard * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__FF_CMDUTILS_H #define FFPLAY__FF_CMDUTILS_H #include "ff_ffinc.h" void print_error(const char *filename, int err); AVDictionary **setup_find_stream_info_opts(AVFormatContext *s, AVDictionary *codec_opts); AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id, AVFormatContext *s, AVStream *st, AVCodec *codec); /** * Realloc array to hold new_size elements of elem_size. * Calls exit() on failure. * * @param array array to reallocate * @param elem_size size in bytes of each element * @param size new element count will be written here * @param new_size number of elements to place in reallocated array * @return reallocated array */ void *grow_array(void *array, int elem_size, int *size, int new_size); #define GROW_ARRAY(array, nb_elems)\ array = grow_array(array, sizeof(*array), &nb_elems, nb_elems + 1) double get_rotation(AVStream *st); #endif ================================================ FILE: ijkmedia/ijkplayer/ff_fferror.h ================================================ /* * ff_fferror.h * * Copyright (c) 2003 Bilibili * Copyright (c) 2003 Fabrice Bellard * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__FF_FFERROR_H #define FFPLAY__FF_FFERROR_H #define EIJK_FAILED -1 #define EIJK_OUT_OF_MEMORY -2 #define EIJK_INVALID_STATE -3 #define EIJK_NULL_IS_PTR -4 #endif ================================================ FILE: ijkmedia/ijkplayer/ff_ffinc.h ================================================ /* * ff_ffinc.h * ffmpeg headers * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__FF_FFINC_H #define FFPLAY__FF_FFINC_H #include #include #include "libavutil/avstring.h" #include "libavutil/time.h" #include "libavformat/avformat.h" #include "libavcodec/avfft.h" #include "libswscale/swscale.h" #include "libavutil/application.h" #include "libavutil/base64.h" #include "libavutil/error.h" #include "libavutil/opt.h" #include "libavutil/version.h" #include "libswresample/swresample.h" #include "ijksdl/ijksdl.h" typedef int (*ijk_inject_callback)(void *opaque, int type, void *data, size_t data_size); #define FFP_OPT_CATEGORY_FORMAT 1 #define FFP_OPT_CATEGORY_CODEC 2 #define FFP_OPT_CATEGORY_SWS 3 #define FFP_OPT_CATEGORY_PLAYER 4 #define FFP_OPT_CATEGORY_SWR 5 #endif ================================================ FILE: ijkmedia/ijkplayer/ff_ffmsg.h ================================================ /* * ff_ffmsg.h * based on PacketQueue in ffplay.c * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__FF_FFMSG_H #define FFPLAY__FF_FFMSG_H #define FFP_MSG_FLUSH 0 #define FFP_MSG_ERROR 100 /* arg1 = error */ #define FFP_MSG_PREPARED 200 #define FFP_MSG_COMPLETED 300 #define FFP_MSG_VIDEO_SIZE_CHANGED 400 /* arg1 = width, arg2 = height */ #define FFP_MSG_SAR_CHANGED 401 /* arg1 = sar.num, arg2 = sar.den */ #define FFP_MSG_VIDEO_RENDERING_START 402 #define FFP_MSG_AUDIO_RENDERING_START 403 #define FFP_MSG_VIDEO_ROTATION_CHANGED 404 /* arg1 = degree */ #define FFP_MSG_AUDIO_DECODED_START 405 #define FFP_MSG_VIDEO_DECODED_START 406 #define FFP_MSG_OPEN_INPUT 407 #define FFP_MSG_FIND_STREAM_INFO 408 #define FFP_MSG_COMPONENT_OPEN 409 #define FFP_MSG_VIDEO_SEEK_RENDERING_START 410 #define FFP_MSG_AUDIO_SEEK_RENDERING_START 411 #define FFP_MSG_BUFFERING_START 500 #define FFP_MSG_BUFFERING_END 501 #define FFP_MSG_BUFFERING_UPDATE 502 /* arg1 = buffering head position in time, arg2 = minimum percent in time or bytes */ #define FFP_MSG_BUFFERING_BYTES_UPDATE 503 /* arg1 = cached data in bytes, arg2 = high water mark */ #define FFP_MSG_BUFFERING_TIME_UPDATE 504 /* arg1 = cached duration in milliseconds, arg2 = high water mark */ #define FFP_MSG_SEEK_COMPLETE 600 /* arg1 = seek position, arg2 = error */ #define FFP_MSG_PLAYBACK_STATE_CHANGED 700 #define FFP_MSG_TIMED_TEXT 800 #define FFP_MSG_ACCURATE_SEEK_COMPLETE 900 /* arg1 = current position*/ #define FFP_MSG_GET_IMG_STATE 1000 /* arg1 = timestamp, arg2 = result code, obj = file name*/ #define FFP_MSG_VIDEO_DECODER_OPEN 10001 #define FFP_REQ_START 20001 #define FFP_REQ_PAUSE 20002 #define FFP_REQ_SEEK 20003 #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 #define FFP_PROP_FLOAT_PLAYBACK_VOLUME 10006 #define FFP_PROP_FLOAT_AVDELAY 10004 #define FFP_PROP_FLOAT_AVDIFF 10005 #define FFP_PROP_FLOAT_DROP_FRAME_RATE 10007 #define FFP_PROP_INT64_SELECTED_VIDEO_STREAM 20001 #define FFP_PROP_INT64_SELECTED_AUDIO_STREAM 20002 #define FFP_PROP_INT64_SELECTED_TIMEDTEXT_STREAM 20011 #define FFP_PROP_INT64_VIDEO_DECODER 20003 #define FFP_PROP_INT64_AUDIO_DECODER 20004 #define FFP_PROPV_DECODER_UNKNOWN 0 #define FFP_PROPV_DECODER_AVCODEC 1 #define FFP_PROPV_DECODER_MEDIACODEC 2 #define FFP_PROPV_DECODER_VIDEOTOOLBOX 3 #define FFP_PROP_INT64_VIDEO_CACHED_DURATION 20005 #define FFP_PROP_INT64_AUDIO_CACHED_DURATION 20006 #define FFP_PROP_INT64_VIDEO_CACHED_BYTES 20007 #define FFP_PROP_INT64_AUDIO_CACHED_BYTES 20008 #define FFP_PROP_INT64_VIDEO_CACHED_PACKETS 20009 #define FFP_PROP_INT64_AUDIO_CACHED_PACKETS 20010 #define FFP_PROP_INT64_BIT_RATE 20100 #define FFP_PROP_INT64_TCP_SPEED 20200 #define FFP_PROP_INT64_ASYNC_STATISTIC_BUF_BACKWARDS 20201 #define FFP_PROP_INT64_ASYNC_STATISTIC_BUF_FORWARDS 20202 #define FFP_PROP_INT64_ASYNC_STATISTIC_BUF_CAPACITY 20203 #define FFP_PROP_INT64_TRAFFIC_STATISTIC_BYTE_COUNT 20204 #define FFP_PROP_INT64_LATEST_SEEK_LOAD_DURATION 20300 #define FFP_PROP_INT64_CACHE_STATISTIC_PHYSICAL_POS 20205 #define FFP_PROP_INT64_CACHE_STATISTIC_FILE_FORWARDS 20206 #define FFP_PROP_INT64_CACHE_STATISTIC_FILE_POS 20207 #define FFP_PROP_INT64_CACHE_STATISTIC_COUNT_BYTES 20208 #define FFP_PROP_INT64_LOGICAL_FILE_SIZE 20209 #define FFP_PROP_INT64_SHARE_CACHE_DATA 20210 #define FFP_PROP_INT64_IMMEDIATE_RECONNECT 20211 #endif ================================================ FILE: ijkmedia/ijkplayer/ff_ffmsg_queue.h ================================================ /* * ff_ffmsg_queue.h * based on PacketQueue in ffplay.c * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__FF_FFMSG_QUEUE_H #define FFPLAY__FF_FFMSG_QUEUE_H #include "ff_ffinc.h" #include "ff_ffmsg.h" // #define FFP_SHOW_MSG_RECYCLE typedef struct AVMessage { int what; int arg1; int arg2; void *obj; void (*free_l)(void *obj); struct AVMessage *next; } AVMessage; typedef struct MessageQueue { AVMessage *first_msg, *last_msg; int nb_messages; int abort_request; SDL_mutex *mutex; SDL_cond *cond; AVMessage *recycle_msg; int recycle_count; int alloc_count; } MessageQueue; inline static void msg_free_res(AVMessage *msg) { if (!msg || !msg->obj) return; assert(msg->free_l); msg->free_l(msg->obj); msg->obj = NULL; } inline static int msg_queue_put_private(MessageQueue *q, AVMessage *msg) { AVMessage *msg1; if (q->abort_request) return -1; #ifdef FFP_MERGE msg1 = av_malloc(sizeof(AVMessage)); #else msg1 = q->recycle_msg; if (msg1) { q->recycle_msg = msg1->next; q->recycle_count++; } else { q->alloc_count++; msg1 = av_malloc(sizeof(AVMessage)); } #ifdef FFP_SHOW_MSG_RECYCLE int total_count = q->recycle_count + q->alloc_count; if (!(total_count % 10)) { av_log(NULL, AV_LOG_DEBUG, "msg-recycle \t%d + \t%d = \t%d\n", q->recycle_count, q->alloc_count, total_count); } #endif #endif if (!msg1) return -1; *msg1 = *msg; msg1->next = NULL; if (!q->last_msg) q->first_msg = msg1; else q->last_msg->next = msg1; q->last_msg = msg1; q->nb_messages++; SDL_CondSignal(q->cond); return 0; } inline static int msg_queue_put(MessageQueue *q, AVMessage *msg) { int ret; SDL_LockMutex(q->mutex); ret = msg_queue_put_private(q, msg); SDL_UnlockMutex(q->mutex); return ret; } inline static void msg_init_msg(AVMessage *msg) { memset(msg, 0, sizeof(AVMessage)); } inline static void msg_queue_put_simple1(MessageQueue *q, int what) { AVMessage msg; msg_init_msg(&msg); msg.what = what; msg_queue_put(q, &msg); } inline static void msg_queue_put_simple2(MessageQueue *q, int what, int arg1) { AVMessage msg; msg_init_msg(&msg); msg.what = what; msg.arg1 = arg1; msg_queue_put(q, &msg); } inline static void msg_queue_put_simple3(MessageQueue *q, int what, int arg1, int arg2) { AVMessage msg; msg_init_msg(&msg); msg.what = what; msg.arg1 = arg1; msg.arg2 = arg2; msg_queue_put(q, &msg); } inline static void msg_obj_free_l(void *obj) { av_free(obj); } inline static void msg_queue_put_simple4(MessageQueue *q, int what, int arg1, int arg2, void *obj, int obj_len) { AVMessage msg; msg_init_msg(&msg); msg.what = what; msg.arg1 = arg1; msg.arg2 = arg2; msg.obj = av_malloc(obj_len); memcpy(msg.obj, obj, obj_len); msg.free_l = msg_obj_free_l; msg_queue_put(q, &msg); } inline static void msg_queue_init(MessageQueue *q) { memset(q, 0, sizeof(MessageQueue)); q->mutex = SDL_CreateMutex(); q->cond = SDL_CreateCond(); q->abort_request = 1; } inline static void msg_queue_flush(MessageQueue *q) { AVMessage *msg, *msg1; SDL_LockMutex(q->mutex); for (msg = q->first_msg; msg != NULL; msg = msg1) { msg1 = msg->next; #ifdef FFP_MERGE av_freep(&msg); #else msg->next = q->recycle_msg; q->recycle_msg = msg; #endif } q->last_msg = NULL; q->first_msg = NULL; q->nb_messages = 0; SDL_UnlockMutex(q->mutex); } inline static void msg_queue_destroy(MessageQueue *q) { msg_queue_flush(q); SDL_LockMutex(q->mutex); while(q->recycle_msg) { AVMessage *msg = q->recycle_msg; if (msg) q->recycle_msg = msg->next; msg_free_res(msg); av_freep(&msg); } SDL_UnlockMutex(q->mutex); SDL_DestroyMutex(q->mutex); SDL_DestroyCond(q->cond); } inline static void msg_queue_abort(MessageQueue *q) { SDL_LockMutex(q->mutex); q->abort_request = 1; SDL_CondSignal(q->cond); SDL_UnlockMutex(q->mutex); } inline static void msg_queue_start(MessageQueue *q) { SDL_LockMutex(q->mutex); q->abort_request = 0; AVMessage msg; msg_init_msg(&msg); msg.what = FFP_MSG_FLUSH; msg_queue_put_private(q, &msg); SDL_UnlockMutex(q->mutex); } /* return < 0 if aborted, 0 if no msg and > 0 if msg. */ inline static int msg_queue_get(MessageQueue *q, AVMessage *msg, int block) { AVMessage *msg1; int ret; SDL_LockMutex(q->mutex); for (;;) { if (q->abort_request) { ret = -1; break; } msg1 = q->first_msg; if (msg1) { q->first_msg = msg1->next; if (!q->first_msg) q->last_msg = NULL; q->nb_messages--; *msg = *msg1; msg1->obj = NULL; #ifdef FFP_MERGE av_free(msg1); #else msg1->next = q->recycle_msg; q->recycle_msg = msg1; #endif ret = 1; break; } else if (!block) { ret = 0; break; } else { SDL_CondWait(q->cond, q->mutex); } } SDL_UnlockMutex(q->mutex); return ret; } inline static void msg_queue_remove(MessageQueue *q, int what) { AVMessage **p_msg, *msg, *last_msg; SDL_LockMutex(q->mutex); last_msg = q->first_msg; if (!q->abort_request && q->first_msg) { p_msg = &q->first_msg; while (*p_msg) { msg = *p_msg; if (msg->what == what) { *p_msg = msg->next; #ifdef FFP_MERGE av_free(msg); #else msg_free_res(msg); msg->next = q->recycle_msg; q->recycle_msg = msg; #endif q->nb_messages--; } else { last_msg = msg; p_msg = &msg->next; } } if (q->first_msg) { q->last_msg = last_msg; } else { q->last_msg = NULL; } } SDL_UnlockMutex(q->mutex); } #endif ================================================ FILE: ijkmedia/ijkplayer/ff_ffpipeline.c ================================================ /* * ff_ffpipeline.c * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ff_ffpipeline.h" #include #include IJKFF_Pipeline *ffpipeline_alloc(SDL_Class *opaque_class, size_t opaque_size) { IJKFF_Pipeline *pipeline = (IJKFF_Pipeline*) calloc(1, sizeof(IJKFF_Pipeline)); if (!pipeline) return NULL; pipeline->opaque_class = opaque_class; pipeline->opaque = calloc(1, opaque_size); if (!pipeline->opaque) { free(pipeline); return NULL; } return pipeline; } void ffpipeline_free(IJKFF_Pipeline *pipeline) { if (!pipeline) return; if (pipeline->func_destroy) { pipeline->func_destroy(pipeline); } free(pipeline->opaque); memset(pipeline, 0, sizeof(IJKFF_Pipeline)); free(pipeline); } void ffpipeline_free_p(IJKFF_Pipeline **pipeline) { if (!pipeline) return; ffpipeline_free(*pipeline); } IJKFF_Pipenode* ffpipeline_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp) { return pipeline->func_open_video_decoder(pipeline, ffp); } IJKFF_Pipenode* ffpipeline_init_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp) { return pipeline->func_init_video_decoder(pipeline, ffp); } int ffpipeline_config_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp) { return pipeline->func_config_video_decoder(pipeline, ffp); } SDL_Aout *ffpipeline_open_audio_output(IJKFF_Pipeline *pipeline, FFPlayer *ffp) { return pipeline->func_open_audio_output(pipeline, ffp); } ================================================ FILE: ijkmedia/ijkplayer/ff_ffpipeline.h ================================================ /* * ff_ffpipeline.h * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__FF_FFPIPELINE_H #define FFPLAY__FF_FFPIPELINE_H #include "ijksdl/ijksdl_class.h" #include "ijksdl/ijksdl_mutex.h" #include "ijksdl/ijksdl_aout.h" #include "ff_ffpipenode.h" #include "ff_ffplay_def.h" typedef struct IJKFF_Pipeline_Opaque IJKFF_Pipeline_Opaque; typedef struct IJKFF_Pipeline IJKFF_Pipeline; struct IJKFF_Pipeline { SDL_Class *opaque_class; IJKFF_Pipeline_Opaque *opaque; void (*func_destroy) (IJKFF_Pipeline *pipeline); IJKFF_Pipenode *(*func_open_video_decoder) (IJKFF_Pipeline *pipeline, FFPlayer *ffp); SDL_Aout *(*func_open_audio_output) (IJKFF_Pipeline *pipeline, FFPlayer *ffp); IJKFF_Pipenode *(*func_init_video_decoder) (IJKFF_Pipeline *pipeline, FFPlayer *ffp); int (*func_config_video_decoder) (IJKFF_Pipeline *pipeline, FFPlayer *ffp); }; IJKFF_Pipeline *ffpipeline_alloc(SDL_Class *opaque_class, size_t opaque_size); void ffpipeline_free(IJKFF_Pipeline *pipeline); void ffpipeline_free_p(IJKFF_Pipeline **pipeline); IJKFF_Pipenode *ffpipeline_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp); SDL_Aout *ffpipeline_open_audio_output(IJKFF_Pipeline *pipeline, FFPlayer *ffp); IJKFF_Pipenode* ffpipeline_init_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp); int ffpipeline_config_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp); #endif ================================================ FILE: ijkmedia/ijkplayer/ff_ffpipenode.c ================================================ /* * ff_ffpipeline_vdec.c * * Copyright (c) 2003 Bilibili * Copyright (c) 2003 Fabrice Bellard * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ff_ffpipenode.h" #include #include IJKFF_Pipenode *ffpipenode_alloc(size_t opaque_size) { IJKFF_Pipenode *node = (IJKFF_Pipenode*) calloc(1, sizeof(IJKFF_Pipenode)); if (!node) return NULL; node->opaque = calloc(1, opaque_size); if (!node->opaque) { free(node); return NULL; } node->mutex = SDL_CreateMutex(); if (node->mutex == NULL) { free(node->opaque); free(node); return NULL; } return node; } void ffpipenode_free(IJKFF_Pipenode *node) { if (!node) return; if (node->func_destroy) { node->func_destroy(node); } SDL_DestroyMutexP(&node->mutex); free(node->opaque); memset(node, 0, sizeof(IJKFF_Pipenode)); free(node); } void ffpipenode_free_p(IJKFF_Pipenode **node) { if (!node) return; ffpipenode_free(*node); *node = NULL; } int ffpipenode_run_sync(IJKFF_Pipenode *node) { return node->func_run_sync(node); } int ffpipenode_flush(IJKFF_Pipenode *node) { if (!node || !node->func_flush) return 0; return node->func_flush(node); } ================================================ FILE: ijkmedia/ijkplayer/ff_ffpipenode.h ================================================ /* * ff_ffpipenode.h * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__FF_FFPIPENODE_H #define FFPLAY__FF_FFPIPENODE_H #include "ijksdl/ijksdl_mutex.h" typedef struct IJKFF_Pipenode_Opaque IJKFF_Pipenode_Opaque; typedef struct IJKFF_Pipenode IJKFF_Pipenode; struct IJKFF_Pipenode { SDL_mutex *mutex; void *opaque; void (*func_destroy) (IJKFF_Pipenode *node); int (*func_run_sync)(IJKFF_Pipenode *node); int (*func_flush) (IJKFF_Pipenode *node); // optional }; IJKFF_Pipenode *ffpipenode_alloc(size_t opaque_size); void ffpipenode_free(IJKFF_Pipenode *node); void ffpipenode_free_p(IJKFF_Pipenode **node); int ffpipenode_run_sync(IJKFF_Pipenode *node); int ffpipenode_flush(IJKFF_Pipenode *node); #endif ================================================ FILE: ijkmedia/ijkplayer/ff_ffplay.c ================================================ /* * Copyright (c) 2003 Bilibili * Copyright (c) 2003 Fabrice Bellard * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ff_ffplay.h" /** * @file * simple media player based on the FFmpeg libraries */ #include "config.h" #include #include #include #include #include #include #include #include #include "libavutil/avstring.h" #include "libavutil/eval.h" #include "libavutil/mathematics.h" #include "libavutil/pixdesc.h" #include "libavutil/imgutils.h" #include "libavutil/dict.h" #include "libavutil/parseutils.h" #include "libavutil/samplefmt.h" #include "libavutil/avassert.h" #include "libavutil/time.h" #include "libavformat/avformat.h" #if CONFIG_AVDEVICE #include "libavdevice/avdevice.h" #endif #include "libswscale/swscale.h" #include "libavutil/opt.h" #include "libavcodec/avfft.h" #include "libswresample/swresample.h" #if CONFIG_AVFILTER # include "libavcodec/avcodec.h" # include "libavfilter/avfilter.h" # include "libavfilter/buffersink.h" # include "libavfilter/buffersrc.h" #endif #include "ijksdl/ijksdl_log.h" #include "ijkavformat/ijkavformat.h" #include "ff_cmdutils.h" #include "ff_fferror.h" #include "ff_ffpipeline.h" #include "ff_ffpipenode.h" #include "ff_ffplay_debug.h" #include "ijkmeta.h" #include "ijkversion.h" #include "ijkplayer.h" #include #if defined(__ANDROID__) #include "ijksoundtouch/ijksoundtouch_wrap.h" #endif #ifndef AV_CODEC_FLAG2_FAST #define AV_CODEC_FLAG2_FAST CODEC_FLAG2_FAST #endif #ifndef AV_CODEC_CAP_DR1 #define AV_CODEC_CAP_DR1 CODEC_CAP_DR1 #endif // FIXME: 9 work around NDKr8e or gcc4.7 bug // isnan() may not recognize some double NAN, so we test both double and float #if defined(__ANDROID__) #ifdef isnan #undef isnan #endif #define isnan(x) (isnan((double)(x)) || isnanf((float)(x))) #endif #if defined(__ANDROID__) #define printf(...) ALOGD(__VA_ARGS__) #endif #define FFP_IO_STAT_STEP (50 * 1024) #define FFP_BUF_MSG_PERIOD (3) // static const AVOption ffp_context_options[] = ... #include "ff_ffplay_options.h" static AVPacket flush_pkt; #if CONFIG_AVFILTER // FFP_MERGE: opt_add_vfilter #endif #define IJKVERSION_GET_MAJOR(x) ((x >> 16) & 0xFF) #define IJKVERSION_GET_MINOR(x) ((x >> 8) & 0xFF) #define IJKVERSION_GET_MICRO(x) ((x ) & 0xFF) #if CONFIG_AVFILTER static inline int cmp_audio_fmts(enum AVSampleFormat fmt1, int64_t channel_count1, enum AVSampleFormat fmt2, int64_t channel_count2) { /* If channel count == 1, planar and non-planar formats are the same */ if (channel_count1 == 1 && channel_count2 == 1) return av_get_packed_sample_fmt(fmt1) != av_get_packed_sample_fmt(fmt2); else return channel_count1 != channel_count2 || fmt1 != fmt2; } static inline int64_t get_valid_channel_layout(int64_t channel_layout, int channels) { if (channel_layout && av_get_channel_layout_nb_channels(channel_layout) == channels) return channel_layout; else return 0; } #endif static void free_picture(Frame *vp); static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt) { MyAVPacketList *pkt1; if (q->abort_request) return -1; #ifdef FFP_MERGE pkt1 = av_malloc(sizeof(MyAVPacketList)); #else pkt1 = q->recycle_pkt; if (pkt1) { q->recycle_pkt = pkt1->next; q->recycle_count++; } else { q->alloc_count++; pkt1 = av_malloc(sizeof(MyAVPacketList)); } #ifdef FFP_SHOW_PKT_RECYCLE int total_count = q->recycle_count + q->alloc_count; if (!(total_count % 50)) { av_log(ffp, AV_LOG_DEBUG, "pkt-recycle \t%d + \t%d = \t%d\n", q->recycle_count, q->alloc_count, total_count); } #endif #endif if (!pkt1) return -1; pkt1->pkt = *pkt; pkt1->next = NULL; if (pkt == &flush_pkt) q->serial++; pkt1->serial = q->serial; if (!q->last_pkt) q->first_pkt = pkt1; else q->last_pkt->next = pkt1; q->last_pkt = pkt1; q->nb_packets++; q->size += pkt1->pkt.size + sizeof(*pkt1); q->duration += FFMAX(pkt1->pkt.duration, MIN_PKT_DURATION); /* XXX: should duplicate packet data in DV case */ SDL_CondSignal(q->cond); return 0; } static int packet_queue_put(PacketQueue *q, AVPacket *pkt) { int ret; SDL_LockMutex(q->mutex); ret = packet_queue_put_private(q, pkt); SDL_UnlockMutex(q->mutex); if (pkt != &flush_pkt && ret < 0) av_packet_unref(pkt); return ret; } static int packet_queue_put_nullpacket(PacketQueue *q, int stream_index) { AVPacket pkt1, *pkt = &pkt1; av_init_packet(pkt); pkt->data = NULL; pkt->size = 0; pkt->stream_index = stream_index; return packet_queue_put(q, pkt); } /* packet queue handling */ static int packet_queue_init(PacketQueue *q) { memset(q, 0, sizeof(PacketQueue)); q->mutex = SDL_CreateMutex(); if (!q->mutex) { av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError()); return AVERROR(ENOMEM); } q->cond = SDL_CreateCond(); if (!q->cond) { av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError()); return AVERROR(ENOMEM); } q->abort_request = 1; return 0; } static void packet_queue_flush(PacketQueue *q) { MyAVPacketList *pkt, *pkt1; SDL_LockMutex(q->mutex); for (pkt = q->first_pkt; pkt; pkt = pkt1) { pkt1 = pkt->next; av_packet_unref(&pkt->pkt); #ifdef FFP_MERGE av_freep(&pkt); #else pkt->next = q->recycle_pkt; q->recycle_pkt = pkt; #endif } q->last_pkt = NULL; q->first_pkt = NULL; q->nb_packets = 0; q->size = 0; q->duration = 0; SDL_UnlockMutex(q->mutex); } static void packet_queue_destroy(PacketQueue *q) { packet_queue_flush(q); SDL_LockMutex(q->mutex); while(q->recycle_pkt) { MyAVPacketList *pkt = q->recycle_pkt; if (pkt) q->recycle_pkt = pkt->next; av_freep(&pkt); } SDL_UnlockMutex(q->mutex); SDL_DestroyMutex(q->mutex); SDL_DestroyCond(q->cond); } static void packet_queue_abort(PacketQueue *q) { SDL_LockMutex(q->mutex); q->abort_request = 1; SDL_CondSignal(q->cond); SDL_UnlockMutex(q->mutex); } static void packet_queue_start(PacketQueue *q) { SDL_LockMutex(q->mutex); q->abort_request = 0; packet_queue_put_private(q, &flush_pkt); SDL_UnlockMutex(q->mutex); } /* return < 0 if aborted, 0 if no packet and > 0 if packet. */ static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial) { MyAVPacketList *pkt1; int ret; SDL_LockMutex(q->mutex); for (;;) { if (q->abort_request) { ret = -1; break; } pkt1 = q->first_pkt; if (pkt1) { q->first_pkt = pkt1->next; if (!q->first_pkt) q->last_pkt = NULL; q->nb_packets--; q->size -= pkt1->pkt.size + sizeof(*pkt1); q->duration -= FFMAX(pkt1->pkt.duration, MIN_PKT_DURATION); *pkt = pkt1->pkt; if (serial) *serial = pkt1->serial; #ifdef FFP_MERGE av_free(pkt1); #else pkt1->next = q->recycle_pkt; q->recycle_pkt = pkt1; #endif ret = 1; break; } else if (!block) { ret = 0; break; } else { SDL_CondWait(q->cond, q->mutex); } } SDL_UnlockMutex(q->mutex); return ret; } static int packet_queue_get_or_buffering(FFPlayer *ffp, PacketQueue *q, AVPacket *pkt, int *serial, int *finished) { assert(finished); if (!ffp->packet_buffering) return packet_queue_get(q, pkt, 1, serial); while (1) { int new_packet = packet_queue_get(q, pkt, 0, serial); if (new_packet < 0) return -1; else if (new_packet == 0) { if (q->is_buffer_indicator && !*finished) ffp_toggle_buffering(ffp, 1); new_packet = packet_queue_get(q, pkt, 1, serial); if (new_packet < 0) return -1; } if (*finished == *serial) { av_packet_unref(pkt); continue; } else break; } return 1; } static void decoder_init(Decoder *d, AVCodecContext *avctx, PacketQueue *queue, SDL_cond *empty_queue_cond) { memset(d, 0, sizeof(Decoder)); d->avctx = avctx; d->queue = queue; d->empty_queue_cond = empty_queue_cond; d->start_pts = AV_NOPTS_VALUE; d->first_frame_decoded_time = SDL_GetTickHR(); d->first_frame_decoded = 0; SDL_ProfilerReset(&d->decode_profiler, -1); } static int convert_image(FFPlayer *ffp, AVFrame *src_frame, int64_t src_frame_pts, int width, int height) { GetImgInfo *img_info = ffp->get_img_info; VideoState *is = ffp->is; AVFrame *dst_frame = NULL; AVPacket avpkt; int got_packet = 0; int dst_width = 0; int dst_height = 0; int bytes = 0; void *buffer = NULL; char file_path[1024] = {0}; char file_name[16] = {0}; int fd = -1; int ret = 0; int tmp = 0; float origin_dar = 0; float dar = 0; AVRational display_aspect_ratio; int file_name_length = 0; if (!height || !width || !img_info->width || !img_info->height) { ret = -1; return ret; } dar = (float) img_info->width / img_info->height; if (is->viddec.avctx) { av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den, is->viddec.avctx->width * (int64_t)is->viddec.avctx->sample_aspect_ratio.num, is->viddec.avctx->height * (int64_t)is->viddec.avctx->sample_aspect_ratio.den, 1024 * 1024); if (!display_aspect_ratio.num || !display_aspect_ratio.den) { origin_dar = (float) width / height; } else { origin_dar = (float) display_aspect_ratio.num / display_aspect_ratio.den; } } else { ret = -1; return ret; } if ((int)(origin_dar * 100) != (int)(dar * 100)) { tmp = img_info->width / origin_dar; if (tmp > img_info->height) { img_info->width = img_info->height * origin_dar; } else { img_info->height = tmp; } av_log(NULL, AV_LOG_INFO, "%s img_info->width = %d, img_info->height = %d\n", __func__, img_info->width, img_info->height); } dst_width = img_info->width; dst_height = img_info->height; av_init_packet(&avpkt); avpkt.size = 0; avpkt.data = NULL; if (!img_info->frame_img_convert_ctx) { img_info->frame_img_convert_ctx = sws_getContext(width, height, src_frame->format, dst_width, dst_height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL); if (!img_info->frame_img_convert_ctx) { ret = -1; av_log(NULL, AV_LOG_ERROR, "%s sws_getContext failed\n", __func__); goto fail0; } } if (!img_info->frame_img_codec_ctx) { AVCodec *image_codec = avcodec_find_encoder(AV_CODEC_ID_PNG); if (!image_codec) { ret = -1; av_log(NULL, AV_LOG_ERROR, "%s avcodec_find_encoder failed\n", __func__); goto fail0; } img_info->frame_img_codec_ctx = avcodec_alloc_context3(image_codec); if (!img_info->frame_img_codec_ctx) { ret = -1; av_log(NULL, AV_LOG_ERROR, "%s avcodec_alloc_context3 failed\n", __func__); goto fail0; } img_info->frame_img_codec_ctx->bit_rate = ffp->stat.bit_rate; img_info->frame_img_codec_ctx->width = dst_width; img_info->frame_img_codec_ctx->height = dst_height; img_info->frame_img_codec_ctx->pix_fmt = AV_PIX_FMT_RGB24; img_info->frame_img_codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO; img_info->frame_img_codec_ctx->time_base.num = ffp->is->video_st->time_base.num; img_info->frame_img_codec_ctx->time_base.den = ffp->is->video_st->time_base.den; avcodec_open2(img_info->frame_img_codec_ctx, image_codec, NULL); } dst_frame = av_frame_alloc(); if (!dst_frame) { ret = -1; av_log(NULL, AV_LOG_ERROR, "%s av_frame_alloc failed\n", __func__); goto fail0; } bytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, dst_width, dst_height, 1); buffer = (uint8_t *) av_malloc(bytes * sizeof(uint8_t)); if (!buffer) { ret = -1; av_log(NULL, AV_LOG_ERROR, "%s av_image_get_buffer_size failed\n", __func__); goto fail1; } dst_frame->format = AV_PIX_FMT_RGB24; dst_frame->width = dst_width; dst_frame->height = dst_height; ret = av_image_fill_arrays(dst_frame->data, dst_frame->linesize, buffer, AV_PIX_FMT_RGB24, dst_width, dst_height, 1); if (ret < 0) { ret = -1; av_log(NULL, AV_LOG_ERROR, "%s av_image_fill_arrays failed\n", __func__); goto fail2; } ret = sws_scale(img_info->frame_img_convert_ctx, (const uint8_t * const *) src_frame->data, src_frame->linesize, 0, src_frame->height, dst_frame->data, dst_frame->linesize); if (ret <= 0) { ret = -1; av_log(NULL, AV_LOG_ERROR, "%s sws_scale failed\n", __func__); goto fail2; } ret = avcodec_encode_video2(img_info->frame_img_codec_ctx, &avpkt, dst_frame, &got_packet); if (ret >= 0 && got_packet > 0) { strcpy(file_path, img_info->img_path); strcat(file_path, "/"); sprintf(file_name, "%lld", src_frame_pts); strcat(file_name, ".png"); strcat(file_path, file_name); fd = open(file_path, O_RDWR | O_TRUNC | O_CREAT, 0600); if (fd < 0) { ret = -1; av_log(NULL, AV_LOG_ERROR, "%s open path = %s failed %s\n", __func__, file_path, strerror(errno)); goto fail2; } write(fd, avpkt.data, avpkt.size); close(fd); img_info->count--; file_name_length = (int)strlen(file_name) + 1; if (img_info->count <= 0) ffp_notify_msg4(ffp, FFP_MSG_GET_IMG_STATE, (int) src_frame_pts, 1, file_name, file_name_length); else ffp_notify_msg4(ffp, FFP_MSG_GET_IMG_STATE, (int) src_frame_pts, 0, file_name, file_name_length); ret = 0; } fail2: av_free(buffer); fail1: av_frame_free(&dst_frame); fail0: av_packet_unref(&avpkt); return ret; } static int decoder_decode_frame(FFPlayer *ffp, Decoder *d, AVFrame *frame, AVSubtitle *sub) { int ret = AVERROR(EAGAIN); for (;;) { AVPacket pkt; if (d->queue->serial == d->pkt_serial) { do { if (d->queue->abort_request) return -1; switch (d->avctx->codec_type) { case AVMEDIA_TYPE_VIDEO: ret = avcodec_receive_frame(d->avctx, frame); if (ret >= 0) { ffp->stat.vdps = SDL_SpeedSamplerAdd(&ffp->vdps_sampler, FFP_SHOW_VDPS_AVCODEC, "vdps[avcodec]"); if (ffp->decoder_reorder_pts == -1) { frame->pts = frame->best_effort_timestamp; } else if (!ffp->decoder_reorder_pts) { frame->pts = frame->pkt_dts; } } break; case AVMEDIA_TYPE_AUDIO: ret = avcodec_receive_frame(d->avctx, frame); if (ret >= 0) { AVRational tb = (AVRational){1, frame->sample_rate}; if (frame->pts != AV_NOPTS_VALUE) frame->pts = av_rescale_q(frame->pts, av_codec_get_pkt_timebase(d->avctx), tb); else if (d->next_pts != AV_NOPTS_VALUE) frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb); if (frame->pts != AV_NOPTS_VALUE) { d->next_pts = frame->pts + frame->nb_samples; d->next_pts_tb = tb; } } break; default: break; } if (ret == AVERROR_EOF) { d->finished = d->pkt_serial; avcodec_flush_buffers(d->avctx); return 0; } if (ret >= 0) return 1; } while (ret != AVERROR(EAGAIN)); } do { if (d->queue->nb_packets == 0) SDL_CondSignal(d->empty_queue_cond); if (d->packet_pending) { av_packet_move_ref(&pkt, &d->pkt); d->packet_pending = 0; } else { if (packet_queue_get_or_buffering(ffp, d->queue, &pkt, &d->pkt_serial, &d->finished) < 0) return -1; } } while (d->queue->serial != d->pkt_serial); if (pkt.data == flush_pkt.data) { avcodec_flush_buffers(d->avctx); d->finished = 0; d->next_pts = d->start_pts; d->next_pts_tb = d->start_pts_tb; } else { if (d->avctx->codec_type == AVMEDIA_TYPE_SUBTITLE) { int got_frame = 0; ret = avcodec_decode_subtitle2(d->avctx, sub, &got_frame, &pkt); if (ret < 0) { ret = AVERROR(EAGAIN); } else { if (got_frame && !pkt.data) { d->packet_pending = 1; av_packet_move_ref(&d->pkt, &pkt); } ret = got_frame ? 0 : (pkt.data ? AVERROR(EAGAIN) : AVERROR_EOF); } } else { if (avcodec_send_packet(d->avctx, &pkt) == AVERROR(EAGAIN)) { av_log(d->avctx, AV_LOG_ERROR, "Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n"); d->packet_pending = 1; av_packet_move_ref(&d->pkt, &pkt); } } av_packet_unref(&pkt); } } } static void decoder_destroy(Decoder *d) { av_packet_unref(&d->pkt); avcodec_free_context(&d->avctx); } static void frame_queue_unref_item(Frame *vp) { av_frame_unref(vp->frame); SDL_VoutUnrefYUVOverlay(vp->bmp); avsubtitle_free(&vp->sub); } static int frame_queue_init(FrameQueue *f, PacketQueue *pktq, int max_size, int keep_last) { int i; memset(f, 0, sizeof(FrameQueue)); if (!(f->mutex = SDL_CreateMutex())) { av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError()); return AVERROR(ENOMEM); } if (!(f->cond = SDL_CreateCond())) { av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError()); return AVERROR(ENOMEM); } f->pktq = pktq; f->max_size = FFMIN(max_size, FRAME_QUEUE_SIZE); f->keep_last = !!keep_last; for (i = 0; i < f->max_size; i++) if (!(f->queue[i].frame = av_frame_alloc())) return AVERROR(ENOMEM); return 0; } static void frame_queue_destory(FrameQueue *f) { int i; for (i = 0; i < f->max_size; i++) { Frame *vp = &f->queue[i]; frame_queue_unref_item(vp); av_frame_free(&vp->frame); free_picture(vp); } SDL_DestroyMutex(f->mutex); SDL_DestroyCond(f->cond); } static void frame_queue_signal(FrameQueue *f) { SDL_LockMutex(f->mutex); SDL_CondSignal(f->cond); SDL_UnlockMutex(f->mutex); } static Frame *frame_queue_peek(FrameQueue *f) { return &f->queue[(f->rindex + f->rindex_shown) % f->max_size]; } static Frame *frame_queue_peek_next(FrameQueue *f) { return &f->queue[(f->rindex + f->rindex_shown + 1) % f->max_size]; } static Frame *frame_queue_peek_last(FrameQueue *f) { return &f->queue[f->rindex]; } static Frame *frame_queue_peek_writable(FrameQueue *f) { /* wait until we have space to put a new frame */ SDL_LockMutex(f->mutex); while (f->size >= f->max_size && !f->pktq->abort_request) { SDL_CondWait(f->cond, f->mutex); } SDL_UnlockMutex(f->mutex); if (f->pktq->abort_request) return NULL; return &f->queue[f->windex]; } static Frame *frame_queue_peek_readable(FrameQueue *f) { /* wait until we have a readable a new frame */ SDL_LockMutex(f->mutex); while (f->size - f->rindex_shown <= 0 && !f->pktq->abort_request) { SDL_CondWait(f->cond, f->mutex); } SDL_UnlockMutex(f->mutex); if (f->pktq->abort_request) return NULL; return &f->queue[(f->rindex + f->rindex_shown) % f->max_size]; } static void frame_queue_push(FrameQueue *f) { if (++f->windex == f->max_size) f->windex = 0; SDL_LockMutex(f->mutex); f->size++; SDL_CondSignal(f->cond); SDL_UnlockMutex(f->mutex); } static void frame_queue_next(FrameQueue *f) { if (f->keep_last && !f->rindex_shown) { f->rindex_shown = 1; return; } frame_queue_unref_item(&f->queue[f->rindex]); if (++f->rindex == f->max_size) f->rindex = 0; SDL_LockMutex(f->mutex); f->size--; SDL_CondSignal(f->cond); SDL_UnlockMutex(f->mutex); } /* return the number of undisplayed frames in the queue */ static int frame_queue_nb_remaining(FrameQueue *f) { return f->size - f->rindex_shown; } /* return last shown position */ #ifdef FFP_MERGE static int64_t frame_queue_last_pos(FrameQueue *f) { Frame *fp = &f->queue[f->rindex]; if (f->rindex_shown && fp->serial == f->pktq->serial) return fp->pos; else return -1; } #endif static void decoder_abort(Decoder *d, FrameQueue *fq) { packet_queue_abort(d->queue); frame_queue_signal(fq); SDL_WaitThread(d->decoder_tid, NULL); d->decoder_tid = NULL; packet_queue_flush(d->queue); } // FFP_MERGE: fill_rectangle // FFP_MERGE: fill_border // FFP_MERGE: ALPHA_BLEND // FFP_MERGE: RGBA_IN // FFP_MERGE: YUVA_IN // FFP_MERGE: YUVA_OUT // FFP_MERGE: BPP // FFP_MERGE: blend_subrect static void free_picture(Frame *vp) { if (vp->bmp) { SDL_VoutFreeYUVOverlay(vp->bmp); vp->bmp = NULL; } } // FFP_MERGE: realloc_texture // FFP_MERGE: calculate_display_rect // FFP_MERGE: upload_texture // FFP_MERGE: video_image_display static size_t parse_ass_subtitle(const char *ass, char *output) { char *tok = NULL; tok = strchr(ass, ':'); if (tok) tok += 1; // skip event tok = strchr(tok, ','); if (tok) tok += 1; // skip layer tok = strchr(tok, ','); if (tok) tok += 1; // skip start_time tok = strchr(tok, ','); if (tok) tok += 1; // skip end_time tok = strchr(tok, ','); if (tok) tok += 1; // skip style tok = strchr(tok, ','); if (tok) tok += 1; // skip name tok = strchr(tok, ','); if (tok) tok += 1; // skip margin_l tok = strchr(tok, ','); if (tok) tok += 1; // skip margin_r tok = strchr(tok, ','); if (tok) tok += 1; // skip margin_v tok = strchr(tok, ','); if (tok) tok += 1; // skip effect if (tok) { char *text = tok; size_t idx = 0; do { char *found = strstr(text, "\\N"); if (found) { size_t n = found - text; memcpy(output+idx, text, n); output[idx + n] = '\n'; idx = n + 1; text = found + 2; } else { size_t left_text_len = strlen(text); memcpy(output+idx, text, left_text_len); if (output[idx + left_text_len - 1] == '\n') output[idx + left_text_len - 1] = '\0'; else output[idx + left_text_len] = '\0'; break; } } while(1); return strlen(output) + 1; } return 0; } static void video_image_display2(FFPlayer *ffp) { VideoState *is = ffp->is; Frame *vp; Frame *sp = NULL; vp = frame_queue_peek_last(&is->pictq); if (vp->bmp) { if (is->subtitle_st) { if (frame_queue_nb_remaining(&is->subpq) > 0) { sp = frame_queue_peek(&is->subpq); if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) { if (!sp->uploaded) { if (sp->sub.num_rects > 0) { char buffered_text[4096]; if (sp->sub.rects[0]->text) { strncpy(buffered_text, sp->sub.rects[0]->text, 4096); } else if (sp->sub.rects[0]->ass) { parse_ass_subtitle(sp->sub.rects[0]->ass, buffered_text); } ffp_notify_msg4(ffp, FFP_MSG_TIMED_TEXT, 0, 0, buffered_text, sizeof(buffered_text)); } sp->uploaded = 1; } } } } if (ffp->render_wait_start && !ffp->start_on_prepared && is->pause_req) { if (!ffp->first_video_frame_rendered) { ffp->first_video_frame_rendered = 1; ffp_notify_msg1(ffp, FFP_MSG_VIDEO_RENDERING_START); } while (is->pause_req && !is->abort_request) { SDL_Delay(20); } } SDL_VoutDisplayYUVOverlay(ffp->vout, vp->bmp); ffp->stat.vfps = SDL_SpeedSamplerAdd(&ffp->vfps_sampler, FFP_SHOW_VFPS_FFPLAY, "vfps[ffplay]"); if (!ffp->first_video_frame_rendered) { ffp->first_video_frame_rendered = 1; ffp_notify_msg1(ffp, FFP_MSG_VIDEO_RENDERING_START); } if (is->latest_video_seek_load_serial == vp->serial) { int latest_video_seek_load_serial = __atomic_exchange_n(&(is->latest_video_seek_load_serial), -1, memory_order_seq_cst); if (latest_video_seek_load_serial == vp->serial) { ffp->stat.latest_seek_load_duration = (av_gettime() - is->latest_seek_load_start_at) / 1000; if (ffp->av_sync_type == AV_SYNC_VIDEO_MASTER) { ffp_notify_msg2(ffp, FFP_MSG_VIDEO_SEEK_RENDERING_START, 1); } else { ffp_notify_msg2(ffp, FFP_MSG_VIDEO_SEEK_RENDERING_START, 0); } } } } } // FFP_MERGE: compute_mod // FFP_MERGE: video_audio_display static void stream_component_close(FFPlayer *ffp, int stream_index) { VideoState *is = ffp->is; AVFormatContext *ic = is->ic; AVCodecParameters *codecpar; if (stream_index < 0 || stream_index >= ic->nb_streams) return; codecpar = ic->streams[stream_index]->codecpar; switch (codecpar->codec_type) { case AVMEDIA_TYPE_AUDIO: decoder_abort(&is->auddec, &is->sampq); SDL_AoutCloseAudio(ffp->aout); decoder_destroy(&is->auddec); swr_free(&is->swr_ctx); av_freep(&is->audio_buf1); is->audio_buf1_size = 0; is->audio_buf = NULL; #ifdef FFP_MERGE if (is->rdft) { av_rdft_end(is->rdft); av_freep(&is->rdft_data); is->rdft = NULL; is->rdft_bits = 0; } #endif break; case AVMEDIA_TYPE_VIDEO: decoder_abort(&is->viddec, &is->pictq); decoder_destroy(&is->viddec); break; case AVMEDIA_TYPE_SUBTITLE: decoder_abort(&is->subdec, &is->subpq); decoder_destroy(&is->subdec); break; default: break; } ic->streams[stream_index]->discard = AVDISCARD_ALL; switch (codecpar->codec_type) { case AVMEDIA_TYPE_AUDIO: is->audio_st = NULL; is->audio_stream = -1; break; case AVMEDIA_TYPE_VIDEO: is->video_st = NULL; is->video_stream = -1; break; case AVMEDIA_TYPE_SUBTITLE: is->subtitle_st = NULL; is->subtitle_stream = -1; break; default: break; } } static void stream_close(FFPlayer *ffp) { VideoState *is = ffp->is; /* XXX: use a special url_shutdown call to abort parse cleanly */ is->abort_request = 1; packet_queue_abort(&is->videoq); packet_queue_abort(&is->audioq); av_log(NULL, AV_LOG_DEBUG, "wait for read_tid\n"); SDL_WaitThread(is->read_tid, NULL); /* close each stream */ if (is->audio_stream >= 0) stream_component_close(ffp, is->audio_stream); if (is->video_stream >= 0) stream_component_close(ffp, is->video_stream); if (is->subtitle_stream >= 0) stream_component_close(ffp, is->subtitle_stream); avformat_close_input(&is->ic); av_log(NULL, AV_LOG_DEBUG, "wait for video_refresh_tid\n"); SDL_WaitThread(is->video_refresh_tid, NULL); packet_queue_destroy(&is->videoq); packet_queue_destroy(&is->audioq); packet_queue_destroy(&is->subtitleq); /* free all pictures */ frame_queue_destory(&is->pictq); frame_queue_destory(&is->sampq); frame_queue_destory(&is->subpq); SDL_DestroyCond(is->audio_accurate_seek_cond); SDL_DestroyCond(is->video_accurate_seek_cond); SDL_DestroyCond(is->continue_read_thread); SDL_DestroyMutex(is->accurate_seek_mutex); SDL_DestroyMutex(is->play_mutex); #if !CONFIG_AVFILTER sws_freeContext(is->img_convert_ctx); #endif #ifdef FFP_MERGE sws_freeContext(is->sub_convert_ctx); #endif #if defined(__ANDROID__) if (ffp->soundtouch_enable && is->handle != NULL) { ijk_soundtouch_destroy(is->handle); } #endif if (ffp->get_img_info) { if (ffp->get_img_info->frame_img_convert_ctx) { sws_freeContext(ffp->get_img_info->frame_img_convert_ctx); } if (ffp->get_img_info->frame_img_codec_ctx) { avcodec_free_context(&ffp->get_img_info->frame_img_codec_ctx); } av_freep(&ffp->get_img_info->img_path); av_freep(&ffp->get_img_info); } av_free(is->filename); av_free(is); ffp->is = NULL; } // FFP_MERGE: do_exit // FFP_MERGE: sigterm_handler // FFP_MERGE: video_open // FFP_MERGE: video_display /* display the current picture, if any */ static void video_display2(FFPlayer *ffp) { VideoState *is = ffp->is; if (is->video_st) video_image_display2(ffp); } static double get_clock(Clock *c) { if (*c->queue_serial != c->serial) return NAN; if (c->paused) { return c->pts; } else { double time = av_gettime_relative() / 1000000.0; return c->pts_drift + time - (time - c->last_updated) * (1.0 - c->speed); } } static void set_clock_at(Clock *c, double pts, int serial, double time) { c->pts = pts; c->last_updated = time; c->pts_drift = c->pts - time; c->serial = serial; } static void set_clock(Clock *c, double pts, int serial) { double time = av_gettime_relative() / 1000000.0; set_clock_at(c, pts, serial, time); } static void set_clock_speed(Clock *c, double speed) { set_clock(c, get_clock(c), c->serial); c->speed = speed; } static void init_clock(Clock *c, int *queue_serial) { c->speed = 1.0; c->paused = 0; c->queue_serial = queue_serial; set_clock(c, NAN, -1); } static void sync_clock_to_slave(Clock *c, Clock *slave) { double clock = get_clock(c); double slave_clock = get_clock(slave); if (!isnan(slave_clock) && (isnan(clock) || fabs(clock - slave_clock) > AV_NOSYNC_THRESHOLD)) set_clock(c, slave_clock, slave->serial); } static int get_master_sync_type(VideoState *is) { if (is->av_sync_type == AV_SYNC_VIDEO_MASTER) { if (is->video_st) return AV_SYNC_VIDEO_MASTER; else return AV_SYNC_AUDIO_MASTER; } else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER) { if (is->audio_st) return AV_SYNC_AUDIO_MASTER; else return AV_SYNC_EXTERNAL_CLOCK; } else { return AV_SYNC_EXTERNAL_CLOCK; } } /* get the current master clock value */ static double get_master_clock(VideoState *is) { double val; switch (get_master_sync_type(is)) { case AV_SYNC_VIDEO_MASTER: val = get_clock(&is->vidclk); break; case AV_SYNC_AUDIO_MASTER: val = get_clock(&is->audclk); break; default: val = get_clock(&is->extclk); break; } return val; } static void check_external_clock_speed(VideoState *is) { if ((is->video_stream >= 0 && is->videoq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES) || (is->audio_stream >= 0 && is->audioq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES)) { set_clock_speed(&is->extclk, FFMAX(EXTERNAL_CLOCK_SPEED_MIN, is->extclk.speed - EXTERNAL_CLOCK_SPEED_STEP)); } else if ((is->video_stream < 0 || is->videoq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES) && (is->audio_stream < 0 || is->audioq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES)) { set_clock_speed(&is->extclk, FFMIN(EXTERNAL_CLOCK_SPEED_MAX, is->extclk.speed + EXTERNAL_CLOCK_SPEED_STEP)); } else { double speed = is->extclk.speed; if (speed != 1.0) set_clock_speed(&is->extclk, speed + EXTERNAL_CLOCK_SPEED_STEP * (1.0 - speed) / fabs(1.0 - speed)); } } /* seek in the stream */ static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_bytes) { if (!is->seek_req) { is->seek_pos = pos; is->seek_rel = rel; is->seek_flags &= ~AVSEEK_FLAG_BYTE; if (seek_by_bytes) is->seek_flags |= AVSEEK_FLAG_BYTE; is->seek_req = 1; SDL_CondSignal(is->continue_read_thread); } } /* pause or resume the video */ static void stream_toggle_pause_l(FFPlayer *ffp, int pause_on) { VideoState *is = ffp->is; if (is->paused && !pause_on) { is->frame_timer += av_gettime_relative() / 1000000.0 - is->vidclk.last_updated; #ifdef FFP_MERGE if (is->read_pause_return != AVERROR(ENOSYS)) { is->vidclk.paused = 0; } #endif set_clock(&is->vidclk, get_clock(&is->vidclk), is->vidclk.serial); set_clock(&is->audclk, get_clock(&is->audclk), is->audclk.serial); } else { } set_clock(&is->extclk, get_clock(&is->extclk), is->extclk.serial); if (is->step && (is->pause_req || is->buffering_on)) { is->paused = is->vidclk.paused = is->extclk.paused = pause_on; } else { is->paused = is->audclk.paused = is->vidclk.paused = is->extclk.paused = pause_on; SDL_AoutPauseAudio(ffp->aout, pause_on); } } static void stream_update_pause_l(FFPlayer *ffp) { VideoState *is = ffp->is; if (!is->step && (is->pause_req || is->buffering_on)) { stream_toggle_pause_l(ffp, 1); } else { stream_toggle_pause_l(ffp, 0); } } static void toggle_pause_l(FFPlayer *ffp, int pause_on) { VideoState *is = ffp->is; if (is->pause_req && !pause_on) { set_clock(&is->vidclk, get_clock(&is->vidclk), is->vidclk.serial); set_clock(&is->audclk, get_clock(&is->audclk), is->audclk.serial); } is->pause_req = pause_on; ffp->auto_resume = !pause_on; stream_update_pause_l(ffp); is->step = 0; } static void toggle_pause(FFPlayer *ffp, int pause_on) { SDL_LockMutex(ffp->is->play_mutex); toggle_pause_l(ffp, pause_on); SDL_UnlockMutex(ffp->is->play_mutex); } // FFP_MERGE: toggle_mute // FFP_MERGE: update_volume static void step_to_next_frame_l(FFPlayer *ffp) { VideoState *is = ffp->is; is->step = 1; /* if the stream is paused unpause it, then step */ if (is->paused) stream_toggle_pause_l(ffp, 0); } static double compute_target_delay(FFPlayer *ffp, double delay, VideoState *is) { double sync_threshold, diff = 0; /* update delay to follow master synchronisation source */ if (get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER) { /* if video is slave, we try to correct big delays by duplicating or deleting a frame */ diff = get_clock(&is->vidclk) - get_master_clock(is); /* skip or repeat frame. We take into account the delay to compute the threshold. I still don't know if it is the best guess */ sync_threshold = FFMAX(AV_SYNC_THRESHOLD_MIN, FFMIN(AV_SYNC_THRESHOLD_MAX, delay)); /* -- by bbcallen: replace is->max_frame_duration with AV_NOSYNC_THRESHOLD */ if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) { if (diff <= -sync_threshold) delay = FFMAX(0, delay + diff); else if (diff >= sync_threshold && delay > AV_SYNC_FRAMEDUP_THRESHOLD) delay = delay + diff; else if (diff >= sync_threshold) delay = 2 * delay; } } if (ffp) { ffp->stat.avdelay = delay; ffp->stat.avdiff = diff; } #ifdef FFP_SHOW_AUDIO_DELAY av_log(NULL, AV_LOG_TRACE, "video: delay=%0.3f A-V=%f\n", delay, -diff); #endif return delay; } static double vp_duration(VideoState *is, Frame *vp, Frame *nextvp) { if (vp->serial == nextvp->serial) { double duration = nextvp->pts - vp->pts; if (isnan(duration) || duration <= 0 || duration > is->max_frame_duration) return vp->duration; else return duration; } else { return 0.0; } } static void update_video_pts(VideoState *is, double pts, int64_t pos, int serial) { /* update current video pts */ set_clock(&is->vidclk, pts, serial); sync_clock_to_slave(&is->extclk, &is->vidclk); } /* called to display each frame */ static void video_refresh(FFPlayer *opaque, double *remaining_time) { FFPlayer *ffp = opaque; VideoState *is = ffp->is; double time; Frame *sp, *sp2; if (!is->paused && get_master_sync_type(is) == AV_SYNC_EXTERNAL_CLOCK && is->realtime) check_external_clock_speed(is); if (!ffp->display_disable && is->show_mode != SHOW_MODE_VIDEO && is->audio_st) { time = av_gettime_relative() / 1000000.0; if (is->force_refresh || is->last_vis_time + ffp->rdftspeed < time) { video_display2(ffp); is->last_vis_time = time; } *remaining_time = FFMIN(*remaining_time, is->last_vis_time + ffp->rdftspeed - time); } if (is->video_st) { retry: if (frame_queue_nb_remaining(&is->pictq) == 0) { // nothing to do, no picture to display in the queue } else { double last_duration, duration, delay; Frame *vp, *lastvp; /* dequeue the picture */ lastvp = frame_queue_peek_last(&is->pictq); vp = frame_queue_peek(&is->pictq); if (vp->serial != is->videoq.serial) { frame_queue_next(&is->pictq); goto retry; } if (lastvp->serial != vp->serial) is->frame_timer = av_gettime_relative() / 1000000.0; if (is->paused) goto display; /* compute nominal last_duration */ last_duration = vp_duration(is, lastvp, vp); delay = compute_target_delay(ffp, last_duration, is); time= av_gettime_relative()/1000000.0; if (isnan(is->frame_timer) || time < is->frame_timer) is->frame_timer = time; if (time < is->frame_timer + delay) { *remaining_time = FFMIN(is->frame_timer + delay - time, *remaining_time); goto display; } is->frame_timer += delay; if (delay > 0 && time - is->frame_timer > AV_SYNC_THRESHOLD_MAX) is->frame_timer = time; SDL_LockMutex(is->pictq.mutex); if (!isnan(vp->pts)) update_video_pts(is, vp->pts, vp->pos, vp->serial); SDL_UnlockMutex(is->pictq.mutex); if (frame_queue_nb_remaining(&is->pictq) > 1) { Frame *nextvp = frame_queue_peek_next(&is->pictq); duration = vp_duration(is, vp, nextvp); if(!is->step && (ffp->framedrop > 0 || (ffp->framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration) { frame_queue_next(&is->pictq); goto retry; } } if (is->subtitle_st) { while (frame_queue_nb_remaining(&is->subpq) > 0) { sp = frame_queue_peek(&is->subpq); if (frame_queue_nb_remaining(&is->subpq) > 1) sp2 = frame_queue_peek_next(&is->subpq); else sp2 = NULL; if (sp->serial != is->subtitleq.serial || (is->vidclk.pts > (sp->pts + ((float) sp->sub.end_display_time / 1000))) || (sp2 && is->vidclk.pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000)))) { if (sp->uploaded) { ffp_notify_msg4(ffp, FFP_MSG_TIMED_TEXT, 0, 0, "", 1); } frame_queue_next(&is->subpq); } else { break; } } } frame_queue_next(&is->pictq); is->force_refresh = 1; SDL_LockMutex(ffp->is->play_mutex); if (is->step) { is->step = 0; if (!is->paused) stream_update_pause_l(ffp); } SDL_UnlockMutex(ffp->is->play_mutex); } display: /* display picture */ if (!ffp->display_disable && is->force_refresh && is->show_mode == SHOW_MODE_VIDEO && is->pictq.rindex_shown) video_display2(ffp); } is->force_refresh = 0; if (ffp->show_status) { static int64_t last_time; int64_t cur_time; int aqsize, vqsize, sqsize __unused; double av_diff; cur_time = av_gettime_relative(); if (!last_time || (cur_time - last_time) >= 30000) { aqsize = 0; vqsize = 0; sqsize = 0; if (is->audio_st) aqsize = is->audioq.size; if (is->video_st) vqsize = is->videoq.size; #ifdef FFP_MERGE if (is->subtitle_st) sqsize = is->subtitleq.size; #else sqsize = 0; #endif av_diff = 0; if (is->audio_st && is->video_st) av_diff = get_clock(&is->audclk) - get_clock(&is->vidclk); else if (is->video_st) av_diff = get_master_clock(is) - get_clock(&is->vidclk); else if (is->audio_st) av_diff = get_master_clock(is) - get_clock(&is->audclk); av_log(NULL, AV_LOG_INFO, "%7.2f %s:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64" \r", get_master_clock(is), (is->audio_st && is->video_st) ? "A-V" : (is->video_st ? "M-V" : (is->audio_st ? "M-A" : " ")), av_diff, is->frame_drops_early + is->frame_drops_late, aqsize / 1024, vqsize / 1024, sqsize, is->video_st ? is->viddec.avctx->pts_correction_num_faulty_dts : 0, is->video_st ? is->viddec.avctx->pts_correction_num_faulty_pts : 0); fflush(stdout); last_time = cur_time; } } } /* allocate a picture (needs to do that in main thread to avoid potential locking problems */ static void alloc_picture(FFPlayer *ffp, int frame_format) { VideoState *is = ffp->is; Frame *vp; #ifdef FFP_MERGE int sdl_format; #endif vp = &is->pictq.queue[is->pictq.windex]; free_picture(vp); #ifdef FFP_MERGE video_open(is, vp); #endif SDL_VoutSetOverlayFormat(ffp->vout, ffp->overlay_format); vp->bmp = SDL_Vout_CreateOverlay(vp->width, vp->height, frame_format, ffp->vout); #ifdef FFP_MERGE if (vp->format == AV_PIX_FMT_YUV420P) sdl_format = SDL_PIXELFORMAT_YV12; else sdl_format = SDL_PIXELFORMAT_ARGB8888; if (realloc_texture(&vp->bmp, sdl_format, vp->width, vp->height, SDL_BLENDMODE_NONE, 0) < 0) { #else /* RV16, RV32 contains only one plane */ if (!vp->bmp || (!vp->bmp->is_private && vp->bmp->pitches[0] < vp->width)) { #endif /* SDL allocates a buffer smaller than requested if the video * overlay hardware is unable to support the requested size. */ av_log(NULL, AV_LOG_FATAL, "Error: the video system does not support an image\n" "size of %dx%d pixels. Try using -lowres or -vf \"scale=w:h\"\n" "to reduce the image size.\n", vp->width, vp->height ); free_picture(vp); } SDL_LockMutex(is->pictq.mutex); vp->allocated = 1; SDL_CondSignal(is->pictq.cond); SDL_UnlockMutex(is->pictq.mutex); } static int queue_picture(FFPlayer *ffp, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial) { VideoState *is = ffp->is; Frame *vp; int video_accurate_seek_fail = 0; int64_t video_seek_pos = 0; int64_t now = 0; int64_t deviation = 0; int64_t deviation2 = 0; int64_t deviation3 = 0; if (ffp->enable_accurate_seek && is->video_accurate_seek_req && !is->seek_req) { if (!isnan(pts)) { video_seek_pos = is->seek_pos; is->accurate_seek_vframe_pts = pts * 1000 * 1000; deviation = llabs((int64_t)(pts * 1000 * 1000) - is->seek_pos); if ((pts * 1000 * 1000 < is->seek_pos) || deviation > MAX_DEVIATION) { now = av_gettime_relative() / 1000; if (is->drop_vframe_count == 0) { SDL_LockMutex(is->accurate_seek_mutex); if (is->accurate_seek_start_time <= 0 && (is->audio_stream < 0 || is->audio_accurate_seek_req)) { is->accurate_seek_start_time = now; } SDL_UnlockMutex(is->accurate_seek_mutex); av_log(NULL, AV_LOG_INFO, "video accurate_seek start, is->seek_pos=%lld, pts=%lf, is->accurate_seek_time = %lld\n", is->seek_pos, pts, is->accurate_seek_start_time); } is->drop_vframe_count++; while (is->audio_accurate_seek_req && !is->abort_request) { int64_t apts = is->accurate_seek_aframe_pts ; deviation2 = apts - pts * 1000 * 1000; deviation3 = apts - is->seek_pos; if (deviation2 > -100 * 1000 && deviation3 < 0) { break; } else { av_usleep(20 * 1000); } now = av_gettime_relative() / 1000; if ((now - is->accurate_seek_start_time) > ffp->accurate_seek_timeout) { break; } } if ((now - is->accurate_seek_start_time) <= ffp->accurate_seek_timeout) { return 1; // drop some old frame when do accurate seek } else { av_log(NULL, AV_LOG_WARNING, "video accurate_seek is error, is->drop_vframe_count=%d, now = %lld, pts = %lf\n", is->drop_vframe_count, now, pts); video_accurate_seek_fail = 1; // if KEY_FRAME interval too big, disable accurate seek } } else { av_log(NULL, AV_LOG_INFO, "video accurate_seek is ok, is->drop_vframe_count =%d, is->seek_pos=%lld, pts=%lf\n", is->drop_vframe_count, is->seek_pos, pts); if (video_seek_pos == is->seek_pos) { is->drop_vframe_count = 0; SDL_LockMutex(is->accurate_seek_mutex); is->video_accurate_seek_req = 0; SDL_CondSignal(is->audio_accurate_seek_cond); if (video_seek_pos == is->seek_pos && is->audio_accurate_seek_req && !is->abort_request) { SDL_CondWaitTimeout(is->video_accurate_seek_cond, is->accurate_seek_mutex, ffp->accurate_seek_timeout); } else { ffp_notify_msg2(ffp, FFP_MSG_ACCURATE_SEEK_COMPLETE, (int)(pts * 1000)); } if (video_seek_pos != is->seek_pos && !is->abort_request) { is->video_accurate_seek_req = 1; SDL_UnlockMutex(is->accurate_seek_mutex); return 1; } SDL_UnlockMutex(is->accurate_seek_mutex); } } } else { video_accurate_seek_fail = 1; } if (video_accurate_seek_fail) { is->drop_vframe_count = 0; SDL_LockMutex(is->accurate_seek_mutex); is->video_accurate_seek_req = 0; SDL_CondSignal(is->audio_accurate_seek_cond); if (is->audio_accurate_seek_req && !is->abort_request) { SDL_CondWaitTimeout(is->video_accurate_seek_cond, is->accurate_seek_mutex, ffp->accurate_seek_timeout); } else { if (!isnan(pts)) { ffp_notify_msg2(ffp, FFP_MSG_ACCURATE_SEEK_COMPLETE, (int)(pts * 1000)); } else { ffp_notify_msg2(ffp, FFP_MSG_ACCURATE_SEEK_COMPLETE, 0); } } SDL_UnlockMutex(is->accurate_seek_mutex); } is->accurate_seek_start_time = 0; video_accurate_seek_fail = 0; is->accurate_seek_vframe_pts = 0; } #if defined(DEBUG_SYNC) printf("frame_type=%c pts=%0.3f\n", av_get_picture_type_char(src_frame->pict_type), pts); #endif if (!(vp = frame_queue_peek_writable(&is->pictq))) return -1; vp->sar = src_frame->sample_aspect_ratio; #ifdef FFP_MERGE vp->uploaded = 0; #endif /* alloc or resize hardware picture buffer */ if (!vp->bmp || !vp->allocated || vp->width != src_frame->width || vp->height != src_frame->height || vp->format != src_frame->format) { if (vp->width != src_frame->width || vp->height != src_frame->height) ffp_notify_msg3(ffp, FFP_MSG_VIDEO_SIZE_CHANGED, src_frame->width, src_frame->height); vp->allocated = 0; vp->width = src_frame->width; vp->height = src_frame->height; vp->format = src_frame->format; /* the allocation must be done in the main thread to avoid locking problems. */ alloc_picture(ffp, src_frame->format); if (is->videoq.abort_request) return -1; } /* if the frame is not skipped, then display it */ if (vp->bmp) { /* get a pointer on the bitmap */ SDL_VoutLockYUVOverlay(vp->bmp); #ifdef FFP_MERGE #if CONFIG_AVFILTER // FIXME use direct rendering av_image_copy(data, linesize, (const uint8_t **)src_frame->data, src_frame->linesize, src_frame->format, vp->width, vp->height); #else // sws_getCachedContext(...); #endif #endif // FIXME: set swscale options if (SDL_VoutFillFrameYUVOverlay(vp->bmp, src_frame) < 0) { av_log(NULL, AV_LOG_FATAL, "Cannot initialize the conversion context\n"); exit(1); } /* update the bitmap content */ SDL_VoutUnlockYUVOverlay(vp->bmp); vp->pts = pts; vp->duration = duration; vp->pos = pos; vp->serial = serial; vp->sar = src_frame->sample_aspect_ratio; vp->bmp->sar_num = vp->sar.num; vp->bmp->sar_den = vp->sar.den; #ifdef FFP_MERGE av_frame_move_ref(vp->frame, src_frame); #endif frame_queue_push(&is->pictq); if (!is->viddec.first_frame_decoded) { ALOGD("Video: first frame decoded\n"); ffp_notify_msg1(ffp, FFP_MSG_VIDEO_DECODED_START); is->viddec.first_frame_decoded_time = SDL_GetTickHR(); is->viddec.first_frame_decoded = 1; } } return 0; } static int get_video_frame(FFPlayer *ffp, AVFrame *frame) { VideoState *is = ffp->is; int got_picture; ffp_video_statistic_l(ffp); if ((got_picture = decoder_decode_frame(ffp, &is->viddec, frame, NULL)) < 0) return -1; if (got_picture) { double dpts = NAN; if (frame->pts != AV_NOPTS_VALUE) dpts = av_q2d(is->video_st->time_base) * frame->pts; frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, frame); if (ffp->framedrop>0 || (ffp->framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) { ffp->stat.decode_frame_count++; if (frame->pts != AV_NOPTS_VALUE) { double diff = dpts - get_master_clock(is); if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD && diff - is->frame_last_filter_delay < 0 && is->viddec.pkt_serial == is->vidclk.serial && is->videoq.nb_packets) { is->frame_drops_early++; is->continuous_frame_drops_early++; if (is->continuous_frame_drops_early > ffp->framedrop) { is->continuous_frame_drops_early = 0; } else { ffp->stat.drop_frame_count++; ffp->stat.drop_frame_rate = (float)(ffp->stat.drop_frame_count) / (float)(ffp->stat.decode_frame_count); av_frame_unref(frame); got_picture = 0; } } } } } return got_picture; } #if CONFIG_AVFILTER static int configure_filtergraph(AVFilterGraph *graph, const char *filtergraph, AVFilterContext *source_ctx, AVFilterContext *sink_ctx) { int ret, i; int nb_filters = graph->nb_filters; AVFilterInOut *outputs = NULL, *inputs = NULL; if (filtergraph) { outputs = avfilter_inout_alloc(); inputs = avfilter_inout_alloc(); if (!outputs || !inputs) { ret = AVERROR(ENOMEM); goto fail; } outputs->name = av_strdup("in"); outputs->filter_ctx = source_ctx; outputs->pad_idx = 0; outputs->next = NULL; inputs->name = av_strdup("out"); inputs->filter_ctx = sink_ctx; inputs->pad_idx = 0; inputs->next = NULL; if ((ret = avfilter_graph_parse_ptr(graph, filtergraph, &inputs, &outputs, NULL)) < 0) goto fail; } else { if ((ret = avfilter_link(source_ctx, 0, sink_ctx, 0)) < 0) goto fail; } /* Reorder the filters to ensure that inputs of the custom filters are merged first */ for (i = 0; i < graph->nb_filters - nb_filters; i++) FFSWAP(AVFilterContext*, graph->filters[i], graph->filters[i + nb_filters]); ret = avfilter_graph_config(graph, NULL); fail: avfilter_inout_free(&outputs); avfilter_inout_free(&inputs); return ret; } static int configure_video_filters(FFPlayer *ffp, AVFilterGraph *graph, VideoState *is, const char *vfilters, AVFrame *frame) { static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_BGRA, AV_PIX_FMT_NONE }; char sws_flags_str[512] = ""; char buffersrc_args[256]; int ret; AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter = NULL; AVCodecParameters *codecpar = is->video_st->codecpar; AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL); AVDictionaryEntry *e = NULL; while ((e = av_dict_get(ffp->sws_dict, "", e, AV_DICT_IGNORE_SUFFIX))) { if (!strcmp(e->key, "sws_flags")) { av_strlcatf(sws_flags_str, sizeof(sws_flags_str), "%s=%s:", "flags", e->value); } else av_strlcatf(sws_flags_str, sizeof(sws_flags_str), "%s=%s:", e->key, e->value); } if (strlen(sws_flags_str)) sws_flags_str[strlen(sws_flags_str)-1] = '\0'; graph->scale_sws_opts = av_strdup(sws_flags_str); snprintf(buffersrc_args, sizeof(buffersrc_args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", frame->width, frame->height, frame->format, is->video_st->time_base.num, is->video_st->time_base.den, codecpar->sample_aspect_ratio.num, FFMAX(codecpar->sample_aspect_ratio.den, 1)); if (fr.num && fr.den) av_strlcatf(buffersrc_args, sizeof(buffersrc_args), ":frame_rate=%d/%d", fr.num, fr.den); if ((ret = avfilter_graph_create_filter(&filt_src, avfilter_get_by_name("buffer"), "ffplay_buffer", buffersrc_args, NULL, graph)) < 0) goto fail; ret = avfilter_graph_create_filter(&filt_out, avfilter_get_by_name("buffersink"), "ffplay_buffersink", NULL, NULL, graph); if (ret < 0) goto fail; if ((ret = av_opt_set_int_list(filt_out, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0) goto fail; last_filter = filt_out; /* Note: this macro adds a filter before the lastly added filter, so the * processing order of the filters is in reverse */ #define INSERT_FILT(name, arg) do { \ AVFilterContext *filt_ctx; \ \ ret = avfilter_graph_create_filter(&filt_ctx, \ avfilter_get_by_name(name), \ "ffplay_" name, arg, NULL, graph); \ if (ret < 0) \ goto fail; \ \ ret = avfilter_link(filt_ctx, 0, last_filter, 0); \ if (ret < 0) \ goto fail; \ \ last_filter = filt_ctx; \ } while (0) if (ffp->autorotate) { double theta = get_rotation(is->video_st); if (fabs(theta - 90) < 1.0) { INSERT_FILT("transpose", "clock"); } else if (fabs(theta - 180) < 1.0) { INSERT_FILT("hflip", NULL); INSERT_FILT("vflip", NULL); } else if (fabs(theta - 270) < 1.0) { INSERT_FILT("transpose", "cclock"); } else if (fabs(theta) > 1.0) { char rotate_buf[64]; snprintf(rotate_buf, sizeof(rotate_buf), "%f*PI/180", theta); INSERT_FILT("rotate", rotate_buf); } } #ifdef FFP_AVFILTER_PLAYBACK_RATE if (fabsf(ffp->pf_playback_rate) > 0.00001 && fabsf(ffp->pf_playback_rate - 1.0f) > 0.00001) { char setpts_buf[256]; float rate = 1.0f / ffp->pf_playback_rate; rate = av_clipf_c(rate, 0.5f, 2.0f); av_log(ffp, AV_LOG_INFO, "vf_rate=%f(1/%f)\n", ffp->pf_playback_rate, rate); snprintf(setpts_buf, sizeof(setpts_buf), "%f*PTS", rate); INSERT_FILT("setpts", setpts_buf); } #endif if ((ret = configure_filtergraph(graph, vfilters, filt_src, last_filter)) < 0) goto fail; is->in_video_filter = filt_src; is->out_video_filter = filt_out; fail: return ret; } static int configure_audio_filters(FFPlayer *ffp, const char *afilters, int force_output_format) { VideoState *is = ffp->is; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }; int sample_rates[2] = { 0, -1 }; int64_t channel_layouts[2] = { 0, -1 }; int channels[2] = { 0, -1 }; AVFilterContext *filt_asrc = NULL, *filt_asink = NULL; char aresample_swr_opts[512] = ""; AVDictionaryEntry *e = NULL; char asrc_args[256]; int ret; char afilters_args[4096]; avfilter_graph_free(&is->agraph); if (!(is->agraph = avfilter_graph_alloc())) return AVERROR(ENOMEM); while ((e = av_dict_get(ffp->swr_opts, "", e, AV_DICT_IGNORE_SUFFIX))) av_strlcatf(aresample_swr_opts, sizeof(aresample_swr_opts), "%s=%s:", e->key, e->value); if (strlen(aresample_swr_opts)) aresample_swr_opts[strlen(aresample_swr_opts)-1] = '\0'; av_opt_set(is->agraph, "aresample_swr_opts", aresample_swr_opts, 0); ret = snprintf(asrc_args, sizeof(asrc_args), "sample_rate=%d:sample_fmt=%s:channels=%d:time_base=%d/%d", is->audio_filter_src.freq, av_get_sample_fmt_name(is->audio_filter_src.fmt), is->audio_filter_src.channels, 1, is->audio_filter_src.freq); if (is->audio_filter_src.channel_layout) snprintf(asrc_args + ret, sizeof(asrc_args) - ret, ":channel_layout=0x%"PRIx64, is->audio_filter_src.channel_layout); ret = avfilter_graph_create_filter(&filt_asrc, avfilter_get_by_name("abuffer"), "ffplay_abuffer", asrc_args, NULL, is->agraph); if (ret < 0) goto end; ret = avfilter_graph_create_filter(&filt_asink, avfilter_get_by_name("abuffersink"), "ffplay_abuffersink", NULL, NULL, is->agraph); if (ret < 0) goto end; if ((ret = av_opt_set_int_list(filt_asink, "sample_fmts", sample_fmts, AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0) goto end; if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN)) < 0) goto end; if (force_output_format) { channel_layouts[0] = is->audio_tgt.channel_layout; channels [0] = is->audio_tgt.channels; sample_rates [0] = is->audio_tgt.freq; if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 0, AV_OPT_SEARCH_CHILDREN)) < 0) goto end; if ((ret = av_opt_set_int_list(filt_asink, "channel_layouts", channel_layouts, -1, AV_OPT_SEARCH_CHILDREN)) < 0) goto end; if ((ret = av_opt_set_int_list(filt_asink, "channel_counts" , channels , -1, AV_OPT_SEARCH_CHILDREN)) < 0) goto end; if ((ret = av_opt_set_int_list(filt_asink, "sample_rates" , sample_rates , -1, AV_OPT_SEARCH_CHILDREN)) < 0) goto end; } afilters_args[0] = 0; if (afilters) snprintf(afilters_args, sizeof(afilters_args), "%s", afilters); #ifdef FFP_AVFILTER_PLAYBACK_RATE if (fabsf(ffp->pf_playback_rate) > 0.00001 && fabsf(ffp->pf_playback_rate - 1.0f) > 0.00001) { if (afilters_args[0]) av_strlcatf(afilters_args, sizeof(afilters_args), ","); av_log(ffp, AV_LOG_INFO, "af_rate=%f\n", ffp->pf_playback_rate); av_strlcatf(afilters_args, sizeof(afilters_args), "atempo=%f", ffp->pf_playback_rate); } #endif if ((ret = configure_filtergraph(is->agraph, afilters_args[0] ? afilters_args : NULL, filt_asrc, filt_asink)) < 0) goto end; is->in_audio_filter = filt_asrc; is->out_audio_filter = filt_asink; end: if (ret < 0) avfilter_graph_free(&is->agraph); return ret; } #endif /* CONFIG_AVFILTER */ static int audio_thread(void *arg) { FFPlayer *ffp = arg; VideoState *is = ffp->is; AVFrame *frame = av_frame_alloc(); Frame *af; #if CONFIG_AVFILTER int last_serial = -1; int64_t dec_channel_layout; int reconfigure; #endif int got_frame = 0; AVRational tb; int ret = 0; int audio_accurate_seek_fail = 0; int64_t audio_seek_pos = 0; double frame_pts = 0; double audio_clock = 0; int64_t now = 0; double samples_duration = 0; int64_t deviation = 0; int64_t deviation2 = 0; int64_t deviation3 = 0; if (!frame) return AVERROR(ENOMEM); do { ffp_audio_statistic_l(ffp); if ((got_frame = decoder_decode_frame(ffp, &is->auddec, frame, NULL)) < 0) goto the_end; if (got_frame) { tb = (AVRational){1, frame->sample_rate}; if (ffp->enable_accurate_seek && is->audio_accurate_seek_req && !is->seek_req) { frame_pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb); now = av_gettime_relative() / 1000; if (!isnan(frame_pts)) { samples_duration = (double) frame->nb_samples / frame->sample_rate; audio_clock = frame_pts + samples_duration; is->accurate_seek_aframe_pts = audio_clock * 1000 * 1000; audio_seek_pos = is->seek_pos; deviation = llabs((int64_t)(audio_clock * 1000 * 1000) - is->seek_pos); if ((audio_clock * 1000 * 1000 < is->seek_pos ) || deviation > MAX_DEVIATION) { if (is->drop_aframe_count == 0) { SDL_LockMutex(is->accurate_seek_mutex); if (is->accurate_seek_start_time <= 0 && (is->video_stream < 0 || is->video_accurate_seek_req)) { is->accurate_seek_start_time = now; } SDL_UnlockMutex(is->accurate_seek_mutex); av_log(NULL, AV_LOG_INFO, "audio accurate_seek start, is->seek_pos=%lld, audio_clock=%lf, is->accurate_seek_start_time = %lld\n", is->seek_pos, audio_clock, is->accurate_seek_start_time); } is->drop_aframe_count++; while (is->video_accurate_seek_req && !is->abort_request) { int64_t vpts = is->accurate_seek_vframe_pts; deviation2 = vpts - audio_clock * 1000 * 1000; deviation3 = vpts - is->seek_pos; if (deviation2 > -100 * 1000 && deviation3 < 0) { break; } else { av_usleep(20 * 1000); } now = av_gettime_relative() / 1000; if ((now - is->accurate_seek_start_time) > ffp->accurate_seek_timeout) { break; } } if(!is->video_accurate_seek_req && is->video_stream >= 0 && audio_clock * 1000 * 1000 > is->accurate_seek_vframe_pts) { audio_accurate_seek_fail = 1; } else { now = av_gettime_relative() / 1000; if ((now - is->accurate_seek_start_time) <= ffp->accurate_seek_timeout) { av_frame_unref(frame); continue; // drop some old frame when do accurate seek } else { audio_accurate_seek_fail = 1; } } } else { if (audio_seek_pos == is->seek_pos) { av_log(NULL, AV_LOG_INFO, "audio accurate_seek is ok, is->drop_aframe_count=%d, audio_clock = %lf\n", is->drop_aframe_count, audio_clock); is->drop_aframe_count = 0; SDL_LockMutex(is->accurate_seek_mutex); is->audio_accurate_seek_req = 0; SDL_CondSignal(is->video_accurate_seek_cond); if (audio_seek_pos == is->seek_pos && is->video_accurate_seek_req && !is->abort_request) { SDL_CondWaitTimeout(is->audio_accurate_seek_cond, is->accurate_seek_mutex, ffp->accurate_seek_timeout); } else { ffp_notify_msg2(ffp, FFP_MSG_ACCURATE_SEEK_COMPLETE, (int)(audio_clock * 1000)); } if (audio_seek_pos != is->seek_pos && !is->abort_request) { is->audio_accurate_seek_req = 1; SDL_UnlockMutex(is->accurate_seek_mutex); av_frame_unref(frame); continue; } SDL_UnlockMutex(is->accurate_seek_mutex); } } } else { audio_accurate_seek_fail = 1; } if (audio_accurate_seek_fail) { av_log(NULL, AV_LOG_INFO, "audio accurate_seek is error, is->drop_aframe_count=%d, now = %lld, audio_clock = %lf\n", is->drop_aframe_count, now, audio_clock); is->drop_aframe_count = 0; SDL_LockMutex(is->accurate_seek_mutex); is->audio_accurate_seek_req = 0; SDL_CondSignal(is->video_accurate_seek_cond); if (is->video_accurate_seek_req && !is->abort_request) { SDL_CondWaitTimeout(is->audio_accurate_seek_cond, is->accurate_seek_mutex, ffp->accurate_seek_timeout); } else { ffp_notify_msg2(ffp, FFP_MSG_ACCURATE_SEEK_COMPLETE, (int)(audio_clock * 1000)); } SDL_UnlockMutex(is->accurate_seek_mutex); } is->accurate_seek_start_time = 0; audio_accurate_seek_fail = 0; } #if CONFIG_AVFILTER dec_channel_layout = get_valid_channel_layout(frame->channel_layout, frame->channels); reconfigure = cmp_audio_fmts(is->audio_filter_src.fmt, is->audio_filter_src.channels, frame->format, frame->channels) || is->audio_filter_src.channel_layout != dec_channel_layout || is->audio_filter_src.freq != frame->sample_rate || is->auddec.pkt_serial != last_serial || ffp->af_changed; if (reconfigure) { SDL_LockMutex(ffp->af_mutex); ffp->af_changed = 0; char buf1[1024], buf2[1024]; av_get_channel_layout_string(buf1, sizeof(buf1), -1, is->audio_filter_src.channel_layout); av_get_channel_layout_string(buf2, sizeof(buf2), -1, dec_channel_layout); av_log(NULL, AV_LOG_DEBUG, "Audio frame changed from rate:%d ch:%d fmt:%s layout:%s serial:%d to rate:%d ch:%d fmt:%s layout:%s serial:%d\n", is->audio_filter_src.freq, is->audio_filter_src.channels, av_get_sample_fmt_name(is->audio_filter_src.fmt), buf1, last_serial, frame->sample_rate, frame->channels, av_get_sample_fmt_name(frame->format), buf2, is->auddec.pkt_serial); is->audio_filter_src.fmt = frame->format; is->audio_filter_src.channels = frame->channels; is->audio_filter_src.channel_layout = dec_channel_layout; is->audio_filter_src.freq = frame->sample_rate; last_serial = is->auddec.pkt_serial; if ((ret = configure_audio_filters(ffp, ffp->afilters, 1)) < 0) { SDL_UnlockMutex(ffp->af_mutex); goto the_end; } SDL_UnlockMutex(ffp->af_mutex); } if ((ret = av_buffersrc_add_frame(is->in_audio_filter, frame)) < 0) goto the_end; while ((ret = av_buffersink_get_frame_flags(is->out_audio_filter, frame, 0)) >= 0) { tb = av_buffersink_get_time_base(is->out_audio_filter); #endif if (!(af = frame_queue_peek_writable(&is->sampq))) goto the_end; af->pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb); af->pos = frame->pkt_pos; af->serial = is->auddec.pkt_serial; af->duration = av_q2d((AVRational){frame->nb_samples, frame->sample_rate}); av_frame_move_ref(af->frame, frame); frame_queue_push(&is->sampq); #if CONFIG_AVFILTER if (is->audioq.serial != is->auddec.pkt_serial) break; } if (ret == AVERROR_EOF) is->auddec.finished = is->auddec.pkt_serial; #endif } } while (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF); the_end: #if CONFIG_AVFILTER avfilter_graph_free(&is->agraph); #endif av_frame_free(&frame); return ret; } static int decoder_start(Decoder *d, int (*fn)(void *), void *arg, const char *name) { packet_queue_start(d->queue); d->decoder_tid = SDL_CreateThreadEx(&d->_decoder_tid, fn, arg, name); if (!d->decoder_tid) { av_log(NULL, AV_LOG_ERROR, "SDL_CreateThread(): %s\n", SDL_GetError()); return AVERROR(ENOMEM); } return 0; } static int ffplay_video_thread(void *arg) { FFPlayer *ffp = arg; VideoState *is = ffp->is; AVFrame *frame = av_frame_alloc(); double pts; double duration; int ret; AVRational tb = is->video_st->time_base; AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL); int64_t dst_pts = -1; int64_t last_dst_pts = -1; int retry_convert_image = 0; int convert_frame_count = 0; #if CONFIG_AVFILTER AVFilterGraph *graph = avfilter_graph_alloc(); AVFilterContext *filt_out = NULL, *filt_in = NULL; int last_w = 0; int last_h = 0; enum AVPixelFormat last_format = -2; int last_serial = -1; int last_vfilter_idx = 0; if (!graph) { av_frame_free(&frame); return AVERROR(ENOMEM); } #else ffp_notify_msg2(ffp, FFP_MSG_VIDEO_ROTATION_CHANGED, ffp_get_video_rotate_degrees(ffp)); #endif if (!frame) { #if CONFIG_AVFILTER avfilter_graph_free(&graph); #endif return AVERROR(ENOMEM); } for (;;) { ret = get_video_frame(ffp, frame); if (ret < 0) goto the_end; if (!ret) continue; if (ffp->get_frame_mode) { if (!ffp->get_img_info || ffp->get_img_info->count <= 0) { av_frame_unref(frame); continue; } last_dst_pts = dst_pts; if (dst_pts < 0) { dst_pts = ffp->get_img_info->start_time; } else { dst_pts += (ffp->get_img_info->end_time - ffp->get_img_info->start_time) / (ffp->get_img_info->num - 1); } pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb); pts = pts * 1000; if (pts >= dst_pts) { while (retry_convert_image <= MAX_RETRY_CONVERT_IMAGE) { ret = convert_image(ffp, frame, (int64_t)pts, frame->width, frame->height); if (!ret) { convert_frame_count++; break; } retry_convert_image++; av_log(NULL, AV_LOG_ERROR, "convert image error retry_convert_image = %d\n", retry_convert_image); } retry_convert_image = 0; if (ret || ffp->get_img_info->count <= 0) { if (ret) { av_log(NULL, AV_LOG_ERROR, "convert image abort ret = %d\n", ret); ffp_notify_msg3(ffp, FFP_MSG_GET_IMG_STATE, 0, ret); } else { av_log(NULL, AV_LOG_INFO, "convert image complete convert_frame_count = %d\n", convert_frame_count); } goto the_end; } } else { dst_pts = last_dst_pts; } av_frame_unref(frame); continue; } #if CONFIG_AVFILTER if ( last_w != frame->width || last_h != frame->height || last_format != frame->format || last_serial != is->viddec.pkt_serial || ffp->vf_changed || last_vfilter_idx != is->vfilter_idx) { SDL_LockMutex(ffp->vf_mutex); ffp->vf_changed = 0; av_log(NULL, AV_LOG_DEBUG, "Video frame changed from size:%dx%d format:%s serial:%d to size:%dx%d format:%s serial:%d\n", last_w, last_h, (const char *)av_x_if_null(av_get_pix_fmt_name(last_format), "none"), last_serial, frame->width, frame->height, (const char *)av_x_if_null(av_get_pix_fmt_name(frame->format), "none"), is->viddec.pkt_serial); avfilter_graph_free(&graph); graph = avfilter_graph_alloc(); if ((ret = configure_video_filters(ffp, graph, is, ffp->vfilters_list ? ffp->vfilters_list[is->vfilter_idx] : NULL, frame)) < 0) { // FIXME: post error SDL_UnlockMutex(ffp->vf_mutex); goto the_end; } filt_in = is->in_video_filter; filt_out = is->out_video_filter; last_w = frame->width; last_h = frame->height; last_format = frame->format; last_serial = is->viddec.pkt_serial; last_vfilter_idx = is->vfilter_idx; frame_rate = av_buffersink_get_frame_rate(filt_out); SDL_UnlockMutex(ffp->vf_mutex); } ret = av_buffersrc_add_frame(filt_in, frame); if (ret < 0) goto the_end; while (ret >= 0) { is->frame_last_returned_time = av_gettime_relative() / 1000000.0; ret = av_buffersink_get_frame_flags(filt_out, frame, 0); if (ret < 0) { if (ret == AVERROR_EOF) is->viddec.finished = is->viddec.pkt_serial; ret = 0; break; } is->frame_last_filter_delay = av_gettime_relative() / 1000000.0 - is->frame_last_returned_time; if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0) is->frame_last_filter_delay = 0; tb = av_buffersink_get_time_base(filt_out); #endif duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0); pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb); ret = queue_picture(ffp, frame, pts, duration, frame->pkt_pos, is->viddec.pkt_serial); av_frame_unref(frame); #if CONFIG_AVFILTER } #endif if (ret < 0) goto the_end; } the_end: #if CONFIG_AVFILTER avfilter_graph_free(&graph); #endif av_log(NULL, AV_LOG_INFO, "convert image convert_frame_count = %d\n", convert_frame_count); av_frame_free(&frame); return 0; } static int video_thread(void *arg) { FFPlayer *ffp = (FFPlayer *)arg; int ret = 0; if (ffp->node_vdec) { ret = ffpipenode_run_sync(ffp->node_vdec); } return ret; } static int subtitle_thread(void *arg) { FFPlayer *ffp = arg; VideoState *is = ffp->is; Frame *sp; int got_subtitle; double pts; for (;;) { if (!(sp = frame_queue_peek_writable(&is->subpq))) return 0; if ((got_subtitle = decoder_decode_frame(ffp, &is->subdec, NULL, &sp->sub)) < 0) break; pts = 0; #ifdef FFP_MERGE if (got_subtitle && sp->sub.format == 0) { #else if (got_subtitle) { #endif if (sp->sub.pts != AV_NOPTS_VALUE) pts = sp->sub.pts / (double)AV_TIME_BASE; sp->pts = pts; sp->serial = is->subdec.pkt_serial; sp->width = is->subdec.avctx->width; sp->height = is->subdec.avctx->height; sp->uploaded = 0; /* now we can update the picture count */ frame_queue_push(&is->subpq); #ifdef FFP_MERGE } else if (got_subtitle) { avsubtitle_free(&sp->sub); #endif } } return 0; } /* copy samples for viewing in editor window */ static void update_sample_display(VideoState *is, short *samples, int samples_size) { int size, len; size = samples_size / sizeof(short); while (size > 0) { len = SAMPLE_ARRAY_SIZE - is->sample_array_index; if (len > size) len = size; memcpy(is->sample_array + is->sample_array_index, samples, len * sizeof(short)); samples += len; is->sample_array_index += len; if (is->sample_array_index >= SAMPLE_ARRAY_SIZE) is->sample_array_index = 0; size -= len; } } /* return the wanted number of samples to get better sync if sync_type is video * or external master clock */ static int synchronize_audio(VideoState *is, int nb_samples) { int wanted_nb_samples = nb_samples; /* if not master, then we try to remove or add samples to correct the clock */ if (get_master_sync_type(is) != AV_SYNC_AUDIO_MASTER) { double diff, avg_diff; int min_nb_samples, max_nb_samples; diff = get_clock(&is->audclk) - get_master_clock(is); if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) { is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum; if (is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) { /* not enough measures to have a correct estimate */ is->audio_diff_avg_count++; } else { /* estimate the A-V difference */ avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef); if (fabs(avg_diff) >= is->audio_diff_threshold) { wanted_nb_samples = nb_samples + (int)(diff * is->audio_src.freq); min_nb_samples = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100)); max_nb_samples = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100)); wanted_nb_samples = av_clip(wanted_nb_samples, min_nb_samples, max_nb_samples); } av_log(NULL, AV_LOG_TRACE, "diff=%f adiff=%f sample_diff=%d apts=%0.3f %f\n", diff, avg_diff, wanted_nb_samples - nb_samples, is->audio_clock, is->audio_diff_threshold); } } else { /* too big difference : may be initial PTS errors, so reset A-V filter */ is->audio_diff_avg_count = 0; is->audio_diff_cum = 0; } } return wanted_nb_samples; } /** * Decode one audio frame and return its uncompressed size. * * The processed audio frame is decoded, converted if required, and * stored in is->audio_buf, with size in bytes given by the return * value. */ static int audio_decode_frame(FFPlayer *ffp) { VideoState *is = ffp->is; int data_size, resampled_data_size; int64_t dec_channel_layout; av_unused double audio_clock0; int wanted_nb_samples; Frame *af; #if defined(__ANDROID__) int translate_time = 1; #endif if (is->paused || is->step) return -1; if (ffp->sync_av_start && /* sync enabled */ is->video_st && /* has video stream */ !is->viddec.first_frame_decoded && /* not hot */ is->viddec.finished != is->videoq.serial) { /* not finished */ /* waiting for first video frame */ Uint64 now = SDL_GetTickHR(); if (now < is->viddec.first_frame_decoded_time || now > is->viddec.first_frame_decoded_time + 2000) { is->viddec.first_frame_decoded = 1; } else { /* video pipeline is not ready yet */ return -1; } } reload: do { #if defined(_WIN32) || defined(__APPLE__) while (frame_queue_nb_remaining(&is->sampq) == 0) { if ((av_gettime_relative() - ffp->audio_callback_time) > 1000000LL * is->audio_hw_buf_size / is->audio_tgt.bytes_per_sec / 2) return -1; av_usleep (1000); } #endif if (!(af = frame_queue_peek_readable(&is->sampq))) return -1; frame_queue_next(&is->sampq); } while (af->serial != is->audioq.serial); data_size = av_samples_get_buffer_size(NULL, af->frame->channels, af->frame->nb_samples, af->frame->format, 1); dec_channel_layout = (af->frame->channel_layout && af->frame->channels == av_get_channel_layout_nb_channels(af->frame->channel_layout)) ? af->frame->channel_layout : av_get_default_channel_layout(af->frame->channels); wanted_nb_samples = synchronize_audio(is, af->frame->nb_samples); if (af->frame->format != is->audio_src.fmt || dec_channel_layout != is->audio_src.channel_layout || af->frame->sample_rate != is->audio_src.freq || (wanted_nb_samples != af->frame->nb_samples && !is->swr_ctx)) { AVDictionary *swr_opts = NULL; swr_free(&is->swr_ctx); is->swr_ctx = swr_alloc_set_opts(NULL, is->audio_tgt.channel_layout, is->audio_tgt.fmt, is->audio_tgt.freq, dec_channel_layout, af->frame->format, af->frame->sample_rate, 0, NULL); if (!is->swr_ctx) { av_log(NULL, AV_LOG_ERROR, "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n", af->frame->sample_rate, av_get_sample_fmt_name(af->frame->format), af->frame->channels, is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels); return -1; } av_dict_copy(&swr_opts, ffp->swr_opts, 0); if (af->frame->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) av_opt_set_double(is->swr_ctx, "center_mix_level", ffp->preset_5_1_center_mix_level, 0); av_opt_set_dict(is->swr_ctx, &swr_opts); av_dict_free(&swr_opts); if (swr_init(is->swr_ctx) < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n", af->frame->sample_rate, av_get_sample_fmt_name(af->frame->format), af->frame->channels, is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels); swr_free(&is->swr_ctx); return -1; } is->audio_src.channel_layout = dec_channel_layout; is->audio_src.channels = af->frame->channels; is->audio_src.freq = af->frame->sample_rate; is->audio_src.fmt = af->frame->format; } if (is->swr_ctx) { const uint8_t **in = (const uint8_t **)af->frame->extended_data; uint8_t **out = &is->audio_buf1; int out_count = (int)((int64_t)wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate + 256); int out_size = av_samples_get_buffer_size(NULL, is->audio_tgt.channels, out_count, is->audio_tgt.fmt, 0); int len2; if (out_size < 0) { av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size() failed\n"); return -1; } if (wanted_nb_samples != af->frame->nb_samples) { if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - af->frame->nb_samples) * is->audio_tgt.freq / af->frame->sample_rate, wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate) < 0) { av_log(NULL, AV_LOG_ERROR, "swr_set_compensation() failed\n"); return -1; } } av_fast_malloc(&is->audio_buf1, &is->audio_buf1_size, out_size); if (!is->audio_buf1) return AVERROR(ENOMEM); len2 = swr_convert(is->swr_ctx, out, out_count, in, af->frame->nb_samples); if (len2 < 0) { av_log(NULL, AV_LOG_ERROR, "swr_convert() failed\n"); return -1; } if (len2 == out_count) { av_log(NULL, AV_LOG_WARNING, "audio buffer is probably too small\n"); if (swr_init(is->swr_ctx) < 0) swr_free(&is->swr_ctx); } is->audio_buf = is->audio_buf1; 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) { 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), 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; resampled_data_size = ret_len; } else { translate_time++; goto reload; } } #endif } else { is->audio_buf = af->frame->data[0]; resampled_data_size = data_size; } audio_clock0 = is->audio_clock; /* update the audio clock with the pts */ if (!isnan(af->pts)) is->audio_clock = af->pts + (double) af->frame->nb_samples / af->frame->sample_rate; else is->audio_clock = NAN; is->audio_clock_serial = af->serial; #ifdef FFP_SHOW_AUDIO_DELAY { static double last_clock; printf("audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n", is->audio_clock - last_clock, is->audio_clock, audio_clock0); last_clock = is->audio_clock; } #endif if (!is->auddec.first_frame_decoded) { ALOGD("avcodec/Audio: first frame decoded\n"); ffp_notify_msg1(ffp, FFP_MSG_AUDIO_DECODED_START); is->auddec.first_frame_decoded_time = SDL_GetTickHR(); is->auddec.first_frame_decoded = 1; } return resampled_data_size; } /* prepare a new audio buffer */ 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) { memset(stream, 0, len); return; } ffp->audio_callback_time = av_gettime_relative(); if (ffp->pf_playback_rate_changed) { ffp->pf_playback_rate_changed = 0; #if defined(__ANDROID__) if (!ffp->soundtouch_enable) { SDL_AoutSetPlaybackRate(ffp->aout, ffp->pf_playback_rate); } #else SDL_AoutSetPlaybackRate(ffp->aout, ffp->pf_playback_rate); #endif } if (ffp->pf_playback_volume_changed) { ffp->pf_playback_volume_changed = 0; SDL_AoutSetPlaybackVolume(ffp->aout, ffp->pf_playback_volume); } while (len > 0) { if (is->audio_buf_index >= is->audio_buf_size) { audio_size = audio_decode_frame(ffp); if (audio_size < 0) { /* if error, just output silence */ is->audio_buf = NULL; is->audio_buf_size = SDL_AUDIO_MIN_BUFFER_SIZE / is->audio_tgt.frame_size * is->audio_tgt.frame_size; } else { if (is->show_mode != SHOW_MODE_VIDEO) update_sample_display(is, (int16_t *)is->audio_buf, audio_size); is->audio_buf_size = audio_size; } is->audio_buf_index = 0; } if (is->auddec.pkt_serial != is->audioq.serial) { is->audio_buf_index = is->audio_buf_size; memset(stream, 0, len); // stream += len; // len = 0; SDL_AoutFlushAudio(ffp->aout); break; } len1 = is->audio_buf_size - is->audio_buf_index; if (len1 > len) len1 = len; if (!is->muted && is->audio_buf && is->audio_volume == SDL_MIX_MAXVOLUME) memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1); else { memset(stream, 0, len1); if (!is->muted && is->audio_buf) SDL_MixAudio(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1, is->audio_volume); } len -= len1; stream += len1; is->audio_buf_index += len1; } 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)) { set_clock_at(&is->audclk, is->audio_clock - (double)(is->audio_write_buf_size) / is->audio_tgt.bytes_per_sec - SDL_AoutGetLatencySeconds(ffp->aout), is->audio_clock_serial, ffp->audio_callback_time / 1000000.0); sync_clock_to_slave(&is->extclk, &is->audclk); } if (!ffp->first_audio_frame_rendered) { ffp->first_audio_frame_rendered = 1; ffp_notify_msg1(ffp, FFP_MSG_AUDIO_RENDERING_START); } if (is->latest_audio_seek_load_serial == is->audio_clock_serial) { int latest_audio_seek_load_serial = __atomic_exchange_n(&(is->latest_audio_seek_load_serial), -1, memory_order_seq_cst); if (latest_audio_seek_load_serial == is->audio_clock_serial) { if (ffp->av_sync_type == AV_SYNC_AUDIO_MASTER) { ffp_notify_msg2(ffp, FFP_MSG_AUDIO_SEEK_RENDERING_START, 1); } else { ffp_notify_msg2(ffp, FFP_MSG_AUDIO_SEEK_RENDERING_START, 0); } } } if (ffp->render_wait_start && !ffp->start_on_prepared && is->pause_req) { while (is->pause_req && !is->abort_request) { SDL_Delay(20); } } } static int audio_open(FFPlayer *opaque, int64_t wanted_channel_layout, int wanted_nb_channels, int wanted_sample_rate, struct AudioParams *audio_hw_params) { FFPlayer *ffp = opaque; VideoState *is = ffp->is; SDL_AudioSpec wanted_spec, spec; const char *env; static const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6}; #ifdef FFP_MERGE static const int next_sample_rates[] = {0, 44100, 48000, 96000, 192000}; #endif static const int next_sample_rates[] = {0, 44100, 48000}; int next_sample_rate_idx = FF_ARRAY_ELEMS(next_sample_rates) - 1; env = SDL_getenv("SDL_AUDIO_CHANNELS"); if (env) { wanted_nb_channels = atoi(env); wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels); } if (!wanted_channel_layout || wanted_nb_channels != av_get_channel_layout_nb_channels(wanted_channel_layout)) { wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels); wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX; } wanted_nb_channels = av_get_channel_layout_nb_channels(wanted_channel_layout); wanted_spec.channels = wanted_nb_channels; wanted_spec.freq = wanted_sample_rate; if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) { av_log(NULL, AV_LOG_ERROR, "Invalid sample rate or channel count!\n"); return -1; } while (next_sample_rate_idx && next_sample_rates[next_sample_rate_idx] >= wanted_spec.freq) next_sample_rate_idx--; wanted_spec.format = AUDIO_S16SYS; wanted_spec.silence = 0; wanted_spec.samples = FFMAX(SDL_AUDIO_MIN_BUFFER_SIZE, 2 << av_log2(wanted_spec.freq / SDL_AoutGetAudioPerSecondCallBacks(ffp->aout))); wanted_spec.callback = sdl_audio_callback; wanted_spec.userdata = opaque; while (SDL_AoutOpenAudio(ffp->aout, &wanted_spec, &spec) < 0) { /* avoid infinity loop on exit. --by bbcallen */ if (is->abort_request) return -1; av_log(NULL, AV_LOG_WARNING, "SDL_OpenAudio (%d channels, %d Hz): %s\n", wanted_spec.channels, wanted_spec.freq, SDL_GetError()); wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)]; if (!wanted_spec.channels) { wanted_spec.freq = next_sample_rates[next_sample_rate_idx--]; wanted_spec.channels = wanted_nb_channels; if (!wanted_spec.freq) { av_log(NULL, AV_LOG_ERROR, "No more combinations to try, audio open failed\n"); return -1; } } wanted_channel_layout = av_get_default_channel_layout(wanted_spec.channels); } if (spec.format != AUDIO_S16SYS) { av_log(NULL, AV_LOG_ERROR, "SDL advised audio format %d is not supported!\n", spec.format); return -1; } if (spec.channels != wanted_spec.channels) { wanted_channel_layout = av_get_default_channel_layout(spec.channels); if (!wanted_channel_layout) { av_log(NULL, AV_LOG_ERROR, "SDL advised channel count %d is not supported!\n", spec.channels); return -1; } } audio_hw_params->fmt = AV_SAMPLE_FMT_S16; audio_hw_params->freq = spec.freq; audio_hw_params->channel_layout = wanted_channel_layout; audio_hw_params->channels = spec.channels; audio_hw_params->frame_size = av_samples_get_buffer_size(NULL, audio_hw_params->channels, 1, audio_hw_params->fmt, 1); audio_hw_params->bytes_per_sec = av_samples_get_buffer_size(NULL, audio_hw_params->channels, audio_hw_params->freq, audio_hw_params->fmt, 1); if (audio_hw_params->bytes_per_sec <= 0 || audio_hw_params->frame_size <= 0) { av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size failed\n"); return -1; } SDL_AoutSetDefaultLatencySeconds(ffp->aout, ((double)(2 * spec.size)) / audio_hw_params->bytes_per_sec); return spec.size; } /* open a given stream. Return 0 if OK */ static int stream_component_open(FFPlayer *ffp, int stream_index) { VideoState *is = ffp->is; AVFormatContext *ic = is->ic; AVCodecContext *avctx; AVCodec *codec = NULL; const char *forced_codec_name = NULL; AVDictionary *opts = NULL; AVDictionaryEntry *t = NULL; int sample_rate, nb_channels; int64_t channel_layout; int ret = 0; int stream_lowres = ffp->lowres; if (stream_index < 0 || stream_index >= ic->nb_streams) return -1; avctx = avcodec_alloc_context3(NULL); if (!avctx) return AVERROR(ENOMEM); ret = avcodec_parameters_to_context(avctx, ic->streams[stream_index]->codecpar); if (ret < 0) 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) codec = avcodec_find_decoder_by_name(forced_codec_name); 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); 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)); stream_lowres = av_codec_get_max_lowres(codec); } av_codec_set_lowres(avctx, stream_lowres); #if FF_API_EMU_EDGE if(stream_lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE; #endif if (ffp->fast) avctx->flags2 |= AV_CODEC_FLAG2_FAST; #if FF_API_EMU_EDGE if(codec->capabilities & AV_CODEC_CAP_DR1) avctx->flags |= CODEC_FLAG_EMU_EDGE; #endif opts = filter_codec_opts(ffp->codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec); if (!av_dict_get(opts, "threads", NULL, 0)) av_dict_set(&opts, "threads", "auto", 0); if (stream_lowres) av_dict_set_int(&opts, "lowres", stream_lowres, 0); 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) { goto fail; } if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) { av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key); #ifdef FFP_MERGE ret = AVERROR_OPTION_NOT_FOUND; goto fail; #endif } is->eof = 0; ic->streams[stream_index]->discard = AVDISCARD_DEFAULT; switch (avctx->codec_type) { case AVMEDIA_TYPE_AUDIO: #if CONFIG_AVFILTER { AVFilterContext *sink; is->audio_filter_src.freq = avctx->sample_rate; is->audio_filter_src.channels = avctx->channels; is->audio_filter_src.channel_layout = get_valid_channel_layout(avctx->channel_layout, avctx->channels); is->audio_filter_src.fmt = avctx->sample_fmt; SDL_LockMutex(ffp->af_mutex); if ((ret = configure_audio_filters(ffp, ffp->afilters, 0)) < 0) { SDL_UnlockMutex(ffp->af_mutex); goto fail; } ffp->af_changed = 0; SDL_UnlockMutex(ffp->af_mutex); sink = is->out_audio_filter; sample_rate = av_buffersink_get_sample_rate(sink); nb_channels = av_buffersink_get_channels(sink); channel_layout = av_buffersink_get_channel_layout(sink); } #else sample_rate = avctx->sample_rate; nb_channels = avctx->channels; channel_layout = avctx->channel_layout; #endif /* prepare audio output */ if ((ret = audio_open(ffp, channel_layout, nb_channels, sample_rate, &is->audio_tgt)) < 0) goto fail; ffp_set_audio_codec_info(ffp, AVCODEC_MODULE_NAME, avcodec_get_name(avctx->codec_id)); is->audio_hw_buf_size = ret; is->audio_src = is->audio_tgt; is->audio_buf_size = 0; is->audio_buf_index = 0; /* init averaging filter */ is->audio_diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB); is->audio_diff_avg_count = 0; /* since we do not have a precise anough audio FIFO fullness, we correct audio sync only if larger than this threshold */ is->audio_diff_threshold = 2.0 * is->audio_hw_buf_size / is->audio_tgt.bytes_per_sec; is->audio_stream = stream_index; is->audio_st = ic->streams[stream_index]; decoder_init(&is->auddec, avctx, &is->audioq, is->continue_read_thread); if ((is->ic->iformat->flags & (AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK)) && !is->ic->iformat->read_seek) { is->auddec.start_pts = is->audio_st->start_time; is->auddec.start_pts_tb = is->audio_st->time_base; } if ((ret = decoder_start(&is->auddec, audio_thread, ffp, "ff_audio_dec")) < 0) goto out; SDL_AoutPauseAudio(ffp->aout, 0); break; case AVMEDIA_TYPE_VIDEO: is->video_stream = stream_index; is->video_st = ic->streams[stream_index]; if (ffp->async_init_decoder) { while (!is->initialized_decoder) { SDL_Delay(5); } if (ffp->node_vdec) { is->viddec.avctx = avctx; ret = ffpipeline_config_video_decoder(ffp->pipeline, ffp); } if (ret || !ffp->node_vdec) { decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread); ffp->node_vdec = ffpipeline_open_video_decoder(ffp->pipeline, ffp); if (!ffp->node_vdec) goto fail; } } else { decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread); ffp->node_vdec = ffpipeline_open_video_decoder(ffp->pipeline, ffp); if (!ffp->node_vdec) goto fail; } if ((ret = decoder_start(&is->viddec, video_thread, ffp, "ff_video_dec")) < 0) goto out; is->queue_attachments_req = 1; if (ffp->max_fps >= 0) { if(is->video_st->avg_frame_rate.den && is->video_st->avg_frame_rate.num) { double fps = av_q2d(is->video_st->avg_frame_rate); SDL_ProfilerReset(&is->viddec.decode_profiler, fps + 0.5); if (fps > ffp->max_fps && fps < 130.0) { is->is_video_high_fps = 1; av_log(ffp, AV_LOG_WARNING, "fps: %lf (too high)\n", fps); } else { av_log(ffp, AV_LOG_WARNING, "fps: %lf (normal)\n", fps); } } if(is->video_st->r_frame_rate.den && is->video_st->r_frame_rate.num) { double tbr = av_q2d(is->video_st->r_frame_rate); if (tbr > ffp->max_fps && tbr < 130.0) { is->is_video_high_fps = 1; av_log(ffp, AV_LOG_WARNING, "fps: %lf (too high)\n", tbr); } else { av_log(ffp, AV_LOG_WARNING, "fps: %lf (normal)\n", tbr); } } } if (is->is_video_high_fps) { avctx->skip_frame = FFMAX(avctx->skip_frame, AVDISCARD_NONREF); avctx->skip_loop_filter = FFMAX(avctx->skip_loop_filter, AVDISCARD_NONREF); avctx->skip_idct = FFMAX(avctx->skip_loop_filter, AVDISCARD_NONREF); } break; case AVMEDIA_TYPE_SUBTITLE: if (!ffp->subtitle) break; is->subtitle_stream = stream_index; is->subtitle_st = ic->streams[stream_index]; ffp_set_subtitle_codec_info(ffp, AVCODEC_MODULE_NAME, avcodec_get_name(avctx->codec_id)); decoder_init(&is->subdec, avctx, &is->subtitleq, is->continue_read_thread); if ((ret = decoder_start(&is->subdec, subtitle_thread, ffp, "ff_subtitle_dec")) < 0) goto out; break; default: break; } goto out; fail: avcodec_free_context(&avctx); out: av_dict_free(&opts); return ret; } static int decode_interrupt_cb(void *ctx) { VideoState *is = ctx; return is->abort_request; } static int stream_has_enough_packets(AVStream *st, int stream_id, PacketQueue *queue, int min_frames) { return stream_id < 0 || queue->abort_request || (st->disposition & AV_DISPOSITION_ATTACHED_PIC) || #ifdef FFP_MERGE queue->nb_packets > MIN_FRAMES && (!queue->duration || av_q2d(st->time_base) * queue->duration > 1.0); #endif queue->nb_packets > min_frames; } static int is_realtime(AVFormatContext *s) { if( !strcmp(s->iformat->name, "rtp") || !strcmp(s->iformat->name, "rtsp") || !strcmp(s->iformat->name, "sdp") ) return 1; if(s->pb && ( !strncmp(s->filename, "rtp:", 4) || !strncmp(s->filename, "udp:", 4) ) ) return 1; return 0; } /* this thread gets the stream from the disk or the network */ static int read_thread(void *arg) { FFPlayer *ffp = arg; VideoState *is = ffp->is; AVFormatContext *ic = NULL; int err, i, ret __unused; int st_index[AVMEDIA_TYPE_NB]; AVPacket pkt1, *pkt = &pkt1; int64_t stream_start_time; int completed = 0; int pkt_in_play_range = 0; AVDictionaryEntry *t; SDL_mutex *wait_mutex = SDL_CreateMutex(); int scan_all_pmts_set = 0; int64_t pkt_ts; int last_error = 0; int64_t prev_io_tick_counter = 0; int64_t io_tick_counter = 0; int init_ijkmeta = 0; if (!wait_mutex) { av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError()); ret = AVERROR(ENOMEM); goto fail; } memset(st_index, -1, sizeof(st_index)); is->last_video_stream = is->video_stream = -1; is->last_audio_stream = is->audio_stream = -1; is->last_subtitle_stream = is->subtitle_stream = -1; is->eof = 0; ic = avformat_alloc_context(); if (!ic) { av_log(NULL, AV_LOG_FATAL, "Could not allocate context.\n"); ret = AVERROR(ENOMEM); goto fail; } ic->interrupt_callback.callback = decode_interrupt_cb; ic->interrupt_callback.opaque = is; if (!av_dict_get(ffp->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) { av_dict_set(&ffp->format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE); scan_all_pmts_set = 1; } if (av_stristart(is->filename, "rtmp", NULL) || av_stristart(is->filename, "rtsp", NULL)) { // There is total different meaning for 'timeout' option in rtmp av_log(ffp, AV_LOG_WARNING, "remove 'timeout' option for rtmp.\n"); av_dict_set(&ffp->format_opts, "timeout", NULL, 0); } if (ffp->skip_calc_frame_rate) { av_dict_set_int(&ic->metadata, "skip-calc-frame-rate", ffp->skip_calc_frame_rate, 0); av_dict_set_int(&ffp->format_opts, "skip-calc-frame-rate", ffp->skip_calc_frame_rate, 0); } if (ffp->iformat_name) is->iformat = av_find_input_format(ffp->iformat_name); av_dict_set_intptr(&ffp->format_opts, "video_cache_ptr", (intptr_t)&ffp->stat.video_cache, 0); av_dict_set_intptr(&ffp->format_opts, "audio_cache_ptr", (intptr_t)&ffp->stat.audio_cache, 0); err = avformat_open_input(&ic, is->filename, is->iformat, &ffp->format_opts); if (err < 0) { print_error(is->filename, err); ret = -1; goto fail; } ffp_notify_msg1(ffp, FFP_MSG_OPEN_INPUT); if (scan_all_pmts_set) av_dict_set(&ffp->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE); if ((t = av_dict_get(ffp->format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) { av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key); #ifdef FFP_MERGE ret = AVERROR_OPTION_NOT_FOUND; goto fail; #endif } is->ic = ic; if (ffp->genpts) ic->flags |= AVFMT_FLAG_GENPTS; av_format_inject_global_side_data(ic); // //AVDictionary **opts; //int orig_nb_streams; //opts = setup_find_stream_info_opts(ic, ffp->codec_opts); //orig_nb_streams = ic->nb_streams; if (ffp->find_stream_info) { AVDictionary **opts = setup_find_stream_info_opts(ic, ffp->codec_opts); int orig_nb_streams = ic->nb_streams; do { if (av_stristart(is->filename, "data:", NULL) && orig_nb_streams > 0) { for (i = 0; i < orig_nb_streams; i++) { if (!ic->streams[i] || !ic->streams[i]->codecpar || ic->streams[i]->codecpar->profile == FF_PROFILE_UNKNOWN) { break; } } if (i == orig_nb_streams) { break; } } err = avformat_find_stream_info(ic, opts); } while(0); ffp_notify_msg1(ffp, FFP_MSG_FIND_STREAM_INFO); for (i = 0; i < orig_nb_streams; i++) av_dict_free(&opts[i]); av_freep(&opts); if (err < 0) { av_log(NULL, AV_LOG_WARNING, "%s: could not find codec parameters\n", is->filename); ret = -1; goto fail; } } if (ic->pb) ic->pb->eof_reached = 0; // FIXME hack, ffplay maybe should not use avio_feof() to test for the end if (ffp->seek_by_bytes < 0) ffp->seek_by_bytes = !!(ic->iformat->flags & AVFMT_TS_DISCONT) && strcmp("ogg", ic->iformat->name); is->max_frame_duration = (ic->iformat->flags & AVFMT_TS_DISCONT) ? 10.0 : 3600.0; is->max_frame_duration = 10.0; av_log(ffp, AV_LOG_INFO, "max_frame_duration: %.3f\n", is->max_frame_duration); #ifdef FFP_MERGE if (!window_title && (t = av_dict_get(ic->metadata, "title", NULL, 0))) window_title = av_asprintf("%s - %s", t->value, input_filename); #endif /* if seeking requested, we execute it */ if (ffp->start_time != AV_NOPTS_VALUE) { int64_t timestamp; timestamp = ffp->start_time; /* add the stream start time */ if (ic->start_time != AV_NOPTS_VALUE) timestamp += ic->start_time; ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0); if (ret < 0) { av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n", is->filename, (double)timestamp / AV_TIME_BASE); } } is->realtime = is_realtime(ic); av_dump_format(ic, 0, is->filename, 0); int video_stream_count = 0; int h264_stream_count = 0; int first_h264_stream = -1; for (i = 0; i < ic->nb_streams; i++) { AVStream *st = ic->streams[i]; enum AVMediaType type = st->codecpar->codec_type; st->discard = AVDISCARD_ALL; if (type >= 0 && ffp->wanted_stream_spec[type] && st_index[type] == -1) if (avformat_match_stream_specifier(ic, st, ffp->wanted_stream_spec[type]) > 0) st_index[type] = i; // choose first h264 if (type == AVMEDIA_TYPE_VIDEO) { enum AVCodecID codec_id = st->codecpar->codec_id; video_stream_count++; if (codec_id == AV_CODEC_ID_H264) { h264_stream_count++; if (first_h264_stream < 0) first_h264_stream = i; } } } if (video_stream_count > 1 && st_index[AVMEDIA_TYPE_VIDEO] < 0) { st_index[AVMEDIA_TYPE_VIDEO] = first_h264_stream; av_log(NULL, AV_LOG_WARNING, "multiple video stream found, prefer first h264 stream: %d\n", first_h264_stream); } if (!ffp->video_disable) st_index[AVMEDIA_TYPE_VIDEO] = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, st_index[AVMEDIA_TYPE_VIDEO], -1, NULL, 0); if (!ffp->audio_disable) st_index[AVMEDIA_TYPE_AUDIO] = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, st_index[AVMEDIA_TYPE_AUDIO], st_index[AVMEDIA_TYPE_VIDEO], NULL, 0); if (!ffp->video_disable && !ffp->subtitle_disable) st_index[AVMEDIA_TYPE_SUBTITLE] = av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE, st_index[AVMEDIA_TYPE_SUBTITLE], (st_index[AVMEDIA_TYPE_AUDIO] >= 0 ? st_index[AVMEDIA_TYPE_AUDIO] : st_index[AVMEDIA_TYPE_VIDEO]), NULL, 0); is->show_mode = ffp->show_mode; #ifdef FFP_MERGE // bbc: dunno if we need this if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) { AVStream *st = ic->streams[st_index[AVMEDIA_TYPE_VIDEO]]; AVCodecParameters *codecpar = st->codecpar; AVRational sar = av_guess_sample_aspect_ratio(ic, st, NULL); if (codecpar->width) set_default_window_size(codecpar->width, codecpar->height, sar); } #endif /* open the streams */ if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) { stream_component_open(ffp, st_index[AVMEDIA_TYPE_AUDIO]); } else { ffp->av_sync_type = AV_SYNC_VIDEO_MASTER; is->av_sync_type = ffp->av_sync_type; } ret = -1; if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) { ret = stream_component_open(ffp, st_index[AVMEDIA_TYPE_VIDEO]); } if (is->show_mode == SHOW_MODE_NONE) is->show_mode = ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT; if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) { stream_component_open(ffp, st_index[AVMEDIA_TYPE_SUBTITLE]); } ffp_notify_msg1(ffp, FFP_MSG_COMPONENT_OPEN); if (!ffp->ijkmeta_delay_init) { ijkmeta_set_avformat_context_l(ffp->meta, ic); } ffp->stat.bit_rate = ic->bit_rate; if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) ijkmeta_set_int64_l(ffp->meta, IJKM_KEY_VIDEO_STREAM, st_index[AVMEDIA_TYPE_VIDEO]); if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) ijkmeta_set_int64_l(ffp->meta, IJKM_KEY_AUDIO_STREAM, st_index[AVMEDIA_TYPE_AUDIO]); if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) ijkmeta_set_int64_l(ffp->meta, IJKM_KEY_TIMEDTEXT_STREAM, st_index[AVMEDIA_TYPE_SUBTITLE]); if (is->video_stream < 0 && is->audio_stream < 0) { av_log(NULL, AV_LOG_FATAL, "Failed to open file '%s' or configure filtergraph\n", is->filename); ret = -1; goto fail; } if (is->audio_stream >= 0) { is->audioq.is_buffer_indicator = 1; is->buffer_indicator_queue = &is->audioq; } else if (is->video_stream >= 0) { is->videoq.is_buffer_indicator = 1; is->buffer_indicator_queue = &is->videoq; } else { assert("invalid streams"); } if (ffp->infinite_buffer < 0 && is->realtime) ffp->infinite_buffer = 1; if (!ffp->render_wait_start && !ffp->start_on_prepared) toggle_pause(ffp, 1); if (is->video_st && is->video_st->codecpar) { AVCodecParameters *codecpar = is->video_st->codecpar; ffp_notify_msg3(ffp, FFP_MSG_VIDEO_SIZE_CHANGED, codecpar->width, codecpar->height); ffp_notify_msg3(ffp, FFP_MSG_SAR_CHANGED, codecpar->sample_aspect_ratio.num, codecpar->sample_aspect_ratio.den); } ffp->prepared = true; ffp_notify_msg1(ffp, FFP_MSG_PREPARED); if (!ffp->render_wait_start && !ffp->start_on_prepared) { while (is->pause_req && !is->abort_request) { SDL_Delay(20); } } if (ffp->auto_resume) { ffp_notify_msg1(ffp, FFP_REQ_START); ffp->auto_resume = 0; } /* offset should be seeked*/ if (ffp->seek_at_start > 0) { ffp_seek_to_l(ffp, (long)(ffp->seek_at_start)); } for (;;) { if (is->abort_request) break; #ifdef FFP_MERGE if (is->paused != is->last_paused) { is->last_paused = is->paused; if (is->paused) is->read_pause_return = av_read_pause(ic); else av_read_play(ic); } #endif #if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL if (is->paused && (!strcmp(ic->iformat->name, "rtsp") || (ic->pb && !strncmp(ffp->input_filename, "mmsh:", 5)))) { /* wait 10 ms to avoid trying to get another packet */ /* XXX: horrible */ SDL_Delay(10); continue; } #endif if (is->seek_req) { int64_t seek_target = is->seek_pos; int64_t seek_min = is->seek_rel > 0 ? seek_target - is->seek_rel + 2: INT64_MIN; int64_t seek_max = is->seek_rel < 0 ? seek_target - is->seek_rel - 2: INT64_MAX; // FIXME the +-2 is due to rounding being not done in the correct direction in generation // of the seek_pos/seek_rel variables ffp_toggle_buffering(ffp, 1); ffp_notify_msg3(ffp, FFP_MSG_BUFFERING_UPDATE, 0, 0); ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "%s: error while seeking\n", is->ic->filename); } else { if (is->audio_stream >= 0) { packet_queue_flush(&is->audioq); packet_queue_put(&is->audioq, &flush_pkt); // TODO: clear invaild audio data // SDL_AoutFlushAudio(ffp->aout); } if (is->subtitle_stream >= 0) { packet_queue_flush(&is->subtitleq); packet_queue_put(&is->subtitleq, &flush_pkt); } if (is->video_stream >= 0) { if (ffp->node_vdec) { ffpipenode_flush(ffp->node_vdec); } packet_queue_flush(&is->videoq); packet_queue_put(&is->videoq, &flush_pkt); } if (is->seek_flags & AVSEEK_FLAG_BYTE) { set_clock(&is->extclk, NAN, 0); } else { set_clock(&is->extclk, seek_target / (double)AV_TIME_BASE, 0); } is->latest_video_seek_load_serial = is->videoq.serial; is->latest_audio_seek_load_serial = is->audioq.serial; is->latest_seek_load_start_at = av_gettime(); } ffp->dcc.current_high_water_mark_in_ms = ffp->dcc.first_high_water_mark_in_ms; is->seek_req = 0; is->queue_attachments_req = 1; is->eof = 0; #ifdef FFP_MERGE if (is->paused) step_to_next_frame(is); #endif completed = 0; SDL_LockMutex(ffp->is->play_mutex); if (ffp->auto_resume) { is->pause_req = 0; if (ffp->packet_buffering) is->buffering_on = 1; ffp->auto_resume = 0; stream_update_pause_l(ffp); } if (is->pause_req) step_to_next_frame_l(ffp); SDL_UnlockMutex(ffp->is->play_mutex); if (ffp->enable_accurate_seek) { is->drop_aframe_count = 0; is->drop_vframe_count = 0; SDL_LockMutex(is->accurate_seek_mutex); if (is->video_stream >= 0) { is->video_accurate_seek_req = 1; } if (is->audio_stream >= 0) { is->audio_accurate_seek_req = 1; } SDL_CondSignal(is->audio_accurate_seek_cond); SDL_CondSignal(is->video_accurate_seek_cond); SDL_UnlockMutex(is->accurate_seek_mutex); } ffp_notify_msg3(ffp, FFP_MSG_SEEK_COMPLETE, (int)fftime_to_milliseconds(seek_target), ret); ffp_toggle_buffering(ffp, 1); } if (is->queue_attachments_req) { if (is->video_st && (is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC)) { AVPacket copy = { 0 }; if ((ret = av_packet_ref(©, &is->video_st->attached_pic)) < 0) goto fail; packet_queue_put(&is->videoq, ©); packet_queue_put_nullpacket(&is->videoq, is->video_stream); } is->queue_attachments_req = 0; } /* if the queue are full, no need to read more */ if (ffp->infinite_buffer<1 && !is->seek_req && #ifdef FFP_MERGE (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE #else (is->audioq.size + is->videoq.size + is->subtitleq.size > ffp->dcc.max_buffer_size #endif || ( stream_has_enough_packets(is->audio_st, is->audio_stream, &is->audioq, MIN_FRAMES) && stream_has_enough_packets(is->video_st, is->video_stream, &is->videoq, MIN_FRAMES) && stream_has_enough_packets(is->subtitle_st, is->subtitle_stream, &is->subtitleq, MIN_FRAMES)))) { if (!is->eof) { ffp_toggle_buffering(ffp, 0); } /* wait 10 ms */ SDL_LockMutex(wait_mutex); SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10); SDL_UnlockMutex(wait_mutex); continue; } if ((!is->paused || completed) && (!is->audio_st || (is->auddec.finished == is->audioq.serial && frame_queue_nb_remaining(&is->sampq) == 0)) && (!is->video_st || (is->viddec.finished == is->videoq.serial && frame_queue_nb_remaining(&is->pictq) == 0))) { if (ffp->loop != 1 && (!ffp->loop || --ffp->loop)) { stream_seek(is, ffp->start_time != AV_NOPTS_VALUE ? ffp->start_time : 0, 0, 0); } else if (ffp->autoexit) { ret = AVERROR_EOF; goto fail; } else { ffp_statistic_l(ffp); if (completed) { av_log(ffp, AV_LOG_INFO, "ffp_toggle_buffering: eof\n"); SDL_LockMutex(wait_mutex); // infinite wait may block shutdown while(!is->abort_request && !is->seek_req) SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 100); SDL_UnlockMutex(wait_mutex); if (!is->abort_request) continue; } else { completed = 1; ffp->auto_resume = 0; // TODO: 0 it's a bit early to notify complete here ffp_toggle_buffering(ffp, 0); toggle_pause(ffp, 1); if (ffp->error) { av_log(ffp, AV_LOG_INFO, "ffp_toggle_buffering: error: %d\n", ffp->error); ffp_notify_msg1(ffp, FFP_MSG_ERROR); } else { av_log(ffp, AV_LOG_INFO, "ffp_toggle_buffering: completed: OK\n"); ffp_notify_msg1(ffp, FFP_MSG_COMPLETED); } } } } pkt->flags = 0; ret = av_read_frame(ic, pkt); if (ret < 0) { int pb_eof = 0; int pb_error = 0; if ((ret == AVERROR_EOF || avio_feof(ic->pb)) && !is->eof) { ffp_check_buffering_l(ffp); pb_eof = 1; // check error later } if (ic->pb && ic->pb->error) { pb_eof = 1; pb_error = ic->pb->error; } if (ret == AVERROR_EXIT) { pb_eof = 1; pb_error = AVERROR_EXIT; } if (pb_eof) { if (is->video_stream >= 0) packet_queue_put_nullpacket(&is->videoq, is->video_stream); if (is->audio_stream >= 0) packet_queue_put_nullpacket(&is->audioq, is->audio_stream); if (is->subtitle_stream >= 0) packet_queue_put_nullpacket(&is->subtitleq, is->subtitle_stream); is->eof = 1; } if (pb_error) { if (is->video_stream >= 0) packet_queue_put_nullpacket(&is->videoq, is->video_stream); if (is->audio_stream >= 0) packet_queue_put_nullpacket(&is->audioq, is->audio_stream); if (is->subtitle_stream >= 0) packet_queue_put_nullpacket(&is->subtitleq, is->subtitle_stream); is->eof = 1; ffp->error = pb_error; av_log(ffp, AV_LOG_ERROR, "av_read_frame error: %s\n", ffp_get_error_string(ffp->error)); // break; } else { ffp->error = 0; } if (is->eof) { ffp_toggle_buffering(ffp, 0); SDL_Delay(100); } SDL_LockMutex(wait_mutex); SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10); SDL_UnlockMutex(wait_mutex); ffp_statistic_l(ffp); continue; } else { is->eof = 0; } if (pkt->flags & AV_PKT_FLAG_DISCONTINUITY) { if (is->audio_stream >= 0) { packet_queue_put(&is->audioq, &flush_pkt); } if (is->subtitle_stream >= 0) { packet_queue_put(&is->subtitleq, &flush_pkt); } if (is->video_stream >= 0) { packet_queue_put(&is->videoq, &flush_pkt); } } /* check if packet is in play range specified by user, then queue, otherwise discard */ stream_start_time = ic->streams[pkt->stream_index]->start_time; pkt_ts = pkt->pts == AV_NOPTS_VALUE ? pkt->dts : pkt->pts; pkt_in_play_range = ffp->duration == AV_NOPTS_VALUE || (pkt_ts - (stream_start_time != AV_NOPTS_VALUE ? stream_start_time : 0)) * av_q2d(ic->streams[pkt->stream_index]->time_base) - (double)(ffp->start_time != AV_NOPTS_VALUE ? ffp->start_time : 0) / 1000000 <= ((double)ffp->duration / 1000000); if (pkt->stream_index == is->audio_stream && pkt_in_play_range) { packet_queue_put(&is->audioq, pkt); } else if (pkt->stream_index == is->video_stream && pkt_in_play_range && !(is->video_st && (is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC))) { packet_queue_put(&is->videoq, pkt); } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) { packet_queue_put(&is->subtitleq, pkt); } else { av_packet_unref(pkt); } ffp_statistic_l(ffp); if (ffp->ijkmeta_delay_init && !init_ijkmeta && (ffp->first_video_frame_rendered || !is->video_st) && (ffp->first_audio_frame_rendered || !is->audio_st)) { ijkmeta_set_avformat_context_l(ffp->meta, ic); init_ijkmeta = 1; } if (ffp->packet_buffering) { io_tick_counter = SDL_GetTickHR(); if ((!ffp->first_video_frame_rendered && is->video_st) || (!ffp->first_audio_frame_rendered && is->audio_st)) { if (abs((int)(io_tick_counter - prev_io_tick_counter)) > FAST_BUFFERING_CHECK_PER_MILLISECONDS) { prev_io_tick_counter = io_tick_counter; ffp->dcc.current_high_water_mark_in_ms = ffp->dcc.first_high_water_mark_in_ms; ffp_check_buffering_l(ffp); } } else { if (abs((int)(io_tick_counter - prev_io_tick_counter)) > BUFFERING_CHECK_PER_MILLISECONDS) { prev_io_tick_counter = io_tick_counter; ffp_check_buffering_l(ffp); } } } } ret = 0; fail: if (ic && !is->ic) avformat_close_input(&ic); if (!ffp->prepared || !is->abort_request) { ffp->last_error = last_error; ffp_notify_msg2(ffp, FFP_MSG_ERROR, last_error); } SDL_DestroyMutex(wait_mutex); return 0; } static int video_refresh_thread(void *arg); static VideoState *stream_open(FFPlayer *ffp, const char *filename, AVInputFormat *iformat) { assert(!ffp->is); VideoState *is; is = av_mallocz(sizeof(VideoState)); if (!is) return NULL; is->filename = av_strdup(filename); if (!is->filename) goto fail; is->iformat = iformat; is->ytop = 0; is->xleft = 0; #if defined(__ANDROID__) if (ffp->soundtouch_enable) { is->handle = ijk_soundtouch_create(); } #endif /* start video display */ if (frame_queue_init(&is->pictq, &is->videoq, ffp->pictq_size, 1) < 0) goto fail; if (frame_queue_init(&is->subpq, &is->subtitleq, SUBPICTURE_QUEUE_SIZE, 0) < 0) goto fail; if (frame_queue_init(&is->sampq, &is->audioq, SAMPLE_QUEUE_SIZE, 1) < 0) goto fail; if (packet_queue_init(&is->videoq) < 0 || packet_queue_init(&is->audioq) < 0 || packet_queue_init(&is->subtitleq) < 0) goto fail; if (!(is->continue_read_thread = SDL_CreateCond())) { av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError()); goto fail; } if (!(is->video_accurate_seek_cond = SDL_CreateCond())) { av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError()); ffp->enable_accurate_seek = 0; } if (!(is->audio_accurate_seek_cond = SDL_CreateCond())) { av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError()); ffp->enable_accurate_seek = 0; } init_clock(&is->vidclk, &is->videoq.serial); init_clock(&is->audclk, &is->audioq.serial); init_clock(&is->extclk, &is->extclk.serial); is->audio_clock_serial = -1; if (ffp->startup_volume < 0) av_log(NULL, AV_LOG_WARNING, "-volume=%d < 0, setting to 0\n", ffp->startup_volume); if (ffp->startup_volume > 100) av_log(NULL, AV_LOG_WARNING, "-volume=%d > 100, setting to 100\n", ffp->startup_volume); ffp->startup_volume = av_clip(ffp->startup_volume, 0, 100); ffp->startup_volume = av_clip(SDL_MIX_MAXVOLUME * ffp->startup_volume / 100, 0, SDL_MIX_MAXVOLUME); is->audio_volume = ffp->startup_volume; is->muted = 0; is->av_sync_type = ffp->av_sync_type; is->play_mutex = SDL_CreateMutex(); is->accurate_seek_mutex = SDL_CreateMutex(); ffp->is = is; is->pause_req = !ffp->start_on_prepared; is->video_refresh_tid = SDL_CreateThreadEx(&is->_video_refresh_tid, video_refresh_thread, ffp, "ff_vout"); if (!is->video_refresh_tid) { av_freep(&ffp->is); return NULL; } is->initialized_decoder = 0; is->read_tid = SDL_CreateThreadEx(&is->_read_tid, read_thread, ffp, "ff_read"); if (!is->read_tid) { av_log(NULL, AV_LOG_FATAL, "SDL_CreateThread(): %s\n", SDL_GetError()); goto fail; } 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) { decoder_init(&is->viddec, NULL, &is->videoq, is->continue_read_thread); ffp->node_vdec = ffpipeline_init_video_decoder(ffp->pipeline, ffp); } } is->initialized_decoder = 1; return is; fail: is->initialized_decoder = 1; is->abort_request = true; if (is->video_refresh_tid) SDL_WaitThread(is->video_refresh_tid, NULL); stream_close(ffp); return NULL; } // FFP_MERGE: stream_cycle_channel // FFP_MERGE: toggle_full_screen // FFP_MERGE: toggle_audio_display // FFP_MERGE: refresh_loop_wait_event // FFP_MERGE: event_loop // FFP_MERGE: opt_frame_size // FFP_MERGE: opt_width // FFP_MERGE: opt_height // FFP_MERGE: opt_format // FFP_MERGE: opt_frame_pix_fmt // FFP_MERGE: opt_sync // FFP_MERGE: opt_seek // FFP_MERGE: opt_duration // FFP_MERGE: opt_show_mode // FFP_MERGE: opt_input_file // FFP_MERGE: opt_codec // FFP_MERGE: dummy // FFP_MERGE: options // FFP_MERGE: show_usage // FFP_MERGE: show_help_default static int video_refresh_thread(void *arg) { FFPlayer *ffp = arg; VideoState *is = ffp->is; double remaining_time = 0.0; while (!is->abort_request) { if (remaining_time > 0.0) av_usleep((int)(int64_t)(remaining_time * 1000000.0)); remaining_time = REFRESH_RATE; if (is->show_mode != SHOW_MODE_NONE && (!is->paused || is->force_refresh)) video_refresh(ffp, &remaining_time); } return 0; } static int lockmgr(void **mtx, enum AVLockOp op) { switch (op) { case AV_LOCK_CREATE: *mtx = SDL_CreateMutex(); if (!*mtx) { av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError()); return 1; } return 0; case AV_LOCK_OBTAIN: return !!SDL_LockMutex(*mtx); case AV_LOCK_RELEASE: return !!SDL_UnlockMutex(*mtx); case AV_LOCK_DESTROY: SDL_DestroyMutex(*mtx); return 0; } return 1; } // FFP_MERGE: main /***************************************************************************** * end last line in ffplay.c ****************************************************************************/ static bool g_ffmpeg_global_inited = false; inline static int log_level_av_to_ijk(int av_level) { int ijk_level = IJK_LOG_VERBOSE; if (av_level <= AV_LOG_PANIC) ijk_level = IJK_LOG_FATAL; else if (av_level <= AV_LOG_FATAL) ijk_level = IJK_LOG_FATAL; else if (av_level <= AV_LOG_ERROR) ijk_level = IJK_LOG_ERROR; else if (av_level <= AV_LOG_WARNING) ijk_level = IJK_LOG_WARN; else if (av_level <= AV_LOG_INFO) ijk_level = IJK_LOG_INFO; // AV_LOG_VERBOSE means detailed info else if (av_level <= AV_LOG_VERBOSE) ijk_level = IJK_LOG_INFO; else if (av_level <= AV_LOG_DEBUG) ijk_level = IJK_LOG_DEBUG; else if (av_level <= AV_LOG_TRACE) ijk_level = IJK_LOG_VERBOSE; else ijk_level = IJK_LOG_VERBOSE; return ijk_level; } inline static int log_level_ijk_to_av(int ijk_level) { int av_level = IJK_LOG_VERBOSE; if (ijk_level >= IJK_LOG_SILENT) av_level = AV_LOG_QUIET; else if (ijk_level >= IJK_LOG_FATAL) av_level = AV_LOG_FATAL; else if (ijk_level >= IJK_LOG_ERROR) av_level = AV_LOG_ERROR; else if (ijk_level >= IJK_LOG_WARN) av_level = AV_LOG_WARNING; else if (ijk_level >= IJK_LOG_INFO) av_level = AV_LOG_INFO; // AV_LOG_VERBOSE means detailed info else if (ijk_level >= IJK_LOG_DEBUG) av_level = AV_LOG_DEBUG; else if (ijk_level >= IJK_LOG_VERBOSE) av_level = AV_LOG_TRACE; else if (ijk_level >= IJK_LOG_DEFAULT) av_level = AV_LOG_TRACE; else if (ijk_level >= IJK_LOG_UNKNOWN) av_level = AV_LOG_TRACE; else av_level = AV_LOG_TRACE; return av_level; } static void ffp_log_callback_brief(void *ptr, int level, const char *fmt, va_list vl) { if (level > av_log_get_level()) return; int ffplv __unused = log_level_av_to_ijk(level); VLOG(ffplv, IJK_LOG_TAG, fmt, vl); } static void ffp_log_callback_report(void *ptr, int level, const char *fmt, va_list vl) { if (level > av_log_get_level()) return; int ffplv __unused = log_level_av_to_ijk(level); va_list vl2; char line[1024]; static int print_prefix = 1; va_copy(vl2, vl); // av_log_default_callback(ptr, level, fmt, vl); av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix); va_end(vl2); ALOG(ffplv, IJK_LOG_TAG, "%s", line); } int ijkav_register_all(void); void ffp_global_init() { if (g_ffmpeg_global_inited) return; ALOGD("ijkmediaplayer version : %s", ijkmp_version()); /* register all codecs, demux and protocols */ avcodec_register_all(); #if CONFIG_AVDEVICE avdevice_register_all(); #endif #if CONFIG_AVFILTER avfilter_register_all(); #endif av_register_all(); ijkav_register_all(); avformat_network_init(); av_lockmgr_register(lockmgr); av_log_set_callback(ffp_log_callback_brief); av_init_packet(&flush_pkt); flush_pkt.data = (uint8_t *)&flush_pkt; g_ffmpeg_global_inited = true; } void ffp_global_uninit() { if (!g_ffmpeg_global_inited) return; av_lockmgr_register(NULL); // FFP_MERGE: uninit_opts avformat_network_deinit(); g_ffmpeg_global_inited = false; } void ffp_global_set_log_report(int use_report) { if (use_report) { av_log_set_callback(ffp_log_callback_report); } else { av_log_set_callback(ffp_log_callback_brief); } } void ffp_global_set_log_level(int log_level) { int av_level = log_level_ijk_to_av(log_level); av_log_set_level(av_level); } static ijk_inject_callback s_inject_callback; int inject_callback(void *opaque, int type, void *data, size_t data_size) { if (s_inject_callback) return s_inject_callback(opaque, type, data, data_size); return 0; } void ffp_global_set_inject_callback(ijk_inject_callback cb) { s_inject_callback = cb; } void ffp_io_stat_register(void (*cb)(const char *url, int type, int bytes)) { // avijk_io_stat_register(cb); } void ffp_io_stat_complete_register(void (*cb)(const char *url, int64_t read_bytes, int64_t total_size, int64_t elpased_time, int64_t total_duration)) { // avijk_io_stat_complete_register(cb); } static const char *ffp_context_to_name(void *ptr) { return "FFPlayer"; } static void *ffp_context_child_next(void *obj, void *prev) { return NULL; } static const AVClass *ffp_context_child_class_next(const AVClass *prev) { return NULL; } const AVClass ffp_context_class = { .class_name = "FFPlayer", .item_name = ffp_context_to_name, .option = ffp_context_options, .version = LIBAVUTIL_VERSION_INT, .child_next = ffp_context_child_next, .child_class_next = ffp_context_child_class_next, }; static const char *ijk_version_info() { return IJKPLAYER_VERSION; } FFPlayer *ffp_create() { av_log(NULL, AV_LOG_INFO, "av_version_info: %s\n", av_version_info()); av_log(NULL, AV_LOG_INFO, "ijk_version_info: %s\n", ijk_version_info()); FFPlayer* ffp = (FFPlayer*) av_mallocz(sizeof(FFPlayer)); if (!ffp) return NULL; msg_queue_init(&ffp->msg_queue); ffp->af_mutex = SDL_CreateMutex(); ffp->vf_mutex = SDL_CreateMutex(); ffp_reset_internal(ffp); ffp->av_class = &ffp_context_class; ffp->meta = ijkmeta_create(); av_opt_set_defaults(ffp); return ffp; } void ffp_destroy(FFPlayer *ffp) { if (!ffp) return; if (ffp->is) { av_log(NULL, AV_LOG_WARNING, "ffp_destroy_ffplayer: force stream_close()"); stream_close(ffp); ffp->is = NULL; } SDL_VoutFreeP(&ffp->vout); SDL_AoutFreeP(&ffp->aout); ffpipenode_free_p(&ffp->node_vdec); ffpipeline_free_p(&ffp->pipeline); ijkmeta_destroy_p(&ffp->meta); ffp_reset_internal(ffp); SDL_DestroyMutexP(&ffp->af_mutex); SDL_DestroyMutexP(&ffp->vf_mutex); msg_queue_destroy(&ffp->msg_queue); av_free(ffp); } void ffp_destroy_p(FFPlayer **pffp) { if (!pffp) return; ffp_destroy(*pffp); *pffp = NULL; } static AVDictionary **ffp_get_opt_dict(FFPlayer *ffp, int opt_category) { assert(ffp); switch (opt_category) { case FFP_OPT_CATEGORY_FORMAT: return &ffp->format_opts; case FFP_OPT_CATEGORY_CODEC: return &ffp->codec_opts; case FFP_OPT_CATEGORY_SWS: return &ffp->sws_dict; case FFP_OPT_CATEGORY_PLAYER: return &ffp->player_opts; case FFP_OPT_CATEGORY_SWR: return &ffp->swr_opts; default: av_log(ffp, AV_LOG_ERROR, "unknown option category %d\n", opt_category); return NULL; } } static int app_func_event(AVApplicationContext *h, int message ,void *data, size_t size) { if (!h || !h->opaque || !data) return 0; FFPlayer *ffp = (FFPlayer *)h->opaque; if (!ffp->inject_opaque) return 0; if (message == AVAPP_EVENT_IO_TRAFFIC && sizeof(AVAppIOTraffic) == size) { AVAppIOTraffic *event = (AVAppIOTraffic *)(intptr_t)data; if (event->bytes > 0) { ffp->stat.byte_count += event->bytes; SDL_SpeedSampler2Add(&ffp->stat.tcp_read_sampler, event->bytes); } } else if (message == AVAPP_EVENT_ASYNC_STATISTIC && sizeof(AVAppAsyncStatistic) == size) { AVAppAsyncStatistic *statistic = (AVAppAsyncStatistic *) (intptr_t)data; ffp->stat.buf_backwards = statistic->buf_backwards; ffp->stat.buf_forwards = statistic->buf_forwards; ffp->stat.buf_capacity = statistic->buf_capacity; } return inject_callback(ffp->inject_opaque, message , data, size); } static int ijkio_app_func_event(IjkIOApplicationContext *h, int message ,void *data, size_t size) { if (!h || !h->opaque || !data) return 0; FFPlayer *ffp = (FFPlayer *)h->opaque; if (!ffp->ijkio_inject_opaque) return 0; if (message == IJKIOAPP_EVENT_CACHE_STATISTIC && sizeof(IjkIOAppCacheStatistic) == size) { IjkIOAppCacheStatistic *statistic = (IjkIOAppCacheStatistic *) (intptr_t)data; ffp->stat.cache_physical_pos = statistic->cache_physical_pos; ffp->stat.cache_file_forwards = statistic->cache_file_forwards; ffp->stat.cache_file_pos = statistic->cache_file_pos; ffp->stat.cache_count_bytes = statistic->cache_count_bytes; ffp->stat.logical_file_size = statistic->logical_file_size; } return 0; } void ffp_set_frame_at_time(FFPlayer *ffp, const char *path, int64_t start_time, int64_t end_time, int num, int definition) { if (!ffp->get_img_info) { ffp->get_img_info = av_mallocz(sizeof(GetImgInfo)); if (!ffp->get_img_info) { ffp_notify_msg3(ffp, FFP_MSG_GET_IMG_STATE, 0, -1); return; } } if (start_time >= 0 && num > 0 && end_time >= 0 && end_time >= start_time) { ffp->get_img_info->img_path = av_strdup(path); ffp->get_img_info->start_time = start_time; ffp->get_img_info->end_time = end_time; ffp->get_img_info->num = num; ffp->get_img_info->count = num; if (definition== HD_IMAGE) { ffp->get_img_info->width = 640; ffp->get_img_info->height = 360; } else if (definition == SD_IMAGE) { ffp->get_img_info->width = 320; ffp->get_img_info->height = 180; } else { ffp->get_img_info->width = 160; ffp->get_img_info->height = 90; } } else { ffp->get_img_info->count = 0; ffp_notify_msg3(ffp, FFP_MSG_GET_IMG_STATE, 0, -1); } } void *ffp_set_ijkio_inject_opaque(FFPlayer *ffp, void *opaque) { if (!ffp) return NULL; void *prev_weak_thiz = ffp->ijkio_inject_opaque; ffp->ijkio_inject_opaque = opaque; ijkio_manager_destroyp(&ffp->ijkio_manager_ctx); ijkio_manager_create(&ffp->ijkio_manager_ctx, ffp); ijkio_manager_set_callback(ffp->ijkio_manager_ctx, ijkio_app_func_event); ffp_set_option_intptr(ffp, FFP_OPT_CATEGORY_FORMAT, "ijkiomanager", (uintptr_t)ffp->ijkio_manager_ctx); return prev_weak_thiz; } void *ffp_set_inject_opaque(FFPlayer *ffp, void *opaque) { if (!ffp) return NULL; void *prev_weak_thiz = ffp->inject_opaque; ffp->inject_opaque = opaque; av_application_closep(&ffp->app_ctx); av_application_open(&ffp->app_ctx, ffp); ffp_set_option_intptr(ffp, FFP_OPT_CATEGORY_FORMAT, "ijkapplication", (uint64_t)(intptr_t)ffp->app_ctx); ffp->app_ctx->func_on_app_event = app_func_event; return prev_weak_thiz; } void ffp_set_option(FFPlayer *ffp, int opt_category, const char *name, const char *value) { if (!ffp) return; AVDictionary **dict = ffp_get_opt_dict(ffp, opt_category); av_dict_set(dict, name, value, 0); } void ffp_set_option_int(FFPlayer *ffp, int opt_category, const char *name, int64_t value) { if (!ffp) return; AVDictionary **dict = ffp_get_opt_dict(ffp, opt_category); av_dict_set_int(dict, name, value, 0); } void ffp_set_option_intptr(FFPlayer *ffp, int opt_category, const char *name, uintptr_t value) { if (!ffp) return; AVDictionary **dict = ffp_get_opt_dict(ffp, opt_category); av_dict_set_intptr(dict, name, value, 0); } void ffp_set_overlay_format(FFPlayer *ffp, int chroma_fourcc) { switch (chroma_fourcc) { case SDL_FCC__GLES2: case SDL_FCC_I420: case SDL_FCC_YV12: case SDL_FCC_RV16: case SDL_FCC_RV24: case SDL_FCC_RV32: ffp->overlay_format = chroma_fourcc; break; #ifdef __APPLE__ case SDL_FCC_I444P10LE: ffp->overlay_format = chroma_fourcc; break; #endif default: av_log(ffp, AV_LOG_ERROR, "ffp_set_overlay_format: unknown chroma fourcc: %d\n", chroma_fourcc); break; } } int ffp_get_video_codec_info(FFPlayer *ffp, char **codec_info) { if (!codec_info) return -1; // FIXME: not thread-safe if (ffp->video_codec_info) { *codec_info = strdup(ffp->video_codec_info); } else { *codec_info = NULL; } return 0; } int ffp_get_audio_codec_info(FFPlayer *ffp, char **codec_info) { if (!codec_info) return -1; // FIXME: not thread-safe if (ffp->audio_codec_info) { *codec_info = strdup(ffp->audio_codec_info); } else { *codec_info = NULL; } return 0; } static void ffp_show_dict(FFPlayer *ffp, const char *tag, AVDictionary *dict) { AVDictionaryEntry *t = NULL; while ((t = av_dict_get(dict, "", t, AV_DICT_IGNORE_SUFFIX))) { av_log(ffp, AV_LOG_INFO, "%-*s: %-*s = %s\n", 12, tag, 28, t->key, t->value); } } #define FFP_VERSION_MODULE_NAME_LENGTH 13 static void ffp_show_version_str(FFPlayer *ffp, const char *module, const char *version) { av_log(ffp, AV_LOG_INFO, "%-*s: %s\n", FFP_VERSION_MODULE_NAME_LENGTH, module, version); } static void ffp_show_version_int(FFPlayer *ffp, const char *module, unsigned version) { av_log(ffp, AV_LOG_INFO, "%-*s: %u.%u.%u\n", FFP_VERSION_MODULE_NAME_LENGTH, module, (unsigned int)IJKVERSION_GET_MAJOR(version), (unsigned int)IJKVERSION_GET_MINOR(version), (unsigned int)IJKVERSION_GET_MICRO(version)); } int ffp_prepare_async_l(FFPlayer *ffp, const char *file_name) { assert(ffp); assert(!ffp->is); assert(file_name); if (av_stristart(file_name, "rtmp", NULL) || av_stristart(file_name, "rtsp", NULL)) { // There is total different meaning for 'timeout' option in rtmp av_log(ffp, AV_LOG_WARNING, "remove 'timeout' option for rtmp.\n"); av_dict_set(&ffp->format_opts, "timeout", NULL, 0); } /* there is a length limit in avformat */ if (strlen(file_name) + 1 > 1024) { av_log(ffp, AV_LOG_ERROR, "%s too long url\n", __func__); if (avio_find_protocol_name("ijklongurl:")) { av_dict_set(&ffp->format_opts, "ijklongurl-url", file_name, 0); file_name = "ijklongurl:"; } } av_log(NULL, AV_LOG_INFO, "===== versions =====\n"); ffp_show_version_str(ffp, "ijkplayer", ijk_version_info()); ffp_show_version_str(ffp, "FFmpeg", av_version_info()); ffp_show_version_int(ffp, "libavutil", avutil_version()); ffp_show_version_int(ffp, "libavcodec", avcodec_version()); ffp_show_version_int(ffp, "libavformat", avformat_version()); ffp_show_version_int(ffp, "libswscale", swscale_version()); ffp_show_version_int(ffp, "libswresample", swresample_version()); av_log(NULL, AV_LOG_INFO, "===== options =====\n"); ffp_show_dict(ffp, "player-opts", ffp->player_opts); ffp_show_dict(ffp, "format-opts", ffp->format_opts); ffp_show_dict(ffp, "codec-opts ", ffp->codec_opts); ffp_show_dict(ffp, "sws-opts ", ffp->sws_dict); ffp_show_dict(ffp, "swr-opts ", ffp->swr_opts); av_log(NULL, AV_LOG_INFO, "===================\n"); av_opt_set_dict(ffp, &ffp->player_opts); if (!ffp->aout) { ffp->aout = ffpipeline_open_audio_output(ffp->pipeline, ffp); if (!ffp->aout) return -1; } #if CONFIG_AVFILTER if (ffp->vfilter0) { GROW_ARRAY(ffp->vfilters_list, ffp->nb_vfilters); ffp->vfilters_list[ffp->nb_vfilters - 1] = ffp->vfilter0; } #endif VideoState *is = stream_open(ffp, file_name, NULL); if (!is) { av_log(NULL, AV_LOG_WARNING, "ffp_prepare_async_l: stream_open failed OOM"); return EIJK_OUT_OF_MEMORY; } ffp->is = is; ffp->input_filename = av_strdup(file_name); return 0; } int ffp_start_from_l(FFPlayer *ffp, long msec) { assert(ffp); VideoState *is = ffp->is; if (!is) return EIJK_NULL_IS_PTR; ffp->auto_resume = 1; ffp_toggle_buffering(ffp, 1); ffp_seek_to_l(ffp, msec); return 0; } int ffp_start_l(FFPlayer *ffp) { assert(ffp); VideoState *is = ffp->is; if (!is) return EIJK_NULL_IS_PTR; toggle_pause(ffp, 0); return 0; } int ffp_pause_l(FFPlayer *ffp) { assert(ffp); VideoState *is = ffp->is; if (!is) return EIJK_NULL_IS_PTR; toggle_pause(ffp, 1); return 0; } int ffp_is_paused_l(FFPlayer *ffp) { assert(ffp); VideoState *is = ffp->is; if (!is) return 1; return is->paused; } int ffp_stop_l(FFPlayer *ffp) { assert(ffp); VideoState *is = ffp->is; if (is) { is->abort_request = 1; toggle_pause(ffp, 1); } msg_queue_abort(&ffp->msg_queue); if (ffp->enable_accurate_seek && is && is->accurate_seek_mutex && is->audio_accurate_seek_cond && is->video_accurate_seek_cond) { SDL_LockMutex(is->accurate_seek_mutex); is->audio_accurate_seek_req = 0; is->video_accurate_seek_req = 0; SDL_CondSignal(is->audio_accurate_seek_cond); SDL_CondSignal(is->video_accurate_seek_cond); SDL_UnlockMutex(is->accurate_seek_mutex); } return 0; } int ffp_wait_stop_l(FFPlayer *ffp) { assert(ffp); if (ffp->is) { ffp_stop_l(ffp); stream_close(ffp); ffp->is = NULL; } return 0; } int ffp_seek_to_l(FFPlayer *ffp, long msec) { assert(ffp); VideoState *is = ffp->is; int64_t start_time = 0; int64_t seek_pos = milliseconds_to_fftime(msec); int64_t duration = milliseconds_to_fftime(ffp_get_duration_l(ffp)); if (!is) return EIJK_NULL_IS_PTR; if (duration > 0 && seek_pos >= duration && ffp->enable_accurate_seek) { toggle_pause(ffp, 1); ffp_notify_msg1(ffp, FFP_MSG_COMPLETED); return 0; } start_time = is->ic->start_time; if (start_time > 0 && start_time != AV_NOPTS_VALUE) seek_pos += start_time; // FIXME: 9 seek by bytes // FIXME: 9 seek out of range // FIXME: 9 seekable av_log(ffp, AV_LOG_DEBUG, "stream_seek %"PRId64"(%d) + %"PRId64", \n", seek_pos, (int)msec, start_time); stream_seek(is, seek_pos, 0, 0); return 0; } long ffp_get_current_position_l(FFPlayer *ffp) { assert(ffp); VideoState *is = ffp->is; if (!is || !is->ic) return 0; int64_t start_time = is->ic->start_time; int64_t start_diff = 0; if (start_time > 0 && start_time != AV_NOPTS_VALUE) start_diff = fftime_to_milliseconds(start_time); int64_t pos = 0; double pos_clock = get_master_clock(is); if (isnan(pos_clock)) { pos = fftime_to_milliseconds(is->seek_pos); } else { pos = pos_clock * 1000; } // If using REAL time and not ajusted, then return the real pos as calculated from the stream // the use case for this is primarily when using a custom non-seekable data source that starts // with a buffer that is NOT the start of the stream. We want the get_current_position to // return the time in the stream, and not the player's internal clock. if (ffp->no_time_adjust) { return (long)pos; } if (pos < 0 || pos < start_diff) return 0; int64_t adjust_pos = pos - start_diff; return (long)adjust_pos; } long ffp_get_duration_l(FFPlayer *ffp) { assert(ffp); VideoState *is = ffp->is; if (!is || !is->ic) return 0; int64_t duration = fftime_to_milliseconds(is->ic->duration); if (duration < 0) return 0; return (long)duration; } long ffp_get_playable_duration_l(FFPlayer *ffp) { assert(ffp); if (!ffp) return 0; return (long)ffp->playable_duration_ms; } void ffp_set_loop(FFPlayer *ffp, int loop) { assert(ffp); if (!ffp) return; ffp->loop = loop; } int ffp_get_loop(FFPlayer *ffp) { assert(ffp); if (!ffp) return 1; return ffp->loop; } int ffp_packet_queue_init(PacketQueue *q) { return packet_queue_init(q); } void ffp_packet_queue_destroy(PacketQueue *q) { return packet_queue_destroy(q); } void ffp_packet_queue_abort(PacketQueue *q) { return packet_queue_abort(q); } void ffp_packet_queue_start(PacketQueue *q) { return packet_queue_start(q); } void ffp_packet_queue_flush(PacketQueue *q) { return packet_queue_flush(q); } int ffp_packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial) { return packet_queue_get(q, pkt, block, serial); } int ffp_packet_queue_get_or_buffering(FFPlayer *ffp, PacketQueue *q, AVPacket *pkt, int *serial, int *finished) { return packet_queue_get_or_buffering(ffp, q, pkt, serial, finished); } int ffp_packet_queue_put(PacketQueue *q, AVPacket *pkt) { return packet_queue_put(q, pkt); } bool ffp_is_flush_packet(AVPacket *pkt) { if (!pkt) return false; return pkt->data == flush_pkt.data; } Frame *ffp_frame_queue_peek_writable(FrameQueue *f) { return frame_queue_peek_writable(f); } void ffp_frame_queue_push(FrameQueue *f) { return frame_queue_push(f); } int ffp_queue_picture(FFPlayer *ffp, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial) { return queue_picture(ffp, src_frame, pts, duration, pos, serial); } int ffp_get_master_sync_type(VideoState *is) { return get_master_sync_type(is); } double ffp_get_master_clock(VideoState *is) { return get_master_clock(is); } void ffp_toggle_buffering_l(FFPlayer *ffp, int buffering_on) { if (!ffp->packet_buffering) return; VideoState *is = ffp->is; if (buffering_on && !is->buffering_on) { av_log(ffp, AV_LOG_DEBUG, "ffp_toggle_buffering_l: start\n"); is->buffering_on = 1; stream_update_pause_l(ffp); if (is->seek_req) { is->seek_buffering = 1; ffp_notify_msg2(ffp, FFP_MSG_BUFFERING_START, 1); } else { ffp_notify_msg2(ffp, FFP_MSG_BUFFERING_START, 0); } } else if (!buffering_on && is->buffering_on){ av_log(ffp, AV_LOG_DEBUG, "ffp_toggle_buffering_l: end\n"); is->buffering_on = 0; stream_update_pause_l(ffp); if (is->seek_buffering) { is->seek_buffering = 0; ffp_notify_msg2(ffp, FFP_MSG_BUFFERING_END, 1); } else { ffp_notify_msg2(ffp, FFP_MSG_BUFFERING_END, 0); } } } void ffp_toggle_buffering(FFPlayer *ffp, int start_buffering) { SDL_LockMutex(ffp->is->play_mutex); ffp_toggle_buffering_l(ffp, start_buffering); SDL_UnlockMutex(ffp->is->play_mutex); } void ffp_track_statistic_l(FFPlayer *ffp, AVStream *st, PacketQueue *q, FFTrackCacheStatistic *cache) { assert(cache); if (q) { cache->bytes = q->size; cache->packets = q->nb_packets; } if (q && st && st->time_base.den > 0 && st->time_base.num > 0) { cache->duration = q->duration * av_q2d(st->time_base) * 1000; } } void ffp_audio_statistic_l(FFPlayer *ffp) { VideoState *is = ffp->is; ffp_track_statistic_l(ffp, is->audio_st, &is->audioq, &ffp->stat.audio_cache); } void ffp_video_statistic_l(FFPlayer *ffp) { VideoState *is = ffp->is; ffp_track_statistic_l(ffp, is->video_st, &is->videoq, &ffp->stat.video_cache); } void ffp_statistic_l(FFPlayer *ffp) { ffp_audio_statistic_l(ffp); ffp_video_statistic_l(ffp); } void ffp_check_buffering_l(FFPlayer *ffp) { VideoState *is = ffp->is; int hwm_in_ms = ffp->dcc.current_high_water_mark_in_ms; // use fast water mark for first loading int buf_size_percent = -1; int buf_time_percent = -1; int hwm_in_bytes = ffp->dcc.high_water_mark_in_bytes; int need_start_buffering = 0; int audio_time_base_valid = 0; int video_time_base_valid = 0; int64_t buf_time_position = -1; if(is->audio_st) audio_time_base_valid = is->audio_st->time_base.den > 0 && is->audio_st->time_base.num > 0; if(is->video_st) video_time_base_valid = is->video_st->time_base.den > 0 && is->video_st->time_base.num > 0; if (hwm_in_ms > 0) { int cached_duration_in_ms = -1; int64_t audio_cached_duration = -1; int64_t video_cached_duration = -1; if (is->audio_st && audio_time_base_valid) { audio_cached_duration = ffp->stat.audio_cache.duration; #ifdef FFP_SHOW_DEMUX_CACHE int audio_cached_percent = (int)av_rescale(audio_cached_duration, 1005, hwm_in_ms * 10); av_log(ffp, AV_LOG_DEBUG, "audio cache=%%%d milli:(%d/%d) bytes:(%d/%d) packet:(%d/%d)\n", audio_cached_percent, (int)audio_cached_duration, hwm_in_ms, is->audioq.size, hwm_in_bytes, is->audioq.nb_packets, MIN_FRAMES); #endif } if (is->video_st && video_time_base_valid) { video_cached_duration = ffp->stat.video_cache.duration; #ifdef FFP_SHOW_DEMUX_CACHE int video_cached_percent = (int)av_rescale(video_cached_duration, 1005, hwm_in_ms * 10); av_log(ffp, AV_LOG_DEBUG, "video cache=%%%d milli:(%d/%d) bytes:(%d/%d) packet:(%d/%d)\n", video_cached_percent, (int)video_cached_duration, hwm_in_ms, is->videoq.size, hwm_in_bytes, is->videoq.nb_packets, MIN_FRAMES); #endif } if (video_cached_duration > 0 && audio_cached_duration > 0) { cached_duration_in_ms = (int)IJKMIN(video_cached_duration, audio_cached_duration); } else if (video_cached_duration > 0) { cached_duration_in_ms = (int)video_cached_duration; } else if (audio_cached_duration > 0) { cached_duration_in_ms = (int)audio_cached_duration; } if (cached_duration_in_ms >= 0) { buf_time_position = ffp_get_current_position_l(ffp) + cached_duration_in_ms; ffp->playable_duration_ms = buf_time_position; buf_time_percent = (int)av_rescale(cached_duration_in_ms, 1005, hwm_in_ms * 10); #ifdef FFP_SHOW_DEMUX_CACHE av_log(ffp, AV_LOG_DEBUG, "time cache=%%%d (%d/%d)\n", buf_time_percent, cached_duration_in_ms, hwm_in_ms); #endif #ifdef FFP_NOTIFY_BUF_TIME ffp_notify_msg3(ffp, FFP_MSG_BUFFERING_TIME_UPDATE, cached_duration_in_ms, hwm_in_ms); #endif } } int cached_size = is->audioq.size + is->videoq.size; if (hwm_in_bytes > 0) { buf_size_percent = (int)av_rescale(cached_size, 1005, hwm_in_bytes * 10); #ifdef FFP_SHOW_DEMUX_CACHE av_log(ffp, AV_LOG_DEBUG, "size cache=%%%d (%d/%d)\n", buf_size_percent, cached_size, hwm_in_bytes); #endif #ifdef FFP_NOTIFY_BUF_BYTES ffp_notify_msg3(ffp, FFP_MSG_BUFFERING_BYTES_UPDATE, cached_size, hwm_in_bytes); #endif } int buf_percent = -1; if (buf_time_percent >= 0) { // alwas depend on cache duration if valid if (buf_time_percent >= 100) need_start_buffering = 1; buf_percent = buf_time_percent; } else { if (buf_size_percent >= 100) need_start_buffering = 1; buf_percent = buf_size_percent; } if (buf_time_percent >= 0 && buf_size_percent >= 0) { buf_percent = FFMIN(buf_time_percent, buf_size_percent); } if (buf_percent) { #ifdef FFP_SHOW_BUF_POS av_log(ffp, AV_LOG_DEBUG, "buf pos=%"PRId64", %%%d\n", buf_time_position, buf_percent); #endif ffp_notify_msg3(ffp, FFP_MSG_BUFFERING_UPDATE, (int)buf_time_position, buf_percent); } if (need_start_buffering) { if (hwm_in_ms < ffp->dcc.next_high_water_mark_in_ms) { hwm_in_ms = ffp->dcc.next_high_water_mark_in_ms; } else { hwm_in_ms *= 2; } if (hwm_in_ms > ffp->dcc.last_high_water_mark_in_ms) hwm_in_ms = ffp->dcc.last_high_water_mark_in_ms; ffp->dcc.current_high_water_mark_in_ms = hwm_in_ms; if (is->buffer_indicator_queue && is->buffer_indicator_queue->nb_packets > 0) { if ( (is->audioq.nb_packets >= MIN_MIN_FRAMES || is->audio_stream < 0 || is->audioq.abort_request) && (is->videoq.nb_packets >= MIN_MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request)) { ffp_toggle_buffering(ffp, 0); } } } } int ffp_video_thread(FFPlayer *ffp) { return ffplay_video_thread(ffp); } void ffp_set_video_codec_info(FFPlayer *ffp, const char *module, const char *codec) { av_freep(&ffp->video_codec_info); ffp->video_codec_info = av_asprintf("%s, %s", module ? module : "", codec ? codec : ""); av_log(ffp, AV_LOG_INFO, "VideoCodec: %s\n", ffp->video_codec_info); } void ffp_set_audio_codec_info(FFPlayer *ffp, const char *module, const char *codec) { av_freep(&ffp->audio_codec_info); ffp->audio_codec_info = av_asprintf("%s, %s", module ? module : "", codec ? codec : ""); av_log(ffp, AV_LOG_INFO, "AudioCodec: %s\n", ffp->audio_codec_info); } void ffp_set_subtitle_codec_info(FFPlayer *ffp, const char *module, const char *codec) { av_freep(&ffp->subtitle_codec_info); ffp->subtitle_codec_info = av_asprintf("%s, %s", module ? module : "", codec ? codec : ""); av_log(ffp, AV_LOG_INFO, "SubtitleCodec: %s\n", ffp->subtitle_codec_info); } void ffp_set_playback_rate(FFPlayer *ffp, float rate) { if (!ffp) return; av_log(ffp, AV_LOG_INFO, "Playback rate: %f\n", rate); ffp->pf_playback_rate = rate; ffp->pf_playback_rate_changed = 1; } void ffp_set_playback_volume(FFPlayer *ffp, float volume) { if (!ffp) return; ffp->pf_playback_volume = volume; ffp->pf_playback_volume_changed = 1; } int ffp_get_video_rotate_degrees(FFPlayer *ffp) { VideoState *is = ffp->is; if (!is) return 0; int theta = abs((int)((int64_t)round(fabs(get_rotation(is->video_st))) % 360)); switch (theta) { case 0: case 90: case 180: case 270: break; case 360: theta = 0; break; default: ALOGW("Unknown rotate degress: %d\n", theta); theta = 0; break; } return theta; } int ffp_set_stream_selected(FFPlayer *ffp, int stream, int selected) { VideoState *is = ffp->is; AVFormatContext *ic = NULL; AVCodecParameters *codecpar = NULL; if (!is) return -1; ic = is->ic; if (!ic) return -1; if (stream < 0 || stream >= ic->nb_streams) { av_log(ffp, AV_LOG_ERROR, "invalid stream index %d >= stream number (%d)\n", stream, ic->nb_streams); return -1; } codecpar = ic->streams[stream]->codecpar; if (selected) { switch (codecpar->codec_type) { case AVMEDIA_TYPE_VIDEO: if (stream != is->video_stream && is->video_stream >= 0) stream_component_close(ffp, is->video_stream); break; case AVMEDIA_TYPE_AUDIO: if (stream != is->audio_stream && is->audio_stream >= 0) stream_component_close(ffp, is->audio_stream); break; case AVMEDIA_TYPE_SUBTITLE: if (stream != is->subtitle_stream && is->subtitle_stream >= 0) stream_component_close(ffp, is->subtitle_stream); break; default: 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) { case AVMEDIA_TYPE_VIDEO: if (stream == is->video_stream) stream_component_close(ffp, is->video_stream); break; case AVMEDIA_TYPE_AUDIO: if (stream == is->audio_stream) stream_component_close(ffp, is->audio_stream); break; case AVMEDIA_TYPE_SUBTITLE: if (stream == is->subtitle_stream) stream_component_close(ffp, is->subtitle_stream); break; default: av_log(ffp, AV_LOG_ERROR, "select invalid stream %d of audio type %d\n", stream, codecpar->codec_type); return -1; } return 0; } } float ffp_get_property_float(FFPlayer *ffp, int id, float default_value) { switch (id) { case FFP_PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND: return ffp ? ffp->stat.vdps : default_value; case FFP_PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND: 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_AVDELAY: return ffp ? ffp->stat.avdelay : default_value; case FFP_PROP_FLOAT_AVDIFF: return ffp ? ffp->stat.avdiff : default_value; case FFP_PROP_FLOAT_PLAYBACK_VOLUME: return ffp ? ffp->pf_playback_volume : default_value; case FFP_PROP_FLOAT_DROP_FRAME_RATE: return ffp ? ffp->stat.drop_frame_rate : default_value; default: return default_value; } } void ffp_set_property_float(FFPlayer *ffp, int id, float value) { switch (id) { case FFP_PROP_FLOAT_PLAYBACK_RATE: ffp_set_playback_rate(ffp, value); break; case FFP_PROP_FLOAT_PLAYBACK_VOLUME: ffp_set_playback_volume(ffp, value); break; default: return; } } int64_t ffp_get_property_int64(FFPlayer *ffp, int id, int64_t default_value) { switch (id) { case FFP_PROP_INT64_SELECTED_VIDEO_STREAM: if (!ffp || !ffp->is) return default_value; return ffp->is->video_stream; case FFP_PROP_INT64_SELECTED_AUDIO_STREAM: if (!ffp || !ffp->is) return default_value; return ffp->is->audio_stream; case FFP_PROP_INT64_SELECTED_TIMEDTEXT_STREAM: if (!ffp || !ffp->is) return default_value; return ffp->is->subtitle_stream; case FFP_PROP_INT64_VIDEO_DECODER: if (!ffp) return default_value; return ffp->stat.vdec_type; case FFP_PROP_INT64_AUDIO_DECODER: return FFP_PROPV_DECODER_AVCODEC; case FFP_PROP_INT64_VIDEO_CACHED_DURATION: if (!ffp) return default_value; return ffp->stat.video_cache.duration; case FFP_PROP_INT64_AUDIO_CACHED_DURATION: if (!ffp) return default_value; return ffp->stat.audio_cache.duration; case FFP_PROP_INT64_VIDEO_CACHED_BYTES: if (!ffp) return default_value; return ffp->stat.video_cache.bytes; case FFP_PROP_INT64_AUDIO_CACHED_BYTES: if (!ffp) return default_value; return ffp->stat.audio_cache.bytes; case FFP_PROP_INT64_VIDEO_CACHED_PACKETS: if (!ffp) return default_value; return ffp->stat.video_cache.packets; case FFP_PROP_INT64_AUDIO_CACHED_PACKETS: if (!ffp) return default_value; return ffp->stat.audio_cache.packets; case FFP_PROP_INT64_BIT_RATE: return ffp ? ffp->stat.bit_rate : default_value; case FFP_PROP_INT64_TCP_SPEED: return ffp ? SDL_SpeedSampler2GetSpeed(&ffp->stat.tcp_read_sampler) : default_value; case FFP_PROP_INT64_ASYNC_STATISTIC_BUF_BACKWARDS: if (!ffp) return default_value; return ffp->stat.buf_backwards; case FFP_PROP_INT64_ASYNC_STATISTIC_BUF_FORWARDS: if (!ffp) return default_value; return ffp->stat.buf_forwards; case FFP_PROP_INT64_ASYNC_STATISTIC_BUF_CAPACITY: if (!ffp) return default_value; return ffp->stat.buf_capacity; case FFP_PROP_INT64_LATEST_SEEK_LOAD_DURATION: return ffp ? ffp->stat.latest_seek_load_duration : default_value; case FFP_PROP_INT64_TRAFFIC_STATISTIC_BYTE_COUNT: return ffp ? ffp->stat.byte_count : default_value; case FFP_PROP_INT64_CACHE_STATISTIC_PHYSICAL_POS: if (!ffp) return default_value; return ffp->stat.cache_physical_pos; case FFP_PROP_INT64_CACHE_STATISTIC_FILE_FORWARDS: if (!ffp) return default_value; return ffp->stat.cache_file_forwards; case FFP_PROP_INT64_CACHE_STATISTIC_FILE_POS: if (!ffp) return default_value; return ffp->stat.cache_file_pos; case FFP_PROP_INT64_CACHE_STATISTIC_COUNT_BYTES: if (!ffp) return default_value; return ffp->stat.cache_count_bytes; case FFP_PROP_INT64_LOGICAL_FILE_SIZE: if (!ffp) return default_value; return ffp->stat.logical_file_size; default: return default_value; } } void ffp_set_property_int64(FFPlayer *ffp, int id, int64_t value) { switch (id) { // case FFP_PROP_INT64_SELECTED_VIDEO_STREAM: // case FFP_PROP_INT64_SELECTED_AUDIO_STREAM: case FFP_PROP_INT64_SHARE_CACHE_DATA: if (ffp) { if (value) { ijkio_manager_will_share_cache_map(ffp->ijkio_manager_ctx); } else { ijkio_manager_did_share_cache_map(ffp->ijkio_manager_ctx); } } break; case FFP_PROP_INT64_IMMEDIATE_RECONNECT: if (ffp) { ijkio_manager_immediate_reconnect(ffp->ijkio_manager_ctx); } default: break; } } IjkMediaMeta *ffp_get_meta_l(FFPlayer *ffp) { if (!ffp) return NULL; return ffp->meta; } ================================================ FILE: ijkmedia/ijkplayer/ff_ffplay.h ================================================ /* * ff_ffplay.h * * Copyright (c) 2003 Bilibili * Copyright (c) 2003 Fabrice Bellard * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__FF_FFPLAY_H #define FFPLAY__FF_FFPLAY_H #include "ff_ffplay_def.h" #include "ff_fferror.h" #include "ff_ffmsg.h" void ffp_global_init(); void ffp_global_uninit(); void ffp_global_set_log_report(int use_report); void ffp_global_set_log_level(int log_level); void ffp_global_set_inject_callback(ijk_inject_callback cb); void ffp_io_stat_register(void (*cb)(const char *url, int type, int bytes)); void ffp_io_stat_complete_register(void (*cb)(const char *url, int64_t read_bytes, int64_t total_size, int64_t elpased_time, int64_t total_duration)); FFPlayer *ffp_create(); void ffp_destroy(FFPlayer *ffp); void ffp_destroy_p(FFPlayer **pffp); void ffp_reset(FFPlayer *ffp); /* set options before ffp_prepare_async_l() */ void ffp_set_frame_at_time(FFPlayer *ffp, const char *path, int64_t start_time, int64_t end_time, int num, int definition); void *ffp_set_inject_opaque(FFPlayer *ffp, void *opaque); void *ffp_set_ijkio_inject_opaque(FFPlayer *ffp, void *opaque); void ffp_set_option(FFPlayer *ffp, int opt_category, const char *name, const char *value); void ffp_set_option_int(FFPlayer *ffp, int opt_category, const char *name, int64_t value); void ffp_set_option_intptr(FFPlayer *ffp, int opt_category, const char *name, uintptr_t value); int ffp_get_video_codec_info(FFPlayer *ffp, char **codec_info); int ffp_get_audio_codec_info(FFPlayer *ffp, char **codec_info); /* playback controll */ int ffp_prepare_async_l(FFPlayer *ffp, const char *file_name); int ffp_start_from_l(FFPlayer *ffp, long msec); int ffp_start_l(FFPlayer *ffp); int ffp_pause_l(FFPlayer *ffp); int ffp_is_paused_l(FFPlayer *ffp); int ffp_stop_l(FFPlayer *ffp); int ffp_wait_stop_l(FFPlayer *ffp); /* all in milliseconds */ int ffp_seek_to_l(FFPlayer *ffp, long msec); long ffp_get_current_position_l(FFPlayer *ffp); long ffp_get_duration_l(FFPlayer *ffp); long ffp_get_playable_duration_l(FFPlayer *ffp); void ffp_set_loop(FFPlayer *ffp, int loop); int ffp_get_loop(FFPlayer *ffp); /* for internal usage */ int ffp_packet_queue_init(PacketQueue *q); void ffp_packet_queue_destroy(PacketQueue *q); void ffp_packet_queue_abort(PacketQueue *q); void ffp_packet_queue_start(PacketQueue *q); void ffp_packet_queue_flush(PacketQueue *q); int ffp_packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial); int ffp_packet_queue_get_or_buffering(FFPlayer *ffp, PacketQueue *q, AVPacket *pkt, int *serial, int *finished); int ffp_packet_queue_put(PacketQueue *q, AVPacket *pkt); bool ffp_is_flush_packet(AVPacket *pkt); Frame *ffp_frame_queue_peek_writable(FrameQueue *f); void ffp_frame_queue_push(FrameQueue *f); int ffp_queue_picture(FFPlayer *ffp, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial); int ffp_get_master_sync_type(VideoState *is); double ffp_get_master_clock(VideoState *is); void ffp_toggle_buffering_l(FFPlayer *ffp, int start_buffering); void ffp_toggle_buffering(FFPlayer *ffp, int start_buffering); void ffp_check_buffering_l(FFPlayer *ffp); void ffp_track_statistic_l(FFPlayer *ffp, AVStream *st, PacketQueue *q, FFTrackCacheStatistic *cache); void ffp_audio_statistic_l(FFPlayer *ffp); void ffp_video_statistic_l(FFPlayer *ffp); void ffp_statistic_l(FFPlayer *ffp); int ffp_video_thread(FFPlayer *ffp); void ffp_set_video_codec_info(FFPlayer *ffp, const char *module, const char *codec); void ffp_set_audio_codec_info(FFPlayer *ffp, const char *module, const char *codec); void ffp_set_subtitle_codec_info(FFPlayer *ffp, const char *module, const char *codec); void ffp_set_playback_rate(FFPlayer *ffp, float rate); void ffp_set_playback_volume(FFPlayer *ffp, float volume); int ffp_get_video_rotate_degrees(FFPlayer *ffp); int ffp_set_stream_selected(FFPlayer *ffp, int stream, int selected); float ffp_get_property_float(FFPlayer *ffp, int id, float default_value); void ffp_set_property_float(FFPlayer *ffp, int id, float value); int64_t ffp_get_property_int64(FFPlayer *ffp, int id, int64_t default_value); void ffp_set_property_int64(FFPlayer *ffp, int id, int64_t value); // must be freed with free(); struct IjkMediaMeta *ffp_get_meta_l(FFPlayer *ffp); #endif ================================================ FILE: ijkmedia/ijkplayer/ff_ffplay_debug.h ================================================ /* * ff_ffplaye_debug.h * * Copyright (c) 2015 Bilibili * Copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__FF_FFPLAY_DEBUG_H #define FFPLAY__FF_FFPLAY_DEBUG_H #define FFP_XPS_PERIOD (3) #define FFP_SHOW_VPS_DPS (0) #define FFP_SHOW_VFPS_FFPLAY (FFP_SHOW_VPS_DPS) #define FFP_SHOW_VDPS_AVCODEC (FFP_SHOW_VPS_DPS) #define FFP_SHOW_VDPS_VIDEOTOOLBOX (FFP_SHOW_VPS_DPS) #define FFP_SHOW_VDPS_MEDIACODEC (FFP_SHOW_VPS_DPS) // #define FFP_SHOW_AUDIO_DELAY // #define FFP_SHOW_DEMUX_CACHE // #define FFP_SHOW_BUF_POS // #define FFP_SHOW_PKT_RECYCLE // #define FFP_NOTIFY_BUF_TIME // #define FFP_NOTIFY_BUF_BYTES // #define FFP_SHOW_VTB_IN_DECODING // #define FFP_VTB_DISABLE_OUTPUT // #define FFP_SHOW_AMC_DROPS // #define FFP_AMC_DISABLE_OUTPUT // #define FFP_AVFILTER_PLAYBACK_RATE #endif ================================================ FILE: ijkmedia/ijkplayer/ff_ffplay_def.h ================================================ /* * Copyright (c) 2003 Bilibili * Copyright (c) 2003 Fabrice Bellard * Copyright (c) 2013-2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__FF_FFPLAY_DEF_H #define FFPLAY__FF_FFPLAY_DEF_H /** * @file * simple media player based on the FFmpeg libraries */ #include "config.h" #include #include #include #include #include #include "libavutil/avstring.h" #include "libavutil/eval.h" #include "libavutil/mathematics.h" #include "libavutil/pixdesc.h" #include "libavutil/imgutils.h" #include "libavutil/dict.h" #include "libavutil/parseutils.h" #include "libavutil/samplefmt.h" #include "libavutil/avassert.h" #include "libavutil/time.h" #include "libavformat/avformat.h" // FFP_MERGE: #include "libavdevice/avdevice.h" #include "libswscale/swscale.h" #include "libavutil/opt.h" #include "libavcodec/avfft.h" #include "libswresample/swresample.h" #if CONFIG_AVFILTER # include "libavfilter/avfilter.h" # include "libavfilter/buffersink.h" # include "libavfilter/buffersrc.h" #endif #include #include "ijkavformat/ijkiomanager.h" #include "ijkavformat/ijkioapplication.h" #include "ff_ffinc.h" #include "ff_ffmsg_queue.h" #include "ff_ffpipenode.h" #include "ijkmeta.h" #define DEFAULT_HIGH_WATER_MARK_IN_BYTES (256 * 1024) /* * START: buffering after prepared/seeked * NEXT: buffering for the second time after START * MAX: ... */ #define DEFAULT_FIRST_HIGH_WATER_MARK_IN_MS (100) #define DEFAULT_NEXT_HIGH_WATER_MARK_IN_MS (1 * 1000) #define DEFAULT_LAST_HIGH_WATER_MARK_IN_MS (5 * 1000) #define BUFFERING_CHECK_PER_BYTES (512) #define BUFFERING_CHECK_PER_MILLISECONDS (500) #define FAST_BUFFERING_CHECK_PER_MILLISECONDS (50) #define MAX_RETRY_CONVERT_IMAGE (3) #define MAX_QUEUE_SIZE (15 * 1024 * 1024) #define MAX_ACCURATE_SEEK_TIMEOUT (5000) #ifdef FFP_MERGE #define MIN_FRAMES 25 #endif #define DEFAULT_MIN_FRAMES 50000 #define MIN_MIN_FRAMES 2 #define MAX_MIN_FRAMES 50000 #define MIN_FRAMES (ffp->dcc.min_frames) #define EXTERNAL_CLOCK_MIN_FRAMES 2 #define EXTERNAL_CLOCK_MAX_FRAMES 10 /* Minimum SDL audio buffer size, in samples. */ #define SDL_AUDIO_MIN_BUFFER_SIZE 512 /* Calculate actual buffer size keeping in mind not cause too frequent audio callbacks */ #define SDL_AUDIO_MAX_CALLBACKS_PER_SEC 30 /* Step size for volume control */ #define SDL_VOLUME_STEP (SDL_MIX_MAXVOLUME / 50) /* no AV sync correction is done if below the minimum AV sync threshold */ #define AV_SYNC_THRESHOLD_MIN 0.04 /* AV sync correction is done if above the maximum AV sync threshold */ #define AV_SYNC_THRESHOLD_MAX 0.1 /* If a frame duration is longer than this, it will not be duplicated to compensate AV sync */ #define AV_SYNC_FRAMEDUP_THRESHOLD 0.15 /* no AV correction is done if too big error */ #define AV_NOSYNC_THRESHOLD 100.0 /* maximum audio speed change to get correct sync */ #define SAMPLE_CORRECTION_PERCENT_MAX 10 /* external clock speed adjustment constants for realtime sources based on buffer fullness */ #define EXTERNAL_CLOCK_SPEED_MIN 0.900 #define EXTERNAL_CLOCK_SPEED_MAX 1.010 #define EXTERNAL_CLOCK_SPEED_STEP 0.001 /* we use about AUDIO_DIFF_AVG_NB A-V differences to make the average */ #define AUDIO_DIFF_AVG_NB 20 /* polls for possible required screen refresh at least this often, should be less than 1/fps */ #define REFRESH_RATE 0.01 /* NOTE: the size must be big enough to compensate the hardware audio buffersize size */ /* TODO: We assume that a decoded and resampled frame fits into this buffer */ #define SAMPLE_ARRAY_SIZE (8 * 65536) #define MIN_PKT_DURATION 15 #ifdef FFP_MERGE #define CURSOR_HIDE_DELAY 1000000 #define USE_ONEPASS_SUBTITLE_RENDER 1 static unsigned sws_flags = SWS_BICUBIC; #endif #define HD_IMAGE 2 // 640*360 #define SD_IMAGE 1 // 320*180 #define LD_IMAGE 0 // 160*90 #define MAX_DEVIATION 1200000 // 1200ms typedef struct GetImgInfo { char *img_path; int64_t start_time; int64_t end_time; int64_t frame_interval; int num; int count; int width; int height; AVCodecContext *frame_img_codec_ctx; struct SwsContext *frame_img_convert_ctx; } GetImgInfo; typedef struct MyAVPacketList { AVPacket pkt; struct MyAVPacketList *next; int serial; } MyAVPacketList; typedef struct PacketQueue { MyAVPacketList *first_pkt, *last_pkt; int nb_packets; int size; int64_t duration; int abort_request; int serial; SDL_mutex *mutex; SDL_cond *cond; MyAVPacketList *recycle_pkt; int recycle_count; int alloc_count; int is_buffer_indicator; } PacketQueue; // #define VIDEO_PICTURE_QUEUE_SIZE 3 #define VIDEO_PICTURE_QUEUE_SIZE_MIN (3) #define VIDEO_PICTURE_QUEUE_SIZE_MAX (16) #define VIDEO_PICTURE_QUEUE_SIZE_DEFAULT (VIDEO_PICTURE_QUEUE_SIZE_MIN) #define SUBPICTURE_QUEUE_SIZE 16 #define SAMPLE_QUEUE_SIZE 9 #define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE_MAX, SUBPICTURE_QUEUE_SIZE)) #define VIDEO_MAX_FPS_DEFAULT 30 typedef struct AudioParams { int freq; int channels; int64_t channel_layout; enum AVSampleFormat fmt; int frame_size; int bytes_per_sec; } AudioParams; typedef struct Clock { double pts; /* clock base */ double pts_drift; /* clock base minus time at which we updated the clock */ double last_updated; double speed; int serial; /* clock is based on a packet with this serial */ int paused; int *queue_serial; /* pointer to the current packet queue serial, used for obsolete clock detection */ } Clock; /* Common struct for handling all types of decoded data and allocated render buffers. */ typedef struct Frame { AVFrame *frame; AVSubtitle sub; int serial; double pts; /* presentation timestamp for the frame */ double duration; /* estimated duration of the frame */ int64_t pos; /* byte position of the frame in the input file */ #ifdef FFP_MERGE SDL_Texture *bmp; #else SDL_VoutOverlay *bmp; #endif int allocated; int width; int height; int format; AVRational sar; int uploaded; } Frame; typedef struct FrameQueue { Frame queue[FRAME_QUEUE_SIZE]; int rindex; int windex; int size; int max_size; int keep_last; int rindex_shown; SDL_mutex *mutex; SDL_cond *cond; PacketQueue *pktq; } FrameQueue; enum { AV_SYNC_AUDIO_MASTER, /* default choice */ AV_SYNC_VIDEO_MASTER, AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */ }; typedef struct Decoder { AVPacket pkt; AVPacket pkt_temp; PacketQueue *queue; AVCodecContext *avctx; int pkt_serial; int finished; int packet_pending; int bfsc_ret; uint8_t *bfsc_data; SDL_cond *empty_queue_cond; int64_t start_pts; AVRational start_pts_tb; int64_t next_pts; AVRational next_pts_tb; SDL_Thread *decoder_tid; SDL_Thread _decoder_tid; SDL_Profiler decode_profiler; Uint64 first_frame_decoded_time; int first_frame_decoded; } Decoder; typedef struct VideoState { SDL_Thread *read_tid; SDL_Thread _read_tid; AVInputFormat *iformat; int abort_request; int force_refresh; int paused; int last_paused; int queue_attachments_req; int seek_req; int seek_flags; int64_t seek_pos; int64_t seek_rel; #ifdef FFP_MERGE int read_pause_return; #endif AVFormatContext *ic; int realtime; Clock audclk; Clock vidclk; Clock extclk; FrameQueue pictq; FrameQueue subpq; FrameQueue sampq; Decoder auddec; Decoder viddec; Decoder subdec; int audio_stream; int av_sync_type; void *handle; double audio_clock; int audio_clock_serial; double audio_diff_cum; /* used for AV difference average computation */ double audio_diff_avg_coef; double audio_diff_threshold; int audio_diff_avg_count; AVStream *audio_st; PacketQueue audioq; int audio_hw_buf_size; uint8_t *audio_buf; uint8_t *audio_buf1; short *audio_new_buf; /* for soundtouch buf */ unsigned int audio_buf_size; /* in bytes */ unsigned int audio_buf1_size; unsigned int audio_new_buf_size; int audio_buf_index; /* in bytes */ int audio_write_buf_size; int audio_volume; int muted; struct AudioParams audio_src; #if CONFIG_AVFILTER struct AudioParams audio_filter_src; #endif struct AudioParams audio_tgt; struct SwrContext *swr_ctx; int frame_drops_early; int frame_drops_late; int continuous_frame_drops_early; enum ShowMode { SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB } show_mode; int16_t sample_array[SAMPLE_ARRAY_SIZE]; int sample_array_index; int last_i_start; #ifdef FFP_MERGE RDFTContext *rdft; int rdft_bits; FFTSample *rdft_data; int xpos; #endif double last_vis_time; #ifdef FFP_MERGE SDL_Texture *vis_texture; SDL_Texture *sub_texture; #endif int subtitle_stream; AVStream *subtitle_st; PacketQueue subtitleq; double frame_timer; double frame_last_returned_time; double frame_last_filter_delay; int video_stream; AVStream *video_st; PacketQueue videoq; double max_frame_duration; // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity struct SwsContext *img_convert_ctx; #ifdef FFP_SUB struct SwsContext *sub_convert_ctx; #endif int eof; char *filename; int width, height, xleft, ytop; int step; #if CONFIG_AVFILTER int vfilter_idx; AVFilterContext *in_video_filter; // the first filter in the video chain AVFilterContext *out_video_filter; // the last filter in the video chain AVFilterContext *in_audio_filter; // the first filter in the audio chain AVFilterContext *out_audio_filter; // the last filter in the audio chain AVFilterGraph *agraph; // audio filter graph #endif int last_video_stream, last_audio_stream, last_subtitle_stream; SDL_cond *continue_read_thread; /* extra fields */ SDL_mutex *play_mutex; // only guard state, do not block any long operation SDL_Thread *video_refresh_tid; SDL_Thread _video_refresh_tid; int buffering_on; int pause_req; int dropping_frame; int is_video_high_fps; // above 30fps int is_video_high_res; // above 1080p PacketQueue *buffer_indicator_queue; volatile int latest_video_seek_load_serial; volatile int latest_audio_seek_load_serial; volatile int64_t latest_seek_load_start_at; int drop_aframe_count; int drop_vframe_count; int64_t accurate_seek_start_time; volatile int64_t accurate_seek_vframe_pts; volatile int64_t accurate_seek_aframe_pts; int audio_accurate_seek_req; int video_accurate_seek_req; SDL_mutex *accurate_seek_mutex; SDL_cond *video_accurate_seek_cond; SDL_cond *audio_accurate_seek_cond; volatile int initialized_decoder; int seek_buffering; } VideoState; /* options specified by the user */ #ifdef FFP_MERGE static AVInputFormat *file_iformat; static const char *input_filename; static const char *window_title; static int default_width = 640; static int default_height = 480; static int screen_width = 0; static int screen_height = 0; static int audio_disable; static int video_disable; static int subtitle_disable; static const char* wanted_stream_spec[AVMEDIA_TYPE_NB] = {0}; static int seek_by_bytes = -1; static int display_disable; static int show_status = 1; static int av_sync_type = AV_SYNC_AUDIO_MASTER; static int64_t start_time = AV_NOPTS_VALUE; static int64_t duration = AV_NOPTS_VALUE; static int fast = 0; static int genpts = 0; static int lowres = 0; static int decoder_reorder_pts = -1; static int autoexit; static int exit_on_keydown; static int exit_on_mousedown; static int loop = 1; static int framedrop = -1; static int infinite_buffer = -1; static enum ShowMode show_mode = SHOW_MODE_NONE; static const char *audio_codec_name; static const char *subtitle_codec_name; static const char *video_codec_name; double rdftspeed = 0.02; static int64_t cursor_last_shown; static int cursor_hidden = 0; #if CONFIG_AVFILTER static const char **vfilters_list = NULL; static int nb_vfilters = 0; static char *afilters = NULL; #endif static int autorotate = 1; static int find_stream_info = 1; /* current context */ static int is_full_screen; static int64_t audio_callback_time; static AVPacket flush_pkt; static AVPacket eof_pkt; #define FF_ALLOC_EVENT (SDL_USEREVENT) #define FF_QUIT_EVENT (SDL_USEREVENT + 2) static SDL_Window *window; static SDL_Renderer *renderer; #endif /***************************************************************************** * end at line 330 in ffplay.c * near packet_queue_put ****************************************************************************/ typedef struct FFTrackCacheStatistic { int64_t duration; int64_t bytes; int64_t packets; } FFTrackCacheStatistic; typedef struct FFStatistic { int64_t vdec_type; float vfps; float vdps; float avdelay; float avdiff; int64_t bit_rate; FFTrackCacheStatistic video_cache; FFTrackCacheStatistic audio_cache; int64_t buf_backwards; int64_t buf_forwards; int64_t buf_capacity; SDL_SpeedSampler2 tcp_read_sampler; int64_t latest_seek_load_duration; int64_t byte_count; int64_t cache_physical_pos; int64_t cache_file_forwards; int64_t cache_file_pos; int64_t cache_count_bytes; int64_t logical_file_size; int drop_frame_count; int decode_frame_count; float drop_frame_rate; } FFStatistic; #define FFP_TCP_READ_SAMPLE_RANGE 2000 inline static void ffp_reset_statistic(FFStatistic *dcc) { memset(dcc, 0, sizeof(FFStatistic)); SDL_SpeedSampler2Reset(&dcc->tcp_read_sampler, FFP_TCP_READ_SAMPLE_RANGE); } typedef struct FFDemuxCacheControl { int min_frames; int max_buffer_size; int high_water_mark_in_bytes; int first_high_water_mark_in_ms; int next_high_water_mark_in_ms; int last_high_water_mark_in_ms; int current_high_water_mark_in_ms; } FFDemuxCacheControl; inline static void ffp_reset_demux_cache_control(FFDemuxCacheControl *dcc) { dcc->min_frames = DEFAULT_MIN_FRAMES; dcc->max_buffer_size = MAX_QUEUE_SIZE; dcc->high_water_mark_in_bytes = DEFAULT_HIGH_WATER_MARK_IN_BYTES; dcc->first_high_water_mark_in_ms = DEFAULT_FIRST_HIGH_WATER_MARK_IN_MS; dcc->next_high_water_mark_in_ms = DEFAULT_NEXT_HIGH_WATER_MARK_IN_MS; dcc->last_high_water_mark_in_ms = DEFAULT_LAST_HIGH_WATER_MARK_IN_MS; dcc->current_high_water_mark_in_ms = DEFAULT_FIRST_HIGH_WATER_MARK_IN_MS; } /* ffplayer */ struct IjkMediaMeta; struct IJKFF_Pipeline; typedef struct FFPlayer { const AVClass *av_class; /* ffplay context */ VideoState *is; /* format/codec options */ AVDictionary *format_opts; AVDictionary *codec_opts; AVDictionary *sws_dict; AVDictionary *player_opts; AVDictionary *swr_opts; AVDictionary *swr_preset_opts; /* ffplay options specified by the user */ #ifdef FFP_MERGE AVInputFormat *file_iformat; #endif char *input_filename; #ifdef FFP_MERGE const char *window_title; int fs_screen_width; int fs_screen_height; int default_width; int default_height; int screen_width; int screen_height; #endif int audio_disable; int video_disable; int subtitle_disable; const char* wanted_stream_spec[AVMEDIA_TYPE_NB]; int seek_by_bytes; int display_disable; int show_status; int av_sync_type; int64_t start_time; int64_t duration; int fast; int genpts; int lowres; int decoder_reorder_pts; int autoexit; #ifdef FFP_MERGE int exit_on_keydown; int exit_on_mousedown; #endif int loop; int framedrop; int64_t seek_at_start; int subtitle; int infinite_buffer; enum ShowMode show_mode; char *audio_codec_name; char *subtitle_codec_name; char *video_codec_name; double rdftspeed; #ifdef FFP_MERGE int64_t cursor_last_shown; int cursor_hidden; #endif #if CONFIG_AVFILTER const char **vfilters_list; int nb_vfilters; char *afilters; char *vfilter0; #endif int autorotate; int find_stream_info; unsigned sws_flags; /* current context */ #ifdef FFP_MERGE int is_full_screen; #endif int64_t audio_callback_time; #ifdef FFP_MERGE SDL_Surface *screen; #endif /* extra fields */ SDL_Aout *aout; SDL_Vout *vout; struct IJKFF_Pipeline *pipeline; struct IJKFF_Pipenode *node_vdec; int sar_num; int sar_den; char *video_codec_info; char *audio_codec_info; char *subtitle_codec_info; Uint32 overlay_format; int last_error; int prepared; int auto_resume; int error; int error_count; int start_on_prepared; int first_video_frame_rendered; int first_audio_frame_rendered; int sync_av_start; MessageQueue msg_queue; int64_t playable_duration_ms; int packet_buffering; int pictq_size; int max_fps; int startup_volume; int videotoolbox; int vtb_max_frame_width; int vtb_async; int vtb_wait_async; int vtb_handle_resolution_change; int mediacodec_all_videos; int mediacodec_avc; int mediacodec_hevc; int mediacodec_mpeg2; int mediacodec_mpeg4; int mediacodec_handle_resolution_change; int mediacodec_auto_rotate; int opensles; int soundtouch_enable; char *iformat_name; int no_time_adjust; double preset_5_1_center_mix_level; struct IjkMediaMeta *meta; SDL_SpeedSampler vfps_sampler; SDL_SpeedSampler vdps_sampler; /* filters */ SDL_mutex *vf_mutex; SDL_mutex *af_mutex; int vf_changed; int af_changed; float pf_playback_rate; int pf_playback_rate_changed; float pf_playback_volume; int pf_playback_volume_changed; void *inject_opaque; void *ijkio_inject_opaque; FFStatistic stat; FFDemuxCacheControl dcc; AVApplicationContext *app_ctx; IjkIOManagerContext *ijkio_manager_ctx; int enable_accurate_seek; int accurate_seek_timeout; int mediacodec_sync; int skip_calc_frame_rate; int get_frame_mode; GetImgInfo *get_img_info; int async_init_decoder; char *video_mime_type; char *mediacodec_default_name; int ijkmeta_delay_init; int render_wait_start; } FFPlayer; #define fftime_to_milliseconds(ts) (av_rescale(ts, 1000, AV_TIME_BASE)) #define milliseconds_to_fftime(ms) (av_rescale(ms, AV_TIME_BASE, 1000)) inline static void ffp_reset_internal(FFPlayer *ffp) { /* ffp->is closed in stream_close() */ av_opt_free(ffp); /* format/codec options */ av_dict_free(&ffp->format_opts); av_dict_free(&ffp->codec_opts); av_dict_free(&ffp->sws_dict); av_dict_free(&ffp->player_opts); av_dict_free(&ffp->swr_opts); av_dict_free(&ffp->swr_preset_opts); /* ffplay options specified by the user */ av_freep(&ffp->input_filename); ffp->audio_disable = 0; ffp->video_disable = 0; memset(ffp->wanted_stream_spec, 0, sizeof(ffp->wanted_stream_spec)); ffp->seek_by_bytes = -1; ffp->display_disable = 0; ffp->show_status = 0; ffp->av_sync_type = AV_SYNC_AUDIO_MASTER; ffp->start_time = AV_NOPTS_VALUE; ffp->duration = AV_NOPTS_VALUE; ffp->fast = 1; ffp->genpts = 0; ffp->lowres = 0; ffp->decoder_reorder_pts = -1; ffp->autoexit = 0; ffp->loop = 1; ffp->framedrop = 0; // option ffp->seek_at_start = 0; ffp->infinite_buffer = -1; ffp->show_mode = SHOW_MODE_NONE; av_freep(&ffp->audio_codec_name); av_freep(&ffp->video_codec_name); ffp->rdftspeed = 0.02; #if CONFIG_AVFILTER av_freep(&ffp->vfilters_list); ffp->nb_vfilters = 0; ffp->afilters = NULL; ffp->vfilter0 = NULL; #endif ffp->autorotate = 1; ffp->find_stream_info = 1; ffp->sws_flags = SWS_FAST_BILINEAR; /* current context */ ffp->audio_callback_time = 0; /* extra fields */ ffp->aout = NULL; /* reset outside */ ffp->vout = NULL; /* reset outside */ ffp->pipeline = NULL; ffp->node_vdec = NULL; ffp->sar_num = 0; ffp->sar_den = 0; av_freep(&ffp->video_codec_info); av_freep(&ffp->audio_codec_info); av_freep(&ffp->subtitle_codec_info); ffp->overlay_format = SDL_FCC_RV32; ffp->last_error = 0; ffp->prepared = 0; ffp->auto_resume = 0; ffp->error = 0; ffp->error_count = 0; ffp->start_on_prepared = 1; ffp->first_video_frame_rendered = 0; ffp->sync_av_start = 1; ffp->enable_accurate_seek = 0; ffp->accurate_seek_timeout = MAX_ACCURATE_SEEK_TIMEOUT; ffp->playable_duration_ms = 0; ffp->packet_buffering = 1; ffp->pictq_size = VIDEO_PICTURE_QUEUE_SIZE_DEFAULT; // option ffp->max_fps = 31; // option ffp->videotoolbox = 0; // option ffp->vtb_max_frame_width = 0; // option ffp->vtb_async = 0; // option 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_handle_resolution_change = 0; // option ffp->mediacodec_auto_rotate = 0; // option ffp->opensles = 0; // option ffp->soundtouch_enable = 0; // option ffp->iformat_name = NULL; // option ffp->no_time_adjust = 0; // option ffp->async_init_decoder = 0; // option ffp->video_mime_type = NULL; // option ffp->mediacodec_default_name = NULL; // option ffp->ijkmeta_delay_init = 0; // option ffp->render_wait_start = 0; ijkmeta_reset(ffp->meta); SDL_SpeedSamplerReset(&ffp->vfps_sampler); SDL_SpeedSamplerReset(&ffp->vdps_sampler); /* filters */ ffp->vf_changed = 0; ffp->af_changed = 0; ffp->pf_playback_rate = 1.0f; ffp->pf_playback_rate_changed = 0; ffp->pf_playback_volume = 1.0f; ffp->pf_playback_volume_changed = 0; av_application_closep(&ffp->app_ctx); ijkio_manager_destroyp(&ffp->ijkio_manager_ctx); msg_queue_flush(&ffp->msg_queue); ffp->inject_opaque = NULL; ffp->ijkio_inject_opaque = NULL; ffp_reset_statistic(&ffp->stat); ffp_reset_demux_cache_control(&ffp->dcc); } inline static void ffp_notify_msg1(FFPlayer *ffp, int what) { msg_queue_put_simple3(&ffp->msg_queue, what, 0, 0); } inline static void ffp_notify_msg2(FFPlayer *ffp, int what, int arg1) { msg_queue_put_simple3(&ffp->msg_queue, what, arg1, 0); } inline static void ffp_notify_msg3(FFPlayer *ffp, int what, int arg1, int arg2) { msg_queue_put_simple3(&ffp->msg_queue, what, arg1, arg2); } inline static void ffp_notify_msg4(FFPlayer *ffp, int what, int arg1, int arg2, void *obj, int obj_len) { msg_queue_put_simple4(&ffp->msg_queue, what, arg1, arg2, obj, obj_len); } inline static void ffp_remove_msg(FFPlayer *ffp, int what) { msg_queue_remove(&ffp->msg_queue, what); } inline static const char *ffp_get_error_string(int error) { switch (error) { case AVERROR(ENOMEM): return "AVERROR(ENOMEM)"; // 12 case AVERROR(EINVAL): return "AVERROR(EINVAL)"; // 22 case AVERROR(EAGAIN): return "AVERROR(EAGAIN)"; // 35 case AVERROR(ETIMEDOUT): return "AVERROR(ETIMEDOUT)"; // 60 case AVERROR_EOF: return "AVERROR_EOF"; case AVERROR_EXIT: return "AVERROR_EXIT"; } return "unknown"; } #define FFTRACE ALOGW #define AVCODEC_MODULE_NAME "avcodec" #define MEDIACODEC_MODULE_NAME "MediaCodec" #endif ================================================ FILE: ijkmedia/ijkplayer/ff_ffplay_options.h ================================================ /* * ff_ffplaye_options.h * * Copyright (c) 2015 Bilibili * Copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__FF_FFPLAY_OPTIONS_H #define FFPLAY__FF_FFPLAY_OPTIONS_H #define OPTION_OFFSET(x) offsetof(FFPlayer, x) #define OPTION_INT(default__, min__, max__) \ .type = AV_OPT_TYPE_INT, \ { .i64 = default__ }, \ .min = min__, \ .max = max__, \ .flags = AV_OPT_FLAG_DECODING_PARAM #define OPTION_INT64(default__, min__, max__) \ .type = AV_OPT_TYPE_INT64, \ { .i64 = default__ }, \ .min = min__, \ .max = max__, \ .flags = AV_OPT_FLAG_DECODING_PARAM #define OPTION_DOUBLE(default__, min__, max__) \ .type = AV_OPT_TYPE_DOUBLE, \ { .dbl = default__ }, \ .min = min__, \ .max = max__, \ .flags = AV_OPT_FLAG_DECODING_PARAM #define OPTION_CONST(default__) \ .type = AV_OPT_TYPE_CONST, \ { .i64 = default__ }, \ .min = INT_MIN, \ .max = INT_MAX, \ .flags = AV_OPT_FLAG_DECODING_PARAM #define OPTION_STR(default__) \ .type = AV_OPT_TYPE_STRING, \ { .str = default__ }, \ .min = 0, \ .max = 0, \ .flags = AV_OPT_FLAG_DECODING_PARAM static const AVOption ffp_context_options[] = { // original options in ffplay.c // FFP_MERGE: x, y, s, fs { "an", "disable audio", OPTION_OFFSET(audio_disable), OPTION_INT(0, 0, 1) }, { "vn", "disable video", OPTION_OFFSET(video_disable), OPTION_INT(0, 0, 1) }, // FFP_MERGE: sn, ast, vst, sst // TODO: ss { "nodisp", "disable graphical display", OPTION_OFFSET(display_disable), OPTION_INT(0, 0, 1) }, { "volume", "set startup volume 0=min 100=max", OPTION_OFFSET(startup_volume), OPTION_INT(100, 0, 100) }, // FFP_MERGE: f, pix_fmt, stats { "fast", "non spec compliant optimizations", OPTION_OFFSET(fast), OPTION_INT(0, 0, 1) }, // FFP_MERGE: genpts, drp, lowres, sync, autoexit, exitonkeydown, exitonmousedown { "loop", "set number of times the playback shall be looped", OPTION_OFFSET(loop), OPTION_INT(1, INT_MIN, INT_MAX) }, { "infbuf", "don't limit the input buffer size (useful with realtime streams)", OPTION_OFFSET(infinite_buffer), OPTION_INT(0, 0, 1) }, { "framedrop", "drop frames when cpu is too slow", OPTION_OFFSET(framedrop), OPTION_INT(0, -1, 120) }, { "seek-at-start", "set offset of player should be seeked", OPTION_OFFSET(seek_at_start), OPTION_INT64(0, 0, INT_MAX) }, { "subtitle", "decode subtitle stream", OPTION_OFFSET(subtitle), OPTION_INT(0, 0, 1) }, // FFP_MERGE: window_title #if CONFIG_AVFILTER { "af", "audio filters", OPTION_OFFSET(afilters), OPTION_STR(NULL) }, { "vf0", "video filters 0", OPTION_OFFSET(vfilter0), OPTION_STR(NULL) }, #endif { "rdftspeed", "rdft speed, in msecs", OPTION_OFFSET(rdftspeed), OPTION_INT(0, 0, INT_MAX) }, // FFP_MERGE: showmode, default, i, codec, acodec, scodec, vcodec // TODO: autorotate { "find_stream_info", "read and decode the streams to fill missing information with heuristics" , OPTION_OFFSET(find_stream_info), OPTION_INT(1, 0, 1) }, // extended options in ff_ffplay.c { "max-fps", "drop frames in video whose fps is greater than max-fps", OPTION_OFFSET(max_fps), OPTION_INT(31, -1, 121) }, { "overlay-format", "fourcc of overlay format", OPTION_OFFSET(overlay_format), OPTION_INT(SDL_FCC_RV32, INT_MIN, INT_MAX), .unit = "overlay-format" }, { "fcc-_es2", "", 0, OPTION_CONST(SDL_FCC__GLES2), .unit = "overlay-format" }, { "fcc-i420", "", 0, OPTION_CONST(SDL_FCC_I420), .unit = "overlay-format" }, { "fcc-yv12", "", 0, OPTION_CONST(SDL_FCC_YV12), .unit = "overlay-format" }, { "fcc-rv16", "", 0, OPTION_CONST(SDL_FCC_RV16), .unit = "overlay-format" }, { "fcc-rv24", "", 0, OPTION_CONST(SDL_FCC_RV24), .unit = "overlay-format" }, { "fcc-rv32", "", 0, OPTION_CONST(SDL_FCC_RV32), .unit = "overlay-format" }, { "start-on-prepared", "automatically start playing on prepared", OPTION_OFFSET(start_on_prepared), OPTION_INT(1, 0, 1) }, { "video-pictq-size", "max picture queue frame count", OPTION_OFFSET(pictq_size), OPTION_INT(VIDEO_PICTURE_QUEUE_SIZE_DEFAULT, VIDEO_PICTURE_QUEUE_SIZE_MIN, VIDEO_PICTURE_QUEUE_SIZE_MAX) }, { "max-buffer-size", "max buffer size should be pre-read", OPTION_OFFSET(dcc.max_buffer_size), OPTION_INT(MAX_QUEUE_SIZE, 0, MAX_QUEUE_SIZE) }, { "min-frames", "minimal frames to stop pre-reading", OPTION_OFFSET(dcc.min_frames), OPTION_INT(DEFAULT_MIN_FRAMES, MIN_MIN_FRAMES, MAX_MIN_FRAMES) }, { "first-high-water-mark-ms", "first chance to wakeup read_thread", OPTION_OFFSET(dcc.first_high_water_mark_in_ms), OPTION_INT(DEFAULT_FIRST_HIGH_WATER_MARK_IN_MS, DEFAULT_FIRST_HIGH_WATER_MARK_IN_MS, DEFAULT_LAST_HIGH_WATER_MARK_IN_MS) }, { "next-high-water-mark-ms", "second chance to wakeup read_thread", OPTION_OFFSET(dcc.next_high_water_mark_in_ms), OPTION_INT(DEFAULT_NEXT_HIGH_WATER_MARK_IN_MS, DEFAULT_FIRST_HIGH_WATER_MARK_IN_MS, DEFAULT_LAST_HIGH_WATER_MARK_IN_MS) }, { "last-high-water-mark-ms", "last chance to wakeup read_thread", OPTION_OFFSET(dcc.last_high_water_mark_in_ms), OPTION_INT(DEFAULT_LAST_HIGH_WATER_MARK_IN_MS, DEFAULT_FIRST_HIGH_WATER_MARK_IN_MS, DEFAULT_LAST_HIGH_WATER_MARK_IN_MS) }, { "packet-buffering", "pause output until enough packets have been read after stalling", OPTION_OFFSET(packet_buffering), OPTION_INT(1, 0, 1) }, { "sync-av-start", "synchronise a/v start time", OPTION_OFFSET(sync_av_start), OPTION_INT(1, 0, 1) }, { "iformat", "force format", OPTION_OFFSET(iformat_name), OPTION_STR(NULL) }, { "no-time-adjust", "return player's real time from the media stream instead of the adjusted time", OPTION_OFFSET(no_time_adjust), OPTION_INT(0, 0, 1) }, { "preset-5-1-center-mix-level", "preset center-mix-level for 5.1 channel", OPTION_OFFSET(preset_5_1_center_mix_level), OPTION_DOUBLE(M_SQRT1_2, -32, 32) }, { "enable-accurate-seek", "enable accurate seek", OPTION_OFFSET(enable_accurate_seek), OPTION_INT(0, 0, 1) }, { "accurate-seek-timeout", "accurate seek timeout", OPTION_OFFSET(accurate_seek_timeout), OPTION_INT(MAX_ACCURATE_SEEK_TIMEOUT, 0, MAX_ACCURATE_SEEK_TIMEOUT) }, { "skip-calc-frame-rate", "don't calculate real frame rate", OPTION_OFFSET(skip_calc_frame_rate), OPTION_INT(0, 0, 1) }, { "get-frame-mode", "warning, this option only for get frame", OPTION_OFFSET(get_frame_mode), OPTION_INT(0, 0, 1) }, { "async-init-decoder", "async create decoder", OPTION_OFFSET(async_init_decoder), OPTION_INT(0, 0, 1) }, { "video-mime-type", "default video mime type", OPTION_OFFSET(video_mime_type), OPTION_STR(NULL) }, // iOS only options { "videotoolbox", "VideoToolbox: enable", OPTION_OFFSET(videotoolbox), OPTION_INT(0, 0, 1) }, { "videotoolbox-max-frame-width", "VideoToolbox: max width of output frame", OPTION_OFFSET(vtb_max_frame_width), OPTION_INT(0, 0, INT_MAX) }, { "videotoolbox-async", "VideoToolbox: use kVTDecodeFrame_EnableAsynchronousDecompression()", OPTION_OFFSET(vtb_async), OPTION_INT(0, 0, 1) }, { "videotoolbox-wait-async", "VideoToolbox: call VTDecompressionSessionWaitForAsynchronousFrames()", OPTION_OFFSET(vtb_wait_async), OPTION_INT(1, 0, 1) }, { "videotoolbox-handle-resolution-change", "VideoToolbox: handle resolution change automatically", 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-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) }, { "mediacodec-sync", "mediacodec: use msg_queue for synchronise", OPTION_OFFSET(mediacodec_sync), OPTION_INT(0, 0, 1) }, { "mediacodec-default-name", "mediacodec default name", OPTION_OFFSET(mediacodec_default_name), OPTION_STR(NULL) }, { "ijkmeta-delay-init", "ijkmeta delay init", OPTION_OFFSET(ijkmeta_delay_init), OPTION_INT(0, 0, 1) }, { "render-wait-start", "render wait start", OPTION_OFFSET(render_wait_start), OPTION_INT(0, 0, 1) }, { NULL } }; #undef OPTION_STR #undef OPTION_CONST #undef OPTION_INT #undef OPTION_OFFSET #endif ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/allformats.c ================================================ /* * Copyright (c) 2003 Bilibili * Copyright (c) 2003 Fabrice Bellard * Copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * Based on libavformat/allformats.c * * FFmpeg 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. * * FFmpeg 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 FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libavformat/avformat.h" #include "libavformat/url.h" #include "libavformat/version.h" #define IJK_REGISTER_DEMUXER(x) \ { \ extern AVInputFormat ijkff_##x##_demuxer; \ int ijkav_register_##x##_demuxer(AVInputFormat *demuxer, int demuxer_size); \ ijkav_register_##x##_demuxer(&ijkff_##x##_demuxer, sizeof(AVInputFormat)); \ } #define IJK_REGISTER_PROTOCOL(x) \ { \ extern URLProtocol ijkimp_ff_##x##_protocol; \ int ijkav_register_##x##_protocol(URLProtocol *protocol, int protocol_size);\ ijkav_register_##x##_protocol(&ijkimp_ff_##x##_protocol, sizeof(URLProtocol)); \ } static struct AVInputFormat *ijkav_find_input_format(const char *iformat_name) { AVInputFormat *fmt = NULL; if (!iformat_name) return NULL; while ((fmt = av_iformat_next(fmt))) { if (!fmt->name) continue; if (!strcmp(iformat_name, fmt->name)) return fmt; } return NULL; } static void ijkav_register_input_format(AVInputFormat *iformat) { if (ijkav_find_input_format(iformat->name)) { av_log(NULL, AV_LOG_WARNING, "skip demuxer : %s (duplicated)\n", iformat->name); } else { av_log(NULL, AV_LOG_INFO, "register demuxer : %s\n", iformat->name); av_register_input_format(iformat); } } void ijkav_register_all(void) { static int initialized; if (initialized) return; initialized = 1; av_register_all(); /* protocols */ av_log(NULL, AV_LOG_INFO, "===== custom modules begin =====\n"); #ifdef __ANDROID__ IJK_REGISTER_PROTOCOL(ijkmediadatasource); #endif IJK_REGISTER_PROTOCOL(ijkio); IJK_REGISTER_PROTOCOL(async); IJK_REGISTER_PROTOCOL(ijklongurl); IJK_REGISTER_PROTOCOL(ijktcphook); IJK_REGISTER_PROTOCOL(ijkhttphook); IJK_REGISTER_PROTOCOL(ijksegment); /* demuxers */ IJK_REGISTER_DEMUXER(ijklivehook); IJK_REGISTER_DEMUXER(ijklas); av_log(NULL, AV_LOG_INFO, "===== custom modules end =====\n"); } ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/cJSON.c ================================================ /* Copyright (c) 2009-2017 Dave Gamble and cJSON contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* cJSON */ /* JSON parser in C. */ /* disable warnings about old C89 functions in MSVC */ #if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) #define _CRT_SECURE_NO_DEPRECATE #endif #ifdef __GNUC__ #pragma GCC visibility push(default) #endif #if defined(_MSC_VER) #pragma warning (push) /* disable warning about single line comments in system headers */ #pragma warning (disable : 4001) #endif #include #include #include #include #include #include #include #ifdef ENABLE_LOCALES #include #endif #if defined(_MSC_VER) #pragma warning (pop) #endif #ifdef __GNUC__ #pragma GCC visibility pop #endif #include "cJSON.h" /* define our own boolean type */ #define true ((cJSON_bool)1) #define false ((cJSON_bool)0) typedef struct { const unsigned char *json; size_t position; } error; static error global_error = { NULL, 0 }; CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) { return (const char*) (global_error.json + global_error.position); } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 6) || (CJSON_VERSION_PATCH != 0) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif CJSON_PUBLIC(const char*) cJSON_Version(void) { static char version[15]; sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); return version; } /* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) { if ((string1 == NULL) || (string2 == NULL)) { return 1; } if (string1 == string2) { return 0; } for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) { if (*string1 == '\0') { return 0; } } return tolower(*string1) - tolower(*string2); } typedef struct internal_hooks { void *(*allocate)(size_t size); void (*deallocate)(void *pointer); void *(*reallocate)(void *pointer, size_t size); } internal_hooks; #if defined(_MSC_VER) /* work around MSVC error C2322: '...' address of dillimport '...' is not static */ static void *internal_malloc(size_t size) { return malloc(size); } static void internal_free(void *pointer) { free(pointer); } static void *internal_realloc(void *pointer, size_t size) { return realloc(pointer, size); } #else #define internal_malloc malloc #define internal_free free #define internal_realloc realloc #endif static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) { size_t length = 0; unsigned char *copy = NULL; if (string == NULL) { return NULL; } length = strlen((const char*)string) + sizeof(""); copy = (unsigned char*)hooks->allocate(length); if (copy == NULL) { return NULL; } memcpy(copy, string, length); return copy; } CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) { if (hooks == NULL) { /* Reset hooks */ global_hooks.allocate = malloc; global_hooks.deallocate = free; global_hooks.reallocate = realloc; return; } global_hooks.allocate = malloc; if (hooks->malloc_fn != NULL) { global_hooks.allocate = hooks->malloc_fn; } global_hooks.deallocate = free; if (hooks->free_fn != NULL) { global_hooks.deallocate = hooks->free_fn; } /* use realloc only if both free and malloc are used */ global_hooks.reallocate = NULL; if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) { global_hooks.reallocate = realloc; } } /* Internal constructor. */ static cJSON *cJSON_New_Item(const internal_hooks * const hooks) { cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); if (node) { memset(node, '\0', sizeof(cJSON)); } return node; } /* Delete a cJSON structure. */ CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) { cJSON *next = NULL; while (item != NULL) { next = item->next; if (!(item->type & cJSON_IsReference) && (item->child != NULL)) { cJSON_Delete(item->child); } if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) { global_hooks.deallocate(item->valuestring); } if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { global_hooks.deallocate(item->string); } global_hooks.deallocate(item); item = next; } } /* get the decimal point character of the current locale */ static unsigned char get_decimal_point(void) { #ifdef ENABLE_LOCALES struct lconv *lconv = localeconv(); return (unsigned char) lconv->decimal_point[0]; #else return '.'; #endif } typedef struct { const unsigned char *content; size_t length; size_t offset; size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ internal_hooks hooks; } parse_buffer; /* check if the given size is left to read in a given parse buffer (starting with 1) */ #define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) /* check if the buffer can be accessed at the given index (starting with 0) */ #define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) #define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) /* get a pointer to the buffer at the position */ #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) /* Parse the input text to generate a number, and populate the result into item. */ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) { double number = 0; unsigned char *after_end = NULL; unsigned char number_c_string[64]; unsigned char decimal_point = get_decimal_point(); size_t i = 0; if ((input_buffer == NULL) || (input_buffer->content == NULL)) { return false; } /* copy the number into a temporary buffer and replace '.' with the decimal point * of the current locale (for strtod) * This also takes care of '\0' not necessarily being available for marking the end of the input */ for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) { switch (buffer_at_offset(input_buffer)[i]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '+': case '-': case 'e': case 'E': number_c_string[i] = buffer_at_offset(input_buffer)[i]; break; case '.': number_c_string[i] = decimal_point; break; default: goto loop_end; } } loop_end: number_c_string[i] = '\0'; number = strtod((const char*)number_c_string, (char**)&after_end); if (number_c_string == after_end) { return false; /* parse_error */ } item->valuedouble = number; /* use saturation in case of overflow */ if (number >= INT_MAX) { item->valueint = INT_MAX; } else if (number <= INT_MIN) { item->valueint = INT_MIN; } else { item->valueint = (int)number; } item->type = cJSON_Number; input_buffer->offset += (size_t)(after_end - number_c_string); return true; } /* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) { if (number >= INT_MAX) { object->valueint = INT_MAX; } else if (number <= INT_MIN) { object->valueint = INT_MIN; } else { object->valueint = (int)number; } return object->valuedouble = number; } typedef struct { unsigned char *buffer; size_t length; size_t offset; size_t depth; /* current nesting depth (for formatted printing) */ cJSON_bool noalloc; cJSON_bool format; /* is this print a formatted print */ internal_hooks hooks; } printbuffer; /* realloc printbuffer if necessary to have at least "needed" bytes more */ static unsigned char* ensure(printbuffer * const p, size_t needed) { unsigned char *newbuffer = NULL; size_t newsize = 0; if ((p == NULL) || (p->buffer == NULL)) { return NULL; } if ((p->length > 0) && (p->offset >= p->length)) { /* make sure that offset is valid */ return NULL; } if (needed > INT_MAX) { /* sizes bigger than INT_MAX are currently not supported */ return NULL; } needed += p->offset + 1; if (needed <= p->length) { return p->buffer + p->offset; } if (p->noalloc) { return NULL; } /* calculate new buffer size */ if (needed > (INT_MAX / 2)) { /* overflow of int, use INT_MAX if possible */ if (needed <= INT_MAX) { newsize = INT_MAX; } else { return NULL; } } else { newsize = needed * 2; } if (p->hooks.reallocate != NULL) { /* reallocate with realloc if available */ newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); if (newbuffer == NULL) { p->hooks.deallocate(p->buffer); p->length = 0; p->buffer = NULL; return NULL; } } else { /* otherwise reallocate manually */ newbuffer = (unsigned char*)p->hooks.allocate(newsize); if (!newbuffer) { p->hooks.deallocate(p->buffer); p->length = 0; p->buffer = NULL; return NULL; } if (newbuffer) { memcpy(newbuffer, p->buffer, p->offset + 1); } p->hooks.deallocate(p->buffer); } p->length = newsize; p->buffer = newbuffer; return newbuffer + p->offset; } /* calculate the new length of the string in a printbuffer and update the offset */ static void update_offset(printbuffer * const buffer) { const unsigned char *buffer_pointer = NULL; if ((buffer == NULL) || (buffer->buffer == NULL)) { return; } buffer_pointer = buffer->buffer + buffer->offset; buffer->offset += strlen((const char*)buffer_pointer); } /* Render the number nicely from the given item into a string. */ static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) { unsigned char *output_pointer = NULL; double d = item->valuedouble; int length = 0; size_t i = 0; unsigned char number_buffer[26]; /* temporary buffer to print the number into */ unsigned char decimal_point = get_decimal_point(); double test; if (output_buffer == NULL) { return false; } /* This checks for NaN and Infinity */ if ((d * 0) != 0) { length = sprintf((char*)number_buffer, "null"); } else { /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ length = sprintf((char*)number_buffer, "%1.15g", d); /* Check whether the original double can be recovered */ if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d)) { /* If not, print with 17 decimal places of precision */ length = sprintf((char*)number_buffer, "%1.17g", d); } } /* sprintf failed or buffer overrun occured */ if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) { return false; } /* reserve appropriate space in the output */ output_pointer = ensure(output_buffer, (size_t)length); if (output_pointer == NULL) { return false; } /* copy the printed number to the output and replace locale * dependent decimal point with '.' */ for (i = 0; i < ((size_t)length); i++) { if (number_buffer[i] == decimal_point) { output_pointer[i] = '.'; continue; } output_pointer[i] = number_buffer[i]; } output_pointer[i] = '\0'; output_buffer->offset += (size_t)length; return true; } /* parse 4 digit hexadecimal number */ static unsigned parse_hex4(const unsigned char * const input) { unsigned int h = 0; size_t i = 0; for (i = 0; i < 4; i++) { /* parse digit */ if ((input[i] >= '0') && (input[i] <= '9')) { h += (unsigned int) input[i] - '0'; } else if ((input[i] >= 'A') && (input[i] <= 'F')) { h += (unsigned int) 10 + input[i] - 'A'; } else if ((input[i] >= 'a') && (input[i] <= 'f')) { h += (unsigned int) 10 + input[i] - 'a'; } else /* invalid */ { return 0; } if (i < 3) { /* shift left to make place for the next nibble */ h = h << 4; } } return h; } /* converts a UTF-16 literal to UTF-8 * A literal can be one or two sequences of the form \uXXXX */ static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) { long unsigned int codepoint = 0; unsigned int first_code = 0; const unsigned char *first_sequence = input_pointer; unsigned char utf8_length = 0; unsigned char utf8_position = 0; unsigned char sequence_length = 0; unsigned char first_byte_mark = 0; if ((input_end - first_sequence) < 6) { /* input ends unexpectedly */ goto fail; } /* get the first utf16 sequence */ first_code = parse_hex4(first_sequence + 2); /* check that the code is valid */ if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) { goto fail; } /* UTF16 surrogate pair */ if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) { const unsigned char *second_sequence = first_sequence + 6; unsigned int second_code = 0; sequence_length = 12; /* \uXXXX\uXXXX */ if ((input_end - second_sequence) < 6) { /* input ends unexpectedly */ goto fail; } if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) { /* missing second half of the surrogate pair */ goto fail; } /* get the second utf16 sequence */ second_code = parse_hex4(second_sequence + 2); /* check that the code is valid */ if ((second_code < 0xDC00) || (second_code > 0xDFFF)) { /* invalid second half of the surrogate pair */ goto fail; } /* calculate the unicode codepoint from the surrogate pair */ codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); } else { sequence_length = 6; /* \uXXXX */ codepoint = first_code; } /* encode as UTF-8 * takes at maximum 4 bytes to encode: * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ if (codepoint < 0x80) { /* normal ascii, encoding 0xxxxxxx */ utf8_length = 1; } else if (codepoint < 0x800) { /* two bytes, encoding 110xxxxx 10xxxxxx */ utf8_length = 2; first_byte_mark = 0xC0; /* 11000000 */ } else if (codepoint < 0x10000) { /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ utf8_length = 3; first_byte_mark = 0xE0; /* 11100000 */ } else if (codepoint <= 0x10FFFF) { /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ utf8_length = 4; first_byte_mark = 0xF0; /* 11110000 */ } else { /* invalid unicode codepoint */ goto fail; } /* encode as utf8 */ for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) { /* 10xxxxxx */ (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); codepoint >>= 6; } /* encode first byte */ if (utf8_length > 1) { (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); } else { (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); } *output_pointer += utf8_length; return sequence_length; fail: return 0; } /* Parse the input text into an unescaped cinput, and populate item. */ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) { const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; unsigned char *output_pointer = NULL; unsigned char *output = NULL; /* not a string */ if (buffer_at_offset(input_buffer)[0] != '\"') { goto fail; } { /* calculate approximate size of the output (overestimate) */ size_t allocation_length = 0; size_t skipped_bytes = 0; while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) { /* is escape sequence */ if (input_end[0] == '\\') { if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) { /* prevent buffer overflow when last input character is a backslash */ goto fail; } skipped_bytes++; input_end++; } input_end++; } if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) { goto fail; /* string ended unexpectedly */ } /* This is at most how much we need for the output */ allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); if (output == NULL) { goto fail; /* allocation failure */ } } output_pointer = output; /* loop through the string literal */ while (input_pointer < input_end) { if (*input_pointer != '\\') { *output_pointer++ = *input_pointer++; } /* escape sequence */ else { unsigned char sequence_length = 2; if ((input_end - input_pointer) < 1) { goto fail; } switch (input_pointer[1]) { case 'b': *output_pointer++ = '\b'; break; case 'f': *output_pointer++ = '\f'; break; case 'n': *output_pointer++ = '\n'; break; case 'r': *output_pointer++ = '\r'; break; case 't': *output_pointer++ = '\t'; break; case '\"': case '\\': case '/': *output_pointer++ = input_pointer[1]; break; /* UTF-16 literal */ case 'u': sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); if (sequence_length == 0) { /* failed to convert UTF16-literal to UTF-8 */ goto fail; } break; default: goto fail; } input_pointer += sequence_length; } } /* zero terminate the output */ *output_pointer = '\0'; item->type = cJSON_String; item->valuestring = (char*)output; input_buffer->offset = (size_t) (input_end - input_buffer->content); input_buffer->offset++; return true; fail: if (output != NULL) { input_buffer->hooks.deallocate(output); } if (input_pointer != NULL) { input_buffer->offset = (size_t)(input_pointer - input_buffer->content); } return false; } /* Render the cstring provided to an escaped version that can be printed. */ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) { const unsigned char *input_pointer = NULL; unsigned char *output = NULL; unsigned char *output_pointer = NULL; size_t output_length = 0; /* numbers of additional characters needed for escaping */ size_t escape_characters = 0; if (output_buffer == NULL) { return false; } /* empty string */ if (input == NULL) { output = ensure(output_buffer, sizeof("\"\"")); if (output == NULL) { return false; } strcpy((char*)output, "\"\""); return true; } /* set "flag" to 1 if something needs to be escaped */ for (input_pointer = input; *input_pointer; input_pointer++) { switch (*input_pointer) { case '\"': case '\\': case '\b': case '\f': case '\n': case '\r': case '\t': /* one character escape sequence */ escape_characters++; break; default: if (*input_pointer < 32) { /* UTF-16 escape sequence uXXXX */ escape_characters += 5; } break; } } output_length = (size_t)(input_pointer - input) + escape_characters; output = ensure(output_buffer, output_length + sizeof("\"\"")); if (output == NULL) { return false; } /* no characters have to be escaped */ if (escape_characters == 0) { output[0] = '\"'; memcpy(output + 1, input, output_length); output[output_length + 1] = '\"'; output[output_length + 2] = '\0'; return true; } output[0] = '\"'; output_pointer = output + 1; /* copy the string */ for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) { if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) { /* normal character, copy */ *output_pointer = *input_pointer; } else { /* character needs to be escaped */ *output_pointer++ = '\\'; switch (*input_pointer) { case '\\': *output_pointer = '\\'; break; case '\"': *output_pointer = '\"'; break; case '\b': *output_pointer = 'b'; break; case '\f': *output_pointer = 'f'; break; case '\n': *output_pointer = 'n'; break; case '\r': *output_pointer = 'r'; break; case '\t': *output_pointer = 't'; break; default: /* escape and print as unicode codepoint */ sprintf((char*)output_pointer, "u%04x", *input_pointer); output_pointer += 4; break; } } } output[output_length + 1] = '\"'; output[output_length + 2] = '\0'; return true; } /* Invoke print_string_ptr (which is useful) on an item. */ static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) { return print_string_ptr((unsigned char*)item->valuestring, p); } /* Predeclare these prototypes. */ static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); /* Utility to jump whitespace and cr/lf */ static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) { if ((buffer == NULL) || (buffer->content == NULL)) { return NULL; } while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) { buffer->offset++; } if (buffer->offset == buffer->length) { buffer->offset--; } return buffer; } /* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) { if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) { return NULL; } if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) { buffer->offset += 3; } return buffer; } /* Parse an object - create a new root, and populate. */ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) { parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; cJSON *item = NULL; /* reset error position */ global_error.json = NULL; global_error.position = 0; if (value == NULL) { goto fail; } buffer.content = (const unsigned char*)value; buffer.length = strlen((const char*)value) + sizeof(""); buffer.offset = 0; buffer.hooks = global_hooks; item = cJSON_New_Item(&global_hooks); if (item == NULL) /* memory fail */ { goto fail; } if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) { /* parse failure. ep is set. */ goto fail; } /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ if (require_null_terminated) { buffer_skip_whitespace(&buffer); if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') { goto fail; } } if (return_parse_end) { *return_parse_end = (const char*)buffer_at_offset(&buffer); } return item; fail: if (item != NULL) { cJSON_Delete(item); } if (value != NULL) { error local_error; local_error.json = (const unsigned char*)value; local_error.position = 0; if (buffer.offset < buffer.length) { local_error.position = buffer.offset; } else if (buffer.length > 0) { local_error.position = buffer.length - 1; } if (return_parse_end != NULL) { *return_parse_end = (const char*)local_error.json + local_error.position; } global_error = local_error; } return NULL; } /* Default options for cJSON_Parse */ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) { return cJSON_ParseWithOpts(value, 0, 0); } #define cjson_min(a, b) ((a < b) ? a : b) static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) { printbuffer buffer[1]; unsigned char *printed = NULL; memset(buffer, 0, sizeof(buffer)); /* create buffer */ buffer->buffer = (unsigned char*) hooks->allocate(256); buffer->format = format; buffer->hooks = *hooks; if (buffer->buffer == NULL) { goto fail; } /* print the value */ if (!print_value(item, buffer)) { goto fail; } update_offset(buffer); /* check if reallocate is available */ if (hooks->reallocate != NULL) { printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->length); buffer->buffer = NULL; if (printed == NULL) { goto fail; } } else /* otherwise copy the JSON over to a new buffer */ { printed = (unsigned char*) hooks->allocate(buffer->offset + 1); if (printed == NULL) { goto fail; } memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); printed[buffer->offset] = '\0'; /* just to be sure */ /* free the buffer */ hooks->deallocate(buffer->buffer); } return printed; fail: if (buffer->buffer != NULL) { hooks->deallocate(buffer->buffer); } if (printed != NULL) { hooks->deallocate(printed); } return NULL; } /* Render a cJSON item/entity/structure to text. */ CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) { return (char*)print(item, true, &global_hooks); } CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) { return (char*)print(item, false, &global_hooks); } CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) { printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; if (prebuffer < 0) { return NULL; } p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); if (!p.buffer) { return NULL; } p.length = (size_t)prebuffer; p.offset = 0; p.noalloc = false; p.format = fmt; p.hooks = global_hooks; if (!print_value(item, &p)) { global_hooks.deallocate(p.buffer); return NULL; } return (char*)p.buffer; } CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt) { printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; if ((len < 0) || (buf == NULL)) { return false; } p.buffer = (unsigned char*)buf; p.length = (size_t)len; p.offset = 0; p.noalloc = true; p.format = fmt; p.hooks = global_hooks; return print_value(item, &p); } /* Parser core - when encountering text, process appropriately. */ static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) { if ((input_buffer == NULL) || (input_buffer->content == NULL)) { return false; /* no input */ } /* parse the different types of values */ /* null */ if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) { item->type = cJSON_NULL; input_buffer->offset += 4; return true; } /* false */ if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) { item->type = cJSON_False; input_buffer->offset += 5; return true; } /* true */ if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) { item->type = cJSON_True; item->valueint = 1; input_buffer->offset += 4; return true; } /* string */ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) { return parse_string(item, input_buffer); } /* number */ if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) { return parse_number(item, input_buffer); } /* array */ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) { return parse_array(item, input_buffer); } /* object */ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) { return parse_object(item, input_buffer); } return false; } /* Render a value to text. */ static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) { unsigned char *output = NULL; if ((item == NULL) || (output_buffer == NULL)) { return false; } switch ((item->type) & 0xFF) { case cJSON_NULL: output = ensure(output_buffer, 5); if (output == NULL) { return false; } strcpy((char*)output, "null"); return true; case cJSON_False: output = ensure(output_buffer, 6); if (output == NULL) { return false; } strcpy((char*)output, "false"); return true; case cJSON_True: output = ensure(output_buffer, 5); if (output == NULL) { return false; } strcpy((char*)output, "true"); return true; case cJSON_Number: return print_number(item, output_buffer); case cJSON_Raw: { size_t raw_length = 0; if (item->valuestring == NULL) { if (!output_buffer->noalloc) { output_buffer->hooks.deallocate(output_buffer->buffer); } return false; } raw_length = strlen(item->valuestring) + sizeof(""); output = ensure(output_buffer, raw_length); if (output == NULL) { return false; } memcpy(output, item->valuestring, raw_length); return true; } case cJSON_String: return print_string(item, output_buffer); case cJSON_Array: return print_array(item, output_buffer); case cJSON_Object: return print_object(item, output_buffer); default: return false; } } /* Build an array from input text. */ static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) { cJSON *head = NULL; /* head of the linked list */ cJSON *current_item = NULL; if (input_buffer->depth >= CJSON_NESTING_LIMIT) { return false; /* to deeply nested */ } input_buffer->depth++; if (buffer_at_offset(input_buffer)[0] != '[') { /* not an array */ goto fail; } input_buffer->offset++; buffer_skip_whitespace(input_buffer); if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) { /* empty array */ goto success; } /* check if we skipped to the end of the buffer */ if (cannot_access_at_index(input_buffer, 0)) { input_buffer->offset--; goto fail; } /* step back to character in front of the first element */ input_buffer->offset--; /* loop through the comma separated array elements */ do { /* allocate next item */ cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); if (new_item == NULL) { goto fail; /* allocation failure */ } /* attach next item to list */ if (head == NULL) { /* start the linked list */ current_item = head = new_item; } else { /* add to the end and advance */ current_item->next = new_item; new_item->prev = current_item; current_item = new_item; } /* parse next value */ input_buffer->offset++; buffer_skip_whitespace(input_buffer); if (!parse_value(current_item, input_buffer)) { goto fail; /* failed to parse value */ } buffer_skip_whitespace(input_buffer); } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') { goto fail; /* expected end of array */ } success: input_buffer->depth--; item->type = cJSON_Array; item->child = head; input_buffer->offset++; return true; fail: if (head != NULL) { cJSON_Delete(head); } return false; } /* Render an array to text */ static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) { unsigned char *output_pointer = NULL; size_t length = 0; cJSON *current_element = item->child; if (output_buffer == NULL) { return false; } /* Compose the output array. */ /* opening square bracket */ output_pointer = ensure(output_buffer, 1); if (output_pointer == NULL) { return false; } *output_pointer = '['; output_buffer->offset++; output_buffer->depth++; while (current_element != NULL) { if (!print_value(current_element, output_buffer)) { return false; } update_offset(output_buffer); if (current_element->next) { length = (size_t) (output_buffer->format ? 2 : 1); output_pointer = ensure(output_buffer, length + 1); if (output_pointer == NULL) { return false; } *output_pointer++ = ','; if(output_buffer->format) { *output_pointer++ = ' '; } *output_pointer = '\0'; output_buffer->offset += length; } current_element = current_element->next; } output_pointer = ensure(output_buffer, 2); if (output_pointer == NULL) { return false; } *output_pointer++ = ']'; *output_pointer = '\0'; output_buffer->depth--; return true; } /* Build an object from the text. */ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) { cJSON *head = NULL; /* linked list head */ cJSON *current_item = NULL; if (input_buffer->depth >= CJSON_NESTING_LIMIT) { return false; /* to deeply nested */ } input_buffer->depth++; if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) { goto fail; /* not an object */ } input_buffer->offset++; buffer_skip_whitespace(input_buffer); if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) { goto success; /* empty object */ } /* check if we skipped to the end of the buffer */ if (cannot_access_at_index(input_buffer, 0)) { input_buffer->offset--; goto fail; } /* step back to character in front of the first element */ input_buffer->offset--; /* loop through the comma separated array elements */ do { /* allocate next item */ cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); if (new_item == NULL) { goto fail; /* allocation failure */ } /* attach next item to list */ if (head == NULL) { /* start the linked list */ current_item = head = new_item; } else { /* add to the end and advance */ current_item->next = new_item; new_item->prev = current_item; current_item = new_item; } /* parse the name of the child */ input_buffer->offset++; buffer_skip_whitespace(input_buffer); if (!parse_string(current_item, input_buffer)) { goto fail; /* faile to parse name */ } buffer_skip_whitespace(input_buffer); /* swap valuestring and string, because we parsed the name */ current_item->string = current_item->valuestring; current_item->valuestring = NULL; if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) { goto fail; /* invalid object */ } /* parse the value */ input_buffer->offset++; buffer_skip_whitespace(input_buffer); if (!parse_value(current_item, input_buffer)) { goto fail; /* failed to parse value */ } buffer_skip_whitespace(input_buffer); } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) { goto fail; /* expected end of object */ } success: input_buffer->depth--; item->type = cJSON_Object; item->child = head; input_buffer->offset++; return true; fail: if (head != NULL) { cJSON_Delete(head); } return false; } /* Render an object to text. */ static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) { unsigned char *output_pointer = NULL; size_t length = 0; cJSON *current_item = item->child; if (output_buffer == NULL) { return false; } /* Compose the output: */ length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ output_pointer = ensure(output_buffer, length + 1); if (output_pointer == NULL) { return false; } *output_pointer++ = '{'; output_buffer->depth++; if (output_buffer->format) { *output_pointer++ = '\n'; } output_buffer->offset += length; while (current_item) { if (output_buffer->format) { size_t i; output_pointer = ensure(output_buffer, output_buffer->depth); if (output_pointer == NULL) { return false; } for (i = 0; i < output_buffer->depth; i++) { *output_pointer++ = '\t'; } output_buffer->offset += output_buffer->depth; } /* print key */ if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) { return false; } update_offset(output_buffer); length = (size_t) (output_buffer->format ? 2 : 1); output_pointer = ensure(output_buffer, length); if (output_pointer == NULL) { return false; } *output_pointer++ = ':'; if (output_buffer->format) { *output_pointer++ = '\t'; } output_buffer->offset += length; /* print value */ if (!print_value(current_item, output_buffer)) { return false; } update_offset(output_buffer); /* print comma if not last */ length = (size_t) ((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0)); output_pointer = ensure(output_buffer, length + 1); if (output_pointer == NULL) { return false; } if (current_item->next) { *output_pointer++ = ','; } if (output_buffer->format) { *output_pointer++ = '\n'; } *output_pointer = '\0'; output_buffer->offset += length; current_item = current_item->next; } output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); if (output_pointer == NULL) { return false; } if (output_buffer->format) { size_t i; for (i = 0; i < (output_buffer->depth - 1); i++) { *output_pointer++ = '\t'; } } *output_pointer++ = '}'; *output_pointer = '\0'; output_buffer->depth--; return true; } /* Get Array size/item / object item. */ CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) { cJSON *child = NULL; size_t size = 0; if (array == NULL) { return 0; } child = array->child; while(child != NULL) { size++; child = child->next; } /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ return (int)size; } static cJSON* get_array_item(const cJSON *array, size_t index) { cJSON *current_child = NULL; if (array == NULL) { return NULL; } current_child = array->child; while ((current_child != NULL) && (index > 0)) { index--; current_child = current_child->next; } return current_child; } CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) { if (index < 0) { return NULL; } return get_array_item(array, (size_t)index); } static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) { cJSON *current_element = NULL; if ((object == NULL) || (name == NULL)) { return NULL; } current_element = object->child; if (case_sensitive) { while ((current_element != NULL) && (strcmp(name, current_element->string) != 0)) { current_element = current_element->next; } } else { while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) { current_element = current_element->next; } } return current_element; } CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) { return get_object_item(object, string, false); } CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) { return get_object_item(object, string, true); } CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) { return cJSON_GetObjectItem(object, string) ? 1 : 0; } /* Utility for array list handling. */ static void suffix_object(cJSON *prev, cJSON *item) { prev->next = item; item->prev = prev; } /* Utility for handling references. */ static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) { cJSON *reference = NULL; if (item == NULL) { return NULL; } reference = cJSON_New_Item(hooks); if (reference == NULL) { return NULL; } memcpy(reference, item, sizeof(cJSON)); reference->string = NULL; reference->type |= cJSON_IsReference; reference->next = reference->prev = NULL; return reference; } /* Add item to array/object. */ CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) { cJSON *child = NULL; if ((item == NULL) || (array == NULL)) { return; } child = array->child; if (child == NULL) { /* list is empty, start new one */ array->child = item; } else { /* append to the end */ while (child->next) { child = child->next; } suffix_object(child, item); } } CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) { if (item == NULL) { return; } /* call cJSON_AddItemToObjectCS for code reuse */ cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string, &global_hooks), item); /* remove cJSON_StringIsConst flag */ item->type &= ~cJSON_StringIsConst; } #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) #pragma GCC diagnostic push #endif #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wcast-qual" #endif /* Add an item to an object with constant string as key */ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) { if ((item == NULL) || (string == NULL)) { return; } if (!(item->type & cJSON_StringIsConst) && item->string) { global_hooks.deallocate(item->string); } item->string = (char*)string; item->type |= cJSON_StringIsConst; cJSON_AddItemToArray(object, item); } #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) #pragma GCC diagnostic pop #endif CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) { if (array == NULL) { return; } cJSON_AddItemToArray(array, create_reference(item, &global_hooks)); } CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) { if ((object == NULL) || (string == NULL)) { return; } cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks)); } CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) { if ((parent == NULL) || (item == NULL)) { return NULL; } if (item->prev != NULL) { /* not the first element */ item->prev->next = item->next; } if (item->next != NULL) { /* not the last element */ item->next->prev = item->prev; } if (item == parent->child) { /* first element */ parent->child = item->next; } /* make sure the detached item doesn't point anywhere anymore */ item->prev = NULL; item->next = NULL; return item; } CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) { if (which < 0) { return NULL; } return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); } CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) { cJSON_Delete(cJSON_DetachItemFromArray(array, which)); } CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) { cJSON *to_detach = cJSON_GetObjectItem(object, string); return cJSON_DetachItemViaPointer(object, to_detach); } CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) { cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); return cJSON_DetachItemViaPointer(object, to_detach); } CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) { cJSON_Delete(cJSON_DetachItemFromObject(object, string)); } CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) { cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); } /* Replace array/object items with new ones. */ CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) { cJSON *after_inserted = NULL; if (which < 0) { return; } after_inserted = get_array_item(array, (size_t)which); if (after_inserted == NULL) { cJSON_AddItemToArray(array, newitem); return; } newitem->next = after_inserted; newitem->prev = after_inserted->prev; after_inserted->prev = newitem; if (after_inserted == array->child) { array->child = newitem; } else { newitem->prev->next = newitem; } } CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) { if ((parent == NULL) || (replacement == NULL) || (item == NULL)) { return false; } if (replacement == item) { return true; } replacement->next = item->next; replacement->prev = item->prev; if (replacement->next != NULL) { replacement->next->prev = replacement; } if (replacement->prev != NULL) { replacement->prev->next = replacement; } if (parent->child == item) { parent->child = replacement; } item->next = NULL; item->prev = NULL; cJSON_Delete(item); return true; } CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) { if (which < 0) { return; } cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); } static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) { if ((replacement == NULL) || (string == NULL)) { return false; } /* replace the name in the replacement */ if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) { cJSON_free(replacement->string); } replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); replacement->type &= ~cJSON_StringIsConst; cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); return true; } CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) { replace_item_in_object(object, string, newitem, false); } CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) { replace_item_in_object(object, string, newitem, true); } /* Create basic types: */ CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) { item->type = cJSON_NULL; } return item; } CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) { item->type = cJSON_True; } return item; } CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) { item->type = cJSON_False; } return item; } CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) { item->type = b ? cJSON_True : cJSON_False; } return item; } CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) { item->type = cJSON_Number; item->valuedouble = num; /* use saturation in case of overflow */ if (num >= INT_MAX) { item->valueint = INT_MAX; } else if (num <= INT_MIN) { item->valueint = INT_MIN; } else { item->valueint = (int)num; } } return item; } CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) { item->type = cJSON_String; item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); if(!item->valuestring) { cJSON_Delete(item); return NULL; } } return item; } CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) { item->type = cJSON_Raw; item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); if(!item->valuestring) { cJSON_Delete(item); return NULL; } } return item; } CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) { item->type=cJSON_Array; } return item; } CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) { cJSON *item = cJSON_New_Item(&global_hooks); if (item) { item->type = cJSON_Object; } return item; } /* Create Arrays: */ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) { size_t i = 0; cJSON *n = NULL; cJSON *p = NULL; cJSON *a = NULL; if ((count < 0) || (numbers == NULL)) { return NULL; } a = cJSON_CreateArray(); for(i = 0; a && (i < (size_t)count); i++) { n = cJSON_CreateNumber(numbers[i]); if (!n) { cJSON_Delete(a); return NULL; } if(!i) { a->child = n; } else { suffix_object(p, n); } p = n; } return a; } CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) { size_t i = 0; cJSON *n = NULL; cJSON *p = NULL; cJSON *a = NULL; if ((count < 0) || (numbers == NULL)) { return NULL; } a = cJSON_CreateArray(); for(i = 0; a && (i < (size_t)count); i++) { n = cJSON_CreateNumber((double)numbers[i]); if(!n) { cJSON_Delete(a); return NULL; } if(!i) { a->child = n; } else { suffix_object(p, n); } p = n; } return a; } CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) { size_t i = 0; cJSON *n = NULL; cJSON *p = NULL; cJSON *a = NULL; if ((count < 0) || (numbers == NULL)) { return NULL; } a = cJSON_CreateArray(); for(i = 0;a && (i < (size_t)count); i++) { n = cJSON_CreateNumber(numbers[i]); if(!n) { cJSON_Delete(a); return NULL; } if(!i) { a->child = n; } else { suffix_object(p, n); } p = n; } return a; } CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) { size_t i = 0; cJSON *n = NULL; cJSON *p = NULL; cJSON *a = NULL; if ((count < 0) || (strings == NULL)) { return NULL; } a = cJSON_CreateArray(); for (i = 0; a && (i < (size_t)count); i++) { n = cJSON_CreateString(strings[i]); if(!n) { cJSON_Delete(a); return NULL; } if(!i) { a->child = n; } else { suffix_object(p,n); } p = n; } return a; } /* Duplication */ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) { cJSON *newitem = NULL; cJSON *child = NULL; cJSON *next = NULL; cJSON *newchild = NULL; /* Bail on bad ptr */ if (!item) { goto fail; } /* Create new item */ newitem = cJSON_New_Item(&global_hooks); if (!newitem) { goto fail; } /* Copy over all vars */ newitem->type = item->type & (~cJSON_IsReference); newitem->valueint = item->valueint; newitem->valuedouble = item->valuedouble; if (item->valuestring) { newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); if (!newitem->valuestring) { goto fail; } } if (item->string) { newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); if (!newitem->string) { goto fail; } } /* If non-recursive, then we're done! */ if (!recurse) { return newitem; } /* Walk the ->next chain for the child. */ child = item->child; while (child != NULL) { newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ if (!newchild) { goto fail; } if (next != NULL) { /* If newitem->child already set, then crosswire ->prev and ->next and move on */ next->next = newchild; newchild->prev = next; next = newchild; } else { /* Set newitem->child and move to it */ newitem->child = newchild; next = newchild; } child = child->next; } return newitem; fail: if (newitem != NULL) { cJSON_Delete(newitem); } return NULL; } CJSON_PUBLIC(void) cJSON_Minify(char *json) { unsigned char *into = (unsigned char*)json; if (json == NULL) { return; } while (*json) { if (*json == ' ') { json++; } else if (*json == '\t') { /* Whitespace characters. */ json++; } else if (*json == '\r') { json++; } else if (*json=='\n') { json++; } else if ((*json == '/') && (json[1] == '/')) { /* double-slash comments, to end of line. */ while (*json && (*json != '\n')) { json++; } } else if ((*json == '/') && (json[1] == '*')) { /* multiline comments. */ while (*json && !((*json == '*') && (json[1] == '/'))) { json++; } json += 2; } else if (*json == '\"') { /* string literals, which are \" sensitive. */ *into++ = (unsigned char)*json++; while (*json && (*json != '\"')) { if (*json == '\\') { *into++ = (unsigned char)*json++; } *into++ = (unsigned char)*json++; } *into++ = (unsigned char)*json++; } else { /* All other characters. */ *into++ = (unsigned char)*json++; } } /* and null-terminate. */ *into = '\0'; } CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) { if (item == NULL) { return false; } return (item->type & 0xFF) == cJSON_Invalid; } CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) { if (item == NULL) { return false; } return (item->type & 0xFF) == cJSON_False; } CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) { if (item == NULL) { return false; } return (item->type & 0xff) == cJSON_True; } CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) { if (item == NULL) { return false; } return (item->type & (cJSON_True | cJSON_False)) != 0; } CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) { if (item == NULL) { return false; } return (item->type & 0xFF) == cJSON_NULL; } CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) { if (item == NULL) { return false; } return (item->type & 0xFF) == cJSON_Number; } CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) { if (item == NULL) { return false; } return (item->type & 0xFF) == cJSON_String; } CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) { if (item == NULL) { return false; } return (item->type & 0xFF) == cJSON_Array; } CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) { if (item == NULL) { return false; } return (item->type & 0xFF) == cJSON_Object; } CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) { if (item == NULL) { return false; } return (item->type & 0xFF) == cJSON_Raw; } CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) { if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) { return false; } /* check if type is valid */ switch (a->type & 0xFF) { case cJSON_False: case cJSON_True: case cJSON_NULL: case cJSON_Number: case cJSON_String: case cJSON_Raw: case cJSON_Array: case cJSON_Object: break; default: return false; } /* identical objects are equal */ if (a == b) { return true; } switch (a->type & 0xFF) { /* in these cases and equal type is enough */ case cJSON_False: case cJSON_True: case cJSON_NULL: return true; case cJSON_Number: if (a->valuedouble == b->valuedouble) { return true; } return false; case cJSON_String: case cJSON_Raw: if ((a->valuestring == NULL) || (b->valuestring == NULL)) { return false; } if (strcmp(a->valuestring, b->valuestring) == 0) { return true; } return false; case cJSON_Array: { cJSON *a_element = a->child; cJSON *b_element = b->child; for (; (a_element != NULL) && (b_element != NULL);) { if (!cJSON_Compare(a_element, b_element, case_sensitive)) { return false; } a_element = a_element->next; b_element = b_element->next; } /* one of the arrays is longer than the other */ if (a_element != b_element) { return false; } return true; } case cJSON_Object: { cJSON *a_element = NULL; cJSON *b_element = NULL; cJSON_ArrayForEach(a_element, a) { /* TODO This has O(n^2) runtime, which is horrible! */ b_element = get_object_item(b, a_element->string, case_sensitive); if (b_element == NULL) { return false; } if (!cJSON_Compare(a_element, b_element, case_sensitive)) { return false; } } /* doing this twice, once on a and b to prevent true comparison if a subset of b * TODO: Do this the proper way, this is just a fix for now */ cJSON_ArrayForEach(b_element, b) { a_element = get_object_item(a, b_element->string, case_sensitive); if (a_element == NULL) { return false; } if (!cJSON_Compare(b_element, a_element, case_sensitive)) { return false; } } return true; } default: return false; } } CJSON_PUBLIC(void *) cJSON_malloc(size_t size) { return global_hooks.allocate(size); } CJSON_PUBLIC(void) cJSON_free(void *object) { global_hooks.deallocate(object); } ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/cJSON.h ================================================ /* Copyright (c) 2009-2017 Dave Gamble and cJSON contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef cJSON__h #define cJSON__h #ifdef __cplusplus extern "C" { #endif /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 6 #define CJSON_VERSION_PATCH 0 #include /* cJSON Types: */ #define cJSON_Invalid (0) #define cJSON_False (1 << 0) #define cJSON_True (1 << 1) #define cJSON_NULL (1 << 2) #define cJSON_Number (1 << 3) #define cJSON_String (1 << 4) #define cJSON_Array (1 << 5) #define cJSON_Object (1 << 6) #define cJSON_Raw (1 << 7) /* raw json */ #define cJSON_IsReference 256 #define cJSON_StringIsConst 512 /* The cJSON structure: */ typedef struct cJSON { /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ struct cJSON *next; struct cJSON *prev; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ struct cJSON *child; /* The type of the item, as above. */ int type; /* The item's string, if type==cJSON_String and type == cJSON_Raw */ char *valuestring; /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ int valueint; /* The item's number, if type==cJSON_Number */ double valuedouble; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ char *string; } cJSON; typedef struct cJSON_Hooks { void *(*malloc_fn)(size_t sz); void (*free_fn)(void *ptr); } cJSON_Hooks; typedef int cJSON_bool; #if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) #define __WINDOWS__ #endif #ifdef __WINDOWS__ /* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options: CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol For *nix builds that support visibility attribute, you can define similar behavior by setting default visibility to hidden by adding -fvisibility=hidden (for gcc) or -xldscope=hidden (for sun cc) to CFLAGS then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does */ /* export symbols by default, this is necessary for copy pasting the C and header file */ #if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) #define CJSON_EXPORT_SYMBOLS #endif #if defined(CJSON_HIDE_SYMBOLS) #define CJSON_PUBLIC(type) type __stdcall #elif defined(CJSON_EXPORT_SYMBOLS) #define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall #elif defined(CJSON_IMPORT_SYMBOLS) #define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall #endif #else /* !WIN32 */ #if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) #define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type #else #define CJSON_PUBLIC(type) type #endif #endif /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. * This is to prevent stack overflows. */ #ifndef CJSON_NESTING_LIMIT #define CJSON_NESTING_LIMIT 1000 #endif /* returns the version of cJSON as a string */ CJSON_PUBLIC(const char*) cJSON_Version(void); /* Supply malloc, realloc and free functions to cJSON */ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); /* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); /* Render a cJSON entity to text for transfer/storage. */ CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); /* Render a cJSON entity to text for transfer/storage without any formatting. */ CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); /* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ /* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); /* Delete a cJSON entity and all subentities. */ CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); /* Returns the number of items in an array (or object). */ CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); /* Get item "string" from object. Case insensitive. */ CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); /* These functions check the type of an item */ CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); /* These calls create a cJSON item of the appropriate type. */ CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); /* raw json */ CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); /* These utilities create an Array of count items. */ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count); /* Append item to the specified array/object. */ CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before * writing to `item->string` */ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); /* Remove/Detatch items from Arrays/Objects. */ CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); /* Update array items. */ CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); /* Duplicate a cJSON item */ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will need to be released. With recurse!=0, it will duplicate any children connected to the item. The item->next and ->prev pointers are always zero on return from Duplicate. */ /* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); CJSON_PUBLIC(void) cJSON_Minify(char *json); /* Macros for creating things quickly. */ #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) #define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) #define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s)) /* When assigning an integer value, it needs to be propagated to valuedouble too. */ #define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) /* helper for the cJSON_SetNumberValue macro */ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); #define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) /* Macro for iterating over an array or object */ #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) /* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ CJSON_PUBLIC(void *) cJSON_malloc(size_t size); CJSON_PUBLIC(void) cJSON_free(void *object); #ifdef __cplusplus } #endif #endif ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijkasync.c ================================================ /* * Input async protocol. * Copyright (c) 2015 Bilibili * Copyright (c) 2015 Zhang Rui * * This file is part of FFmpeg. * * FFmpeg 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. * * FFmpeg 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 FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Based on libavformat/cache.c by Michael Niedermayer */ /** * @TODO * support timeout * support work with concatdec, hls */ #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/error.h" #include "libavutil/fifo.h" #include "libavutil/log.h" #include "libavutil/opt.h" #include "libavutil/thread.h" #include "libavutil/time.h" #include "libavformat/url.h" #include #include "libavutil/application.h" #if HAVE_UNISTD_H #include #endif #define SHORT_SEEK_THRESHOLD (256 * 1024) typedef struct RingBuffer { AVFifoBuffer *fifo; int read_back_capacity; int read_pos; } RingBuffer; typedef struct Context { AVClass *class; URLContext *inner; int seek_request; int64_t seek_pos; int seek_whence; int seek_completed; int64_t seek_ret; int inner_io_error; int io_error; int io_eof_reached; int64_t logical_pos; int64_t logical_size; RingBuffer ring; pthread_cond_t cond_wakeup_main; pthread_cond_t cond_wakeup_background; pthread_mutex_t mutex; pthread_t async_buffer_thread; int abort_request; AVIOInterruptCB interrupt_callback; /* options */ int64_t forwards_capacity; int64_t backwards_capacity; char * app_ctx_intptr; AVApplicationContext *app_ctx; } Context; static int ring_init(RingBuffer *ring, int64_t capacity, int64_t read_back_capacity) { memset(ring, 0, sizeof(RingBuffer)); ring->fifo = av_fifo_alloc((unsigned int)(capacity + read_back_capacity)); if (!ring->fifo) return AVERROR(ENOMEM); ring->read_back_capacity = (int)read_back_capacity; return 0; } static void ring_destroy(RingBuffer *ring) { av_fifo_freep(&ring->fifo); } static void ring_reset(RingBuffer *ring) { av_fifo_reset(ring->fifo); ring->read_pos = 0; } static int ring_size(RingBuffer *ring) { return av_fifo_size(ring->fifo) - ring->read_pos; } static int ring_space(RingBuffer *ring) { return av_fifo_space(ring->fifo); } static int ring_generic_read(RingBuffer *ring, void *dest, int buf_size, void (*func)(void*, void*, int)) { int ret; av_assert2(buf_size <= ring_size(ring)); ret = av_fifo_generic_peek_at(ring->fifo, dest, ring->read_pos, buf_size, func); ring->read_pos += buf_size; if (ring->read_pos > ring->read_back_capacity) { av_fifo_drain(ring->fifo, ring->read_pos - ring->read_back_capacity); ring->read_pos = ring->read_back_capacity; } return ret; } static int ring_generic_write(RingBuffer *ring, void *src, int size, int (*func)(void*, void*, int)) { av_assert2(size <= ring_space(ring)); return av_fifo_generic_write(ring->fifo, src, size, func); } static int ring_size_of_read_back(RingBuffer *ring) { return ring->read_pos; } static int ring_drain(RingBuffer *ring, int offset) { av_assert2(offset >= -ring_size_of_read_back(ring)); av_assert2(offset <= -ring_size(ring)); ring->read_pos += offset; return 0; } static int async_check_interrupt(void *arg) { URLContext *h = arg; Context *c = h->priv_data; if (c->abort_request) return 1; if (ff_check_interrupt(&c->interrupt_callback)) c->abort_request = 1; return c->abort_request; } static int wrapped_url_read(void *src, void *dst, int size) { URLContext *h = src; Context *c = h->priv_data; int ret; ret = ffurl_read(c->inner, dst, size); c->inner_io_error = ret < 0 ? ret : 0; return ret; } static void call_inject_statistic(URLContext *h) { Context *c = h->priv_data; if (c->app_ctx) { AVAppAsyncStatistic statistic = {0}; statistic.size = sizeof(statistic); statistic.buf_forwards = ring_size(&c->ring); statistic.buf_backwards = ring_size_of_read_back(&c->ring); statistic.buf_capacity = c->forwards_capacity + c->backwards_capacity; av_application_on_async_statistic(c->app_ctx, &statistic); } } static void call_inject_async_fill_speed(URLContext *h, int is_full_speed, int64_t bytes, int64_t elapsed_micro) { Context *c = h->priv_data; int64_t elapsed_milli = elapsed_micro / 1000; if (c->app_ctx && bytes > 0 && elapsed_milli > 0) { AVAppAsyncReadSpeed speed = {0}; speed.size = sizeof(speed); speed.is_full_speed = is_full_speed; speed.io_bytes = bytes; speed.elapsed_milli = elapsed_milli; av_application_on_async_read_speed(c->app_ctx, &speed); } } static void *async_buffer_task(void *arg) { URLContext *h = arg; Context *c = h->priv_data; RingBuffer *ring = &c->ring; int ret = 0; int64_t seek_ret; int is_full_speed = 1; int64_t count_bytes = 0; int64_t count_start_time_micro = av_gettime_relative(); while (1) { int fifo_space, to_copy; pthread_mutex_lock(&c->mutex); if (async_check_interrupt(h)) { c->io_eof_reached = 1; c->io_error = AVERROR_EXIT; pthread_cond_signal(&c->cond_wakeup_main); pthread_mutex_unlock(&c->mutex); break; } if (c->seek_request) { seek_ret = ffurl_seek(c->inner, c->seek_pos, c->seek_whence); if (seek_ret < 0) { c->io_eof_reached = 1; c->io_error = (int)seek_ret; } else { c->io_eof_reached = 0; c->io_error = 0; } c->seek_completed = 1; c->seek_ret = seek_ret; c->seek_request = 0; ring_reset(ring); pthread_cond_signal(&c->cond_wakeup_main); pthread_mutex_unlock(&c->mutex); is_full_speed = 0; continue; } fifo_space = ring_space(ring); if (c->io_eof_reached || fifo_space <= 0) { pthread_cond_signal(&c->cond_wakeup_main); pthread_cond_wait(&c->cond_wakeup_background, &c->mutex); pthread_mutex_unlock(&c->mutex); is_full_speed = 0; continue; } pthread_mutex_unlock(&c->mutex); to_copy = FFMIN(4096, fifo_space); ret = ring_generic_write(ring, (void *)h, to_copy, (void *)wrapped_url_read); if (ret > 0) { count_bytes += ret; if (count_bytes > FFMIN((1 * 1024 * 1024), c->forwards_capacity)) { int64_t now = av_gettime_relative(); call_inject_async_fill_speed(h, is_full_speed, count_bytes, now - count_start_time_micro); is_full_speed = 1; count_bytes = 0; count_start_time_micro = now; } } pthread_mutex_lock(&c->mutex); if (ret <= 0) { c->io_eof_reached = 1; if (c->inner_io_error < 0) c->io_error = c->inner_io_error; } pthread_cond_signal(&c->cond_wakeup_main); pthread_mutex_unlock(&c->mutex); call_inject_statistic(h); } return NULL; } static int async_open(URLContext *h, const char *arg, int flags, AVDictionary **options) { Context *c = h->priv_data; int ret; AVIOInterruptCB interrupt_callback = {.callback = async_check_interrupt, .opaque = h}; av_strstart(arg, "async:", &arg); ret = ring_init(&c->ring, c->forwards_capacity, c->backwards_capacity); if (ret < 0) goto fifo_fail; if (c->app_ctx_intptr) { c->app_ctx = (AVApplicationContext *)av_dict_strtoptr(c->app_ctx_intptr); av_dict_set_intptr(options, "ijkapplication", (uintptr_t )c->app_ctx, 0); } /* wrap interrupt callback */ c->interrupt_callback = h->interrupt_callback; ret = ffurl_open_whitelist(&c->inner, arg, flags, &interrupt_callback, options, h->protocol_whitelist, h->protocol_blacklist, h); if (ret != 0) { av_log(h, AV_LOG_ERROR, "ffurl_open_whitelist failed : %s, %s\n", av_err2str(ret), arg); goto url_fail; } c->logical_size = ffurl_size(c->inner); h->is_streamed = c->inner->is_streamed; ret = pthread_mutex_init(&c->mutex, NULL); if (ret != 0) { av_log(h, AV_LOG_ERROR, "pthread_mutex_init failed : %s\n", av_err2str(ret)); goto mutex_fail; } ret = pthread_cond_init(&c->cond_wakeup_main, NULL); if (ret != 0) { av_log(h, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", av_err2str(ret)); goto cond_wakeup_main_fail; } ret = pthread_cond_init(&c->cond_wakeup_background, NULL); if (ret != 0) { av_log(h, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", av_err2str(ret)); goto cond_wakeup_background_fail; } ret = pthread_create(&c->async_buffer_thread, NULL, async_buffer_task, h); if (ret) { av_log(h, AV_LOG_ERROR, "pthread_create failed : %s\n", av_err2str(ret)); goto thread_fail; } return 0; thread_fail: pthread_cond_destroy(&c->cond_wakeup_background); cond_wakeup_background_fail: pthread_cond_destroy(&c->cond_wakeup_main); cond_wakeup_main_fail: pthread_mutex_destroy(&c->mutex); mutex_fail: ffurl_close(c->inner); url_fail: ring_destroy(&c->ring); fifo_fail: return ret; } static int async_close(URLContext *h) { Context *c = h->priv_data; int ret; pthread_mutex_lock(&c->mutex); c->abort_request = 1; pthread_cond_signal(&c->cond_wakeup_background); pthread_mutex_unlock(&c->mutex); ret = pthread_join(c->async_buffer_thread, NULL); if (ret != 0) av_log(h, AV_LOG_ERROR, "pthread_join(): %s\n", av_err2str(ret)); pthread_cond_destroy(&c->cond_wakeup_background); pthread_cond_destroy(&c->cond_wakeup_main); pthread_mutex_destroy(&c->mutex); ffurl_close(c->inner); ring_destroy(&c->ring); return 0; } static int async_read_internal(URLContext *h, void *dest, int size, int read_complete, void (*func)(void*, void*, int)) { Context *c = h->priv_data; RingBuffer *ring = &c->ring; int to_read = size; int ret = 0; pthread_mutex_lock(&c->mutex); while (to_read > 0) { int fifo_size, to_copy; if (async_check_interrupt(h)) { ret = AVERROR_EXIT; break; } fifo_size = ring_size(ring); to_copy = FFMIN(to_read, fifo_size); if (to_copy > 0) { ring_generic_read(ring, dest, to_copy, func); if (!func) dest = (uint8_t *)dest + to_copy; c->logical_pos += to_copy; to_read -= to_copy; ret = size - to_read; if (to_read <= 0 || !read_complete) break; } else if (c->io_eof_reached) { if (ret <= 0) { if (c->io_error) ret = c->io_error; else ret = AVERROR_EOF; } break; } pthread_cond_signal(&c->cond_wakeup_background); pthread_cond_wait(&c->cond_wakeup_main, &c->mutex); } pthread_cond_signal(&c->cond_wakeup_background); pthread_mutex_unlock(&c->mutex); call_inject_statistic(h); return ret; } static int async_read(URLContext *h, unsigned char *buf, int size) { return async_read_internal(h, buf, size, 0, NULL); } static void fifo_do_not_copy_func(void* dest, void* src, int size) { // do not copy } static int64_t async_seek(URLContext *h, int64_t pos, int whence) { Context *c = h->priv_data; RingBuffer *ring = &c->ring; int64_t ret; int64_t new_logical_pos; int fifo_size; int fifo_size_of_read_back; if (whence == AVSEEK_SIZE) { av_log(h, AV_LOG_TRACE, "async_seek: AVSEEK_SIZE: %"PRId64"\n", (int64_t)c->logical_size); return c->logical_size; } else if (whence == SEEK_CUR) { av_log(h, AV_LOG_TRACE, "async_seek: %"PRId64"\n", pos); new_logical_pos = pos + c->logical_pos; } else if (whence == SEEK_SET){ av_log(h, AV_LOG_TRACE, "async_seek: %"PRId64"\n", pos); new_logical_pos = pos; } else { return AVERROR(EINVAL); } if (new_logical_pos < 0) return AVERROR(EINVAL); fifo_size = ring_size(ring); fifo_size_of_read_back = ring_size_of_read_back(ring); if (new_logical_pos == c->logical_pos) { /* current position */ return c->logical_pos; } else if ((new_logical_pos >= (c->logical_pos - fifo_size_of_read_back)) && (new_logical_pos < (c->logical_pos + fifo_size + SHORT_SEEK_THRESHOLD))) { int pos_delta = (int)(new_logical_pos - c->logical_pos); /* fast seek */ av_log(h, AV_LOG_TRACE, "async_seek: fask_seek %"PRId64" from %d dist:%d/%d\n", new_logical_pos, (int)c->logical_pos, (int)(new_logical_pos - c->logical_pos), fifo_size); if (pos_delta > 0) { // fast seek forwards async_read_internal(h, NULL, pos_delta, 1, fifo_do_not_copy_func); } else { // fast seek backwards ring_drain(ring, pos_delta); call_inject_statistic(h); c->logical_pos = new_logical_pos; } return c->logical_pos; } else if (c->logical_size <= 0) { /* can not seek */ return AVERROR(EINVAL); } else if (new_logical_pos > c->logical_size) { /* beyond end */ return AVERROR(EINVAL); } pthread_mutex_lock(&c->mutex); c->seek_request = 1; c->seek_pos = new_logical_pos; c->seek_whence = SEEK_SET; c->seek_completed = 0; c->seek_ret = 0; while (1) { if (async_check_interrupt(h)) { ret = AVERROR_EXIT; break; } if (c->seek_completed) { if (c->seek_ret >= 0) c->logical_pos = c->seek_ret; ret = c->seek_ret; break; } pthread_cond_signal(&c->cond_wakeup_background); pthread_cond_wait(&c->cond_wakeup_main, &c->mutex); } pthread_mutex_unlock(&c->mutex); call_inject_statistic(h); return ret; } #define OFFSET(x) offsetof(Context, x) #define D AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { { "async-forwards-capacity", "max bytes that may be read forward in background", OFFSET(forwards_capacity), AV_OPT_TYPE_INT64, {.i64 = 128 * 1024}, 128 * 1024, 128 * 1024 * 1024, D }, { "async-backwards-capacity", "max bytes that may be seek backward without seeking in inner protocol", OFFSET(backwards_capacity), AV_OPT_TYPE_INT64, {.i64 = 128 * 1024}, 128 * 1024, 128 * 1024 * 1024, D }, { "ijkapplication", "AVApplicationContext", OFFSET(app_ctx_intptr), AV_OPT_TYPE_STRING, { .str = 0 }, 0, 0, .flags = D }, {NULL}, }; #undef D #undef OFFSET static const AVClass async_context_class = { .class_name = "Async", .item_name = av_default_item_name, .option = options, .version = LIBAVUTIL_VERSION_INT, }; const URLProtocol ijkimp_ff_async_protocol = { .name = "async", .url_open2 = async_open, .url_read = async_read, .url_seek = async_seek, .url_close = async_close, .priv_data_size = sizeof(Context), .priv_data_class = &async_context_class, }; #if 0 #define TEST_SEEK_POS (1536) #define TEST_STREAM_SIZE (2048) typedef struct TestContext { AVClass *class; int64_t logical_pos; int64_t logical_size; /* options */ int opt_read_error; } TestContext; static int async_test_open(URLContext *h, const char *arg, int flags, AVDictionary **options) { TestContext *c = h->priv_data; c->logical_pos = 0; c->logical_size = TEST_STREAM_SIZE; return 0; } static int async_test_close(URLContext *h) { return 0; } static int async_test_read(URLContext *h, unsigned char *buf, int size) { TestContext *c = h->priv_data; int i; int read_len = 0; if (c->opt_read_error) return c->opt_read_error; if (c->logical_pos >= c->logical_size) return AVERROR_EOF; for (i = 0; i < size; ++i) { buf[i] = c->logical_pos & 0xFF; c->logical_pos++; read_len++; if (c->logical_pos >= c->logical_size) break; } return read_len; } static int64_t async_test_seek(URLContext *h, int64_t pos, int whence) { TestContext *c = h->priv_data; int64_t new_logical_pos; if (whence == AVSEEK_SIZE) { return c->logical_size; } else if (whence == SEEK_CUR) { new_logical_pos = pos + c->logical_pos; } else if (whence == SEEK_SET){ new_logical_pos = pos; } else { return AVERROR(EINVAL); } if (new_logical_pos < 0) return AVERROR(EINVAL); c->logical_pos = new_logical_pos; return new_logical_pos; } #define OFFSET(x) offsetof(TestContext, x) #define D AV_OPT_FLAG_DECODING_PARAM static const AVOption async_test_options[] = { { "async-test-read-error", "cause read fail", OFFSET(opt_read_error), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, .flags = D }, {NULL}, }; #undef D #undef OFFSET static const AVClass async_test_context_class = { .class_name = "Async-Test", .item_name = av_default_item_name, .option = async_test_options, .version = LIBAVUTIL_VERSION_INT, }; const URLProtocol ff_async_test_protocol = { .name = "async-test", .url_open2 = async_test_open, .url_read = async_test_read, .url_seek = async_test_seek, .url_close = async_test_close, .priv_data_size = sizeof(TestContext), .priv_data_class = &async_test_context_class, }; int main(void) { URLContext *h = NULL; int i; int ret; int64_t size; int64_t pos; int64_t read_len; unsigned char buf[4096]; AVDictionary *opts = NULL; ffurl_register_protocol(&ijkimp_ff_async_protocol); ffurl_register_protocol(&ff_async_test_protocol); /* * test normal read */ ret = ffurl_open(&h, "async:async-test:", AVIO_FLAG_READ, NULL, NULL); printf("open: %d\n", ret); size = ffurl_size(h); printf("size: %"PRId64"\n", size); pos = ffurl_seek(h, 0, SEEK_CUR); read_len = 0; while (1) { ret = ffurl_read(h, buf, sizeof(buf)); if (ret == AVERROR_EOF) { printf("read-error: AVERROR_EOF at %"PRId64"\n", ffurl_seek(h, 0, SEEK_CUR)); break; } else if (ret == 0) break; else if (ret < 0) { printf("read-error: %d at %"PRId64"\n", ret, ffurl_seek(h, 0, SEEK_CUR)); goto fail; } else { for (i = 0; i < ret; ++i) { if (buf[i] != (pos & 0xFF)) { printf("read-mismatch: actual %d, expecting %d, at %"PRId64"\n", (int)buf[i], (int)(pos & 0xFF), pos); break; } pos++; } } read_len += ret; } printf("read: %"PRId64"\n", read_len); /* * test normal seek */ ret = ffurl_read(h, buf, 1); printf("read: %d\n", ret); pos = ffurl_seek(h, TEST_SEEK_POS, SEEK_SET); printf("seek: %"PRId64"\n", pos); read_len = 0; while (1) { ret = ffurl_read(h, buf, sizeof(buf)); if (ret == AVERROR_EOF) break; else if (ret == 0) break; else if (ret < 0) { printf("read-error: %d at %"PRId64"\n", ret, ffurl_seek(h, 0, SEEK_CUR)); goto fail; } else { for (i = 0; i < ret; ++i) { if (buf[i] != (pos & 0xFF)) { printf("read-mismatch: actual %d, expecting %d, at %"PRId64"\n", (int)buf[i], (int)(pos & 0xFF), pos); break; } pos++; } } read_len += ret; } printf("read: %"PRId64"\n", read_len); ret = ffurl_read(h, buf, 1); printf("read: %d\n", ret); /* * test read error */ ffurl_close(h); av_dict_set_int(&opts, "async-test-read-error", -10000, 0); ret = ffurl_open(&h, "async:async-test:", AVIO_FLAG_READ, NULL, &opts); printf("open: %d\n", ret); ret = ffurl_read(h, buf, 1); printf("read: %d\n", ret); fail: av_dict_free(&opts); ffurl_close(h); return 0; } #endif ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijkavformat.h ================================================ /* * ijkavformat.h * * Copyright (c) 2003 Bilibili * Copyright (c) 2003 Fabrice Bellard * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVFORMAT_IJKAVFORMAT_H #define AVFORMAT_IJKAVFORMAT_H #define AV_PKT_FLAG_DISCONTINUITY 0x0100 #endif ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijkio.c ================================================ /* * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Raymond Zheng * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "libavformat/avformat.h" #include "libavformat/url.h" #include "libavutil/avstring.h" #include "libavutil/log.h" #include "libavutil/opt.h" #include "ijkiomanager.h" #include "ijkplayer/ijkavutil/ijkdict.h" typedef struct Context { AVClass *class; char *io_manager_ctx_intptr; } Context; static int ijkio_copy_options(IjkAVDictionary **dst, AVDictionary *src) { AVDictionaryEntry *t = NULL; while ((t = av_dict_get(src, "", t, AV_DICT_IGNORE_SUFFIX))) { int ret = ijk_av_dict_set(dst, t->key, t->value, 0); if (ret < 0) return ret; } return 0; } static int ijkio_open(URLContext *h, const char *arg, int flags, AVDictionary **options) { Context *c = h->priv_data; int ret = -1; if (!c || !c->io_manager_ctx_intptr) return -1; IjkIOManagerContext *manager_ctx = (IjkIOManagerContext *)av_dict_strtoptr(c->io_manager_ctx_intptr); manager_ctx->ijkio_interrupt_callback = (IjkAVIOInterruptCB *)&(h->interrupt_callback); av_strstart(arg, "ijkio:", &arg); IjkAVDictionary *opts = NULL; ijkio_copy_options(&opts, *options); manager_ctx->cur_ffmpeg_ctx = c; ret = ijkio_manager_io_open(manager_ctx, arg, flags, &opts); ijk_av_dict_free(&opts); if (ret != 0) { ijkio_manager_io_close(manager_ctx); } return ret; } static int ijkio_read(URLContext *h, unsigned char *buf, int size) { Context *c = h->priv_data; if (!c || !c->io_manager_ctx_intptr) return -1; ((IjkIOManagerContext *)(av_dict_strtoptr(c->io_manager_ctx_intptr)))->cur_ffmpeg_ctx = c; return ijkio_manager_io_read((IjkIOManagerContext *)(av_dict_strtoptr(c->io_manager_ctx_intptr)), buf, size); } static int64_t ijkio_seek(URLContext *h, int64_t offset, int whence) { Context *c = h->priv_data; if (!c || !c->io_manager_ctx_intptr) return -1; ((IjkIOManagerContext *)(av_dict_strtoptr(c->io_manager_ctx_intptr)))->cur_ffmpeg_ctx = c; return ijkio_manager_io_seek((IjkIOManagerContext *)(av_dict_strtoptr(c->io_manager_ctx_intptr)), offset, whence); } static int ijkio_close(URLContext *h) { Context *c = h->priv_data; if (!c || !c->io_manager_ctx_intptr) return -1; ((IjkIOManagerContext *)(av_dict_strtoptr(c->io_manager_ctx_intptr)))->cur_ffmpeg_ctx = c; return ijkio_manager_io_close((IjkIOManagerContext *)(av_dict_strtoptr(c->io_manager_ctx_intptr))); } #define OFFSET(x) offsetof(Context, x) #define D AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { { "ijkiomanager", "IjkIOManagerContext", OFFSET(io_manager_ctx_intptr), AV_OPT_TYPE_STRING, { .i64 = 0 }, 0, 0, .flags = D }, { NULL } }; #undef D #undef OFFSET static const AVClass ijkio_context_class = { .class_name = "IjkIo", .item_name = av_default_item_name, .option = options, .version = LIBAVUTIL_VERSION_INT, }; URLProtocol ijkimp_ff_ijkio_protocol = { .name = "ijkio", .url_open2 = ijkio_open, .url_read = ijkio_read, .url_seek = ijkio_seek, .url_close = ijkio_close, .priv_data_size = sizeof(Context), .priv_data_class = &ijkio_context_class, }; ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijkioandroidio.c ================================================ /* * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Raymond Zheng * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijkiourl.h" #include "libavformat/avformat.h" #include "libavformat/url.h" #include "libavutil/avstring.h" #include "libavutil/log.h" #include "libavutil/opt.h" #include "ijkavformat/ijkavformat.h" #include "ijkplayer/ijkavutil/opt.h" #include "ijkplayer/ijkavutil/ijkutils.h" #include "j4a/class/tv/danmaku/ijk/media/player/misc/IAndroidIO.h" #include "ijksdl/android/ijksdl_android_jni.h" #include typedef struct IjkIOAndroidioContext { jobject ijkio_androidio; jbyteArray jbuffer; int jbuffer_capacity; URLContext *inner; } IjkIOAndroidioContext; static int ijkio_androidio_open(IjkURLContext *h, const char *url, int flags, IjkAVDictionary **options) { IjkIOAndroidioContext *c= h->priv_data; JNIEnv *env = NULL; jobject ijkio_androidio = NULL; char *final = NULL; if (!c) return -1; av_strstart(url, "androidio:", &url); IjkAVDictionaryEntry *t = NULL; t = ijk_av_dict_get(*options, "androidio-inject-callback", NULL, IJK_AV_DICT_IGNORE_SUFFIX); if (t) { ijkio_androidio = (jobject) (intptr_t) strtoll(t->value, &final, 10); } else { return -1; } if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { av_log(h, AV_LOG_ERROR, "%s: SDL_JNI_SetupThreadEnv: failed", __func__); return AVERROR(EINVAL); } if (!ijkio_androidio) return AVERROR(EINVAL); c->ijkio_androidio = (*env)->NewGlobalRef(env, ijkio_androidio); if (J4A_ExceptionCheck__catchAll(env) || !c->ijkio_androidio) { return AVERROR(ENOMEM); } jstring urlString = NULL; urlString = (*env)->NewStringUTF(env, url); jint ret = J4AC_IAndroidIO__open(env, c->ijkio_androidio, urlString); if (J4A_ExceptionCheck__catchAll(env)) { return AVERROR(EINVAL); } else if (ret < 0) { return ret; } return 0; } static jobject jbuffer_grow(JNIEnv *env, IjkURLContext *h, int new_capacity) { IjkIOAndroidioContext *c = h->priv_data; if (!c) return NULL; if (c->jbuffer && c->jbuffer_capacity >= new_capacity) return c->jbuffer; new_capacity = FFMAX(new_capacity, c->jbuffer_capacity * 2); J4A_DeleteGlobalRef__p(env, &c->jbuffer); c->jbuffer_capacity = 0; c->jbuffer = J4A_NewByteArray__asGlobalRef__catchAll(env, new_capacity); if (J4A_ExceptionCheck__catchAll(env) || !c->jbuffer) { c->jbuffer = NULL; return NULL; } c->jbuffer_capacity = new_capacity; return c->jbuffer; } static int ijkio_androidio_read(IjkURLContext *h, unsigned char *buf, int size) { IjkIOAndroidioContext *c = h->priv_data; JNIEnv *env = NULL; jbyteArray jbuffer = NULL; jint ret = 0; if (!c || !c->ijkio_androidio) return AVERROR(EINVAL); if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { av_log(h, AV_LOG_ERROR, "%s: SDL_JNI_SetupThreadEnv: failed", __func__); return AVERROR(EINVAL); } jbuffer = jbuffer_grow(env, h, size); if (!jbuffer) return AVERROR(ENOMEM); ret = J4AC_IAndroidIO__read(env, c->ijkio_androidio, jbuffer, size); if (J4A_ExceptionCheck__catchAll(env)) return AVERROR(EIO); else if (ret < 0) return AVERROR_EOF; else if (ret == 0) return AVERROR(EAGAIN); (*env)->GetByteArrayRegion(env, jbuffer, 0, ret, (jbyte*)buf); if (J4A_ExceptionCheck__catchAll(env)) return AVERROR(EIO); return ret; } static int64_t ijkio_androidio_seek(IjkURLContext *h, int64_t offset, int whence) { IjkIOAndroidioContext *c = h->priv_data; int64_t ret; JNIEnv *env = NULL; if (!c || !c->ijkio_androidio) return AVERROR(EINVAL); if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { av_log(h, AV_LOG_ERROR, "%s: SDL_JNI_SetupThreadEnv: failed", __func__); return AVERROR(EINVAL); } ret = J4AC_IAndroidIO__seek(env, c->ijkio_androidio, offset, whence); if (J4A_ExceptionCheck__catchAll(env)) return AVERROR(EIO); return ret; } static int ijkio_androidio_close(IjkURLContext *h) { IjkIOAndroidioContext *c = h->priv_data; JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { av_log(h, AV_LOG_ERROR, "%s: SDL_JNI_SetupThreadEnv: failed", __func__); return AVERROR(EINVAL); } if (!c || !c->ijkio_androidio) return AVERROR(EINVAL); J4A_DeleteGlobalRef__p(env, &c->jbuffer); if (c->ijkio_androidio) { J4AC_IAndroidIO__close__catchAll(env, c->ijkio_androidio); J4A_DeleteGlobalRef__p(env, &c->ijkio_androidio); } return 0; } IjkURLProtocol ijkio_androidio_protocol = { .name = "ijkioandroidio", .url_open2 = ijkio_androidio_open, .url_read = ijkio_androidio_read, .url_seek = ijkio_androidio_seek, .url_close = ijkio_androidio_close, .priv_data_size = sizeof(IjkIOAndroidioContext), }; ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijkioapplication.c ================================================ /* * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Raymond Zheng * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijkioapplication.h" #include int ijkio_application_alloc(IjkIOApplicationContext **ph, void *opaque) { IjkIOApplicationContext *h = NULL; h = calloc(1, sizeof(IjkIOApplicationContext)); if (!h) return -1; h->opaque = opaque; *ph = h; return 0; } int ijkio_application_open(IjkIOApplicationContext **ph, void *opaque) { int ret = ijkio_application_alloc(ph, opaque); if (ret) return ret; return 0; } void ijkio_application_close(IjkIOApplicationContext *h) { free(h); } void ijkio_application_closep(IjkIOApplicationContext **ph) { if (!ph || !*ph) return; ijkio_application_close(*ph); *ph = NULL; } void ijkio_application_on_cache_statistic(IjkIOApplicationContext *h, IjkIOAppCacheStatistic *statistic) { if (h && h->func_ijkio_on_app_event) h->func_ijkio_on_app_event(h, IJKIOAPP_EVENT_CACHE_STATISTIC, (void *)statistic, sizeof(IjkIOAppCacheStatistic)); } ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijkioapplication.h ================================================ /* * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Raymond Zheng * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKAVFORMAT_IJKIOAPPLICATION_H #define IJKAVFORMAT_IJKIOAPPLICATION_H #include "ijkplayer/ijkavutil/ijkutils.h" #include "ijkplayer/ijkavutil/ijkthreadpool.h" #include #define CACHE_FILE_PATH_MAX_LEN 512 #define IJKIOAPP_EVENT_CACHE_STATISTIC 0x1003 //IJKIOAppCacheStatistic share with avutil/application.h typedef struct IjkIOAppCacheStatistic { int64_t cache_physical_pos; int64_t cache_file_forwards; int64_t cache_file_pos; int64_t cache_count_bytes; int64_t logical_file_size; } IjkIOAppCacheStatistic; typedef struct IjkCacheEntry { int64_t logical_pos; int64_t physical_pos; int64_t size; } IjkCacheEntry; typedef struct IjkIOApplicationContext IjkIOApplicationContext; struct IjkIOApplicationContext { IjkThreadPoolContext *threadpool_ctx; IjkAVIOInterruptCB *ijkio_interrupt_callback; char cache_file_path[CACHE_FILE_PATH_MAX_LEN]; int64_t last_physical_pos; void *cache_info_map; void *opaque; int64_t cache_count_bytes; int fd; pthread_mutex_t mutex; int shared; int active_reconnect; int (*func_ijkio_on_app_event)(IjkIOApplicationContext *h, int event_type ,void *obj, int size); }; int ijkio_application_alloc(IjkIOApplicationContext **ph, void *opaque); int ijkio_application_open(IjkIOApplicationContext **ph, void *opaque); void ijkio_application_close(IjkIOApplicationContext *h); void ijkio_application_closep(IjkIOApplicationContext **ph); void ijkio_application_on_cache_statistic(IjkIOApplicationContext *h, IjkIOAppCacheStatistic *statistic); #endif /* IJKAVFORMAT_IJKIOAPPLICATION_H */ ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijkiocache.c ================================================ /* * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Raymond Zheng * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijkiourl.h" #include "ijkioprotocol.h" #include "ijkioapplication.h" #include "ijkplayer/ijkavutil/ijktree.h" #include "ijkplayer/ijkavutil/ijkutils.h" #include "ijkplayer/ijkavutil/ijkthreadpool.h" #include "ijkplayer/ijkavutil/ijkstl.h" #include "libavutil/log.h" #include #include #include #include #include #include #include #include #include #define DEFAULT_CACHE_MAX_CAPACITY (512 * 1024 * 1024) #define DEFAULT_CACHE_FILE_FORWARDS_CAPACITY (8 * 1024 * 1024) # ifndef O_BINARY # define O_BINARY 0 # endif #define FILE_RW_ERROR (-100) typedef struct IjkIOCacheContext { char *cache_file_path; int fd; IjkCacheTreeInfo *tree_info; int64_t logical_size; int64_t read_logical_pos; int64_t read_inner_pos; int64_t file_logical_pos; int64_t cache_physical_pos; int64_t file_inner_pos; int64_t file_logical_end; int64_t cache_max_capacity; int64_t cache_file_forwards_capacity; int cache_file_close; int io_eof_reached; int io_error; int inner_io_error; int read_file_inner_error; int file_handle_retry_count; int file_error_count; int seek_request; int seek_completed; int seek_whence; int64_t seek_pos; int64_t seek_ret; int cur_file_no; void *cache_info_map; int64_t *last_physical_pos; int64_t *cache_count_bytes; pthread_cond_t cond_wakeup_main; pthread_cond_t cond_wakeup_file_background; pthread_cond_t cond_wakeup_exit; pthread_cond_t cond_wakeup_write_file_exit; pthread_mutex_t file_mutex; int abort_request; IjkAVIOInterruptCB *ijkio_interrupt_callback; int task_is_running; IjkURLContext *inner; IjkThreadPoolContext *threadpool_ctx; IjkIOApplicationContext *ijkio_app_ctx; int async_open; IjkAVDictionary *inner_options; char inner_url[4096]; int inner_flags; int only_read_file; } IjkIOCacheContext; static int cmp(const void *key, const void *node) { return FFDIFFSIGN(*(const int64_t *)key, ((const IjkCacheEntry *) node)->logical_pos); } static void call_inject_statistic(IjkURLContext *h) { IjkIOCacheContext *c = h->priv_data; if (c->ijkio_app_ctx) { IjkIOAppCacheStatistic statistic = {0}; statistic.cache_physical_pos = c->cache_physical_pos; statistic.cache_file_forwards = c->file_logical_pos - c->read_logical_pos; statistic.cache_file_pos = c->file_logical_pos; statistic.cache_count_bytes = *c->cache_count_bytes; statistic.logical_file_size = c->logical_size; ijkio_application_on_cache_statistic(c->ijkio_app_ctx, &statistic); } } static int ijkio_cache_check_interrupt(IjkURLContext *h) { IjkIOCacheContext *c = h->priv_data; if (!c) return 1; if (c->abort_request) return 1; if (c->ijkio_interrupt_callback && c->ijkio_interrupt_callback->callback && c->ijkio_interrupt_callback->callback(c->ijkio_interrupt_callback->opaque)) { c->abort_request = 1; } if (c->abort_request) return 1; return c->abort_request; } static int enu_free(void *opaque, void *elem) { free(elem); return 0; } static int tree_destroy(void *parm, int64_t key, void *elem) { IjkCacheTreeInfo *info = elem; ijk_av_tree_enumerate(info->root, NULL, NULL, enu_free); ijk_av_tree_destroy(info->root); free(info); return 0; } static int ijkio_cache_file_error(IjkURLContext *h) { IjkIOCacheContext *c = h->priv_data; av_log(NULL, AV_LOG_WARNING, "ijkio_cache_file_error\n"); if (c && c->file_handle_retry_count > 3) { pthread_mutex_lock(&h->ijkio_app_ctx->mutex); c->file_error_count++; if (!c->ijkio_app_ctx->shared) { ijk_map_traversal_handle(c->cache_info_map, NULL, tree_destroy); ijk_map_clear(c->cache_info_map); c->tree_info = NULL; *c->last_physical_pos = 0; c->cache_physical_pos = 0; c->file_inner_pos = 0; c->io_eof_reached = 0; c->file_logical_pos = c->read_logical_pos; close(c->fd); c->fd = -1; c->ijkio_app_ctx->fd = -1; if (c->file_error_count > 3) { c->cache_file_close = 1; remove(c->cache_file_path); av_log(NULL, AV_LOG_WARNING, "ijkio_cache_file_error will remove file\n"); goto fail; } c->fd = open(c->cache_file_path, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0600); c->ijkio_app_ctx->fd = c->fd; if (c->fd >= 0) { c->file_handle_retry_count = 0; c->tree_info = calloc(1, sizeof(IjkCacheTreeInfo)); if (!c->tree_info) { c->cache_file_close = 1; goto fail; } ijk_map_put(c->cache_info_map, (int64_t)c->cur_file_no, c->tree_info); } else { av_log(NULL, AV_LOG_WARNING, "ijkio_cache_file_error will cache_file_close\n"); c->cache_file_close = 1; goto fail; } } pthread_mutex_unlock(&h->ijkio_app_ctx->mutex); } return 0; fail: pthread_mutex_unlock(&h->ijkio_app_ctx->mutex); return FILE_RW_ERROR; } static int64_t ijkio_cache_file_overrang(IjkURLContext *h, int64_t *cur_pos, int size) { IjkIOCacheContext *c = h->priv_data; av_log(NULL, AV_LOG_WARNING, "ijkio_cache_file_overrang will flush file\n"); pthread_mutex_lock(&h->ijkio_app_ctx->mutex); if (!c->ijkio_app_ctx->shared) { ijk_map_remove(c->cache_info_map, (int64_t)c->cur_file_no); ijk_map_traversal_handle(c->cache_info_map, NULL, tree_destroy); ijk_map_clear(c->cache_info_map); memset(c->tree_info, 0, sizeof(IjkCacheTreeInfo)); ijk_map_put(c->cache_info_map, (int64_t)c->cur_file_no, c->tree_info); *c->last_physical_pos = 0; c->cache_physical_pos = 0; c->io_eof_reached = 0; c->file_logical_pos = c->read_logical_pos; *cur_pos = lseek(c->fd, 0, SEEK_SET); if (*cur_pos < 0) { goto fail; } } else { goto fail; } pthread_mutex_unlock(&h->ijkio_app_ctx->mutex); return c->cache_max_capacity; fail: pthread_mutex_unlock(&h->ijkio_app_ctx->mutex); return FILE_RW_ERROR; } static int64_t add_entry(IjkURLContext *h, const unsigned char *buf, int size) { IjkIOCacheContext *c= h->priv_data; int64_t pos = -1; int64_t ret = 0; IjkCacheEntry *entry = NULL, *next[2] = {NULL, NULL}; IjkCacheEntry *entry_ret = NULL; struct IjkAVTreeNode *node = NULL; int64_t free_space = 0; //FIXME avoid lseek pos = lseek(c->fd, *c->last_physical_pos, SEEK_SET); if (pos < 0) { c->file_handle_retry_count++; return ijkio_cache_file_error(h); } else { c->cache_physical_pos = pos; *c->last_physical_pos = pos; } if (pos + size >= c->cache_max_capacity) { free_space = ijkio_cache_file_overrang(h, &pos, size); if (free_space < size) { c->cache_file_close = 1; return FILE_RW_ERROR; } if (pos < 0) { c->file_handle_retry_count++; return ijkio_cache_file_error(h); } if (free_space == c->cache_max_capacity) return 0; } ret = write(c->fd, buf, size); if (ret < 0) { c->file_handle_retry_count++; return ijkio_cache_file_error(h); } else { c->file_handle_retry_count = 0; } c->cache_physical_pos += ret; *c->last_physical_pos += ret; c->tree_info->physical_size += ret; entry = ijk_av_tree_find(c->tree_info->root, &c->file_logical_pos, cmp, (void**)next); if (!entry) entry = next[0]; if (!entry || entry->logical_pos + entry->size != c->file_logical_pos || entry->physical_pos + entry->size != pos) { entry = malloc(sizeof(*entry)); node = ijk_av_tree_node_alloc(); if (!entry || !node) { ret = IJKAVERROR(ENOMEM); goto fail; } entry->logical_pos = c->file_logical_pos; entry->physical_pos = pos; entry->size = ret; entry_ret = ijk_av_tree_insert(&c->tree_info->root, entry, cmp, &node); if (entry_ret && entry_ret != entry) { ret = -1; av_log(NULL, AV_LOG_ERROR, "av_tree_insert failed\n"); goto fail; } } else entry->size += ret; return ret; fail: //we could truncate the file to pos here if pos >=0 but ftruncate isn't available in VS so //for simplicty we just leave the file a bit larger free(entry); free(node); return ret; } static int wrapped_file_read(IjkURLContext *h, void *dst, int size) { IjkIOCacheContext *c = h->priv_data; int ret; ret = (int)read(c->fd, dst, size); c->read_file_inner_error = ret < 0 ? ret : 0; return ret; } static int wrapped_url_read(IjkURLContext *h, void *dst, int size) { IjkIOCacheContext *c = h->priv_data; int ret; ret = c->inner->prot->url_read(c->inner, dst, size); if (ret > 0) *c->cache_count_bytes += ret; c->inner_io_error = ret < 0 ? ret : 0; return ret; } static int64_t ijkio_cache_ffurl_size(IjkURLContext *h) { int64_t pos, size; IjkIOCacheContext *c= ((IjkURLContext *)h)->priv_data; if (!c || !c->inner || !c->inner->prot) return IJKAVERROR(ENOSYS); size = c->inner->prot->url_seek(c->inner, 0, IJKAVSEEK_SIZE); if (size < 0) { pos = c->inner->prot->url_seek(c->inner, 0, SEEK_CUR); if ((size = c->inner->prot->url_seek(c->inner, -1, SEEK_END)) < 0) return size; size++; c->inner->prot->url_seek(c->inner, pos, SEEK_SET); } return size; } static int ijkio_cache_io_open(IjkURLContext *h, const char *url, int flags, IjkAVDictionary **options) { int ret = 0; IjkIOCacheContext *c= h->priv_data; ret = c->inner->prot->url_open2(c->inner, url, flags, options); if (ret != 0) { return ret; } else { c->logical_size = ijkio_cache_ffurl_size(h); if (c->tree_info && !c->cache_file_close) { c->tree_info->file_size = c->logical_size; } } call_inject_statistic(h); return ret; } static int64_t ijkio_cache_write_file(IjkURLContext *h) { IjkIOCacheContext *c= h->priv_data; int64_t r; unsigned char buf[4096] = {0}; int to_read = 4096; int64_t to_copy = (int64_t)to_read; IjkCacheEntry *root = NULL ,*l_entry = NULL, *r_entry = NULL, *next[2] = {NULL, NULL}; if (!c || !c->inner || !c->inner->prot) return IJKAVERROR(ENOSYS); root = ijk_av_tree_find(c->tree_info->root, &c->file_logical_pos, cmp, (void**)next); if (!root) l_entry = next[0]; if (l_entry) { int64_t in_block_pos = c->file_logical_pos - l_entry->logical_pos; assert(l_entry->logical_pos <= c->file_logical_pos); if (in_block_pos < l_entry->size) { c->file_logical_pos = l_entry->logical_pos + l_entry->size; } } else if (root) { int64_t in_block_pos = c->file_logical_pos - root->logical_pos; assert(root->logical_pos <= c->file_logical_pos); if (in_block_pos < root->size) { c->file_logical_pos = root->logical_pos + root->size; } } r_entry = next[1]; if (r_entry) { to_copy = r_entry->logical_pos - c->file_logical_pos; to_copy = FFMIN(to_copy, to_read); } if (to_copy == 0) { return 0; } if (c->file_logical_end > 0 && c->file_logical_pos == c->file_logical_end) { c->io_eof_reached = 1; return 0; } if (c->file_logical_pos >= c->logical_size) { c->io_eof_reached = 1; return 0; } if (c->file_logical_pos != c->file_inner_pos) { if (c->async_open > 0) { r = ijkio_cache_io_open(h, c->inner_url, c->inner_flags, &c->inner_options); if (r != 0) { c->io_eof_reached = 1; c->io_error = (int)r; return r; } c->async_open = 0; } r = c->inner->prot->url_seek(c->inner, c->file_logical_pos, SEEK_SET); if (r < 0) { c->io_eof_reached = 1; if (c->file_logical_end == c->file_logical_pos) { c->file_inner_pos = c->file_logical_end; } return r; } c->file_inner_pos = r; } if (c->async_open > 0) { r = ijkio_cache_io_open(h, c->inner_url, c->inner_flags, &c->inner_options); if (r != 0) { c->io_eof_reached = 1; c->io_error = (int)r; return r; } c->async_open = 0; } r = c->inner->prot->url_read(c->inner, buf, (int)to_copy); if (r == 0 && to_copy > 0) { c->file_logical_end = c->file_logical_pos; } if (r <= 0) { c->io_eof_reached = 1; c->io_error = (int)r; return r; } *c->cache_count_bytes += r; c->file_inner_pos += r; pthread_mutex_lock(&c->file_mutex); r = add_entry(h, buf, (int)r); if (r > 0) { c->file_logical_pos += r; pthread_cond_signal(&c->cond_wakeup_file_background); } pthread_mutex_unlock(&c->file_mutex); return r; } static void ijkio_cache_task(void *h, void *r) { IjkIOCacheContext *c= ((IjkURLContext *)h)->priv_data; c->task_is_running = 1; int64_t ret = 0; while(1) { if (c->cache_file_close) { break; } if (ijkio_cache_check_interrupt(h)) { c->io_eof_reached = 1; c->io_error = IJKAVERROR_EXIT; break; } if (c->seek_request) { pthread_mutex_lock(&c->file_mutex); c->io_eof_reached = 0; c->io_error = 0; c->seek_completed = 1; c->seek_request = 0; c->read_logical_pos = c->seek_pos; c->file_logical_pos = c->seek_pos; c->seek_ret = c->seek_pos; pthread_cond_signal(&c->cond_wakeup_main); pthread_mutex_unlock(&c->file_mutex); } if (((c->file_logical_pos - c->read_logical_pos > c->cache_file_forwards_capacity) || c->io_eof_reached)) { pthread_mutex_lock(&c->file_mutex); pthread_cond_signal(&c->cond_wakeup_main); pthread_cond_wait(&c->cond_wakeup_file_background, &c->file_mutex); pthread_mutex_unlock(&c->file_mutex); } else { ret = ijkio_cache_write_file(h); if (ret > 0) { pthread_mutex_lock(&c->file_mutex); pthread_cond_signal(&c->cond_wakeup_main); pthread_mutex_unlock(&c->file_mutex); } else if (ret == FILE_RW_ERROR) { break; } } call_inject_statistic(h); } pthread_mutex_lock(&c->file_mutex); c->task_is_running = 0; pthread_cond_signal(&c->cond_wakeup_main); pthread_cond_signal(&c->cond_wakeup_exit); pthread_mutex_unlock(&c->file_mutex); } static int ijkio_cache_open(IjkURLContext *h, const char *url, int flags, IjkAVDictionary **options) { IjkIOCacheContext *c= h->priv_data; int ret = 0; int64_t cur_exist_file_size = 0; if (!c) return IJKAVERROR(ENOSYS); c->ijkio_app_ctx = h->ijkio_app_ctx; if (c->ijkio_app_ctx == NULL) { return -1; } c->async_open = 0; c->ijkio_interrupt_callback = h->ijkio_app_ctx->ijkio_interrupt_callback; c->cache_file_forwards_capacity = 0; ijk_av_strstart(url, "cache:", &url); c->cache_max_capacity = DEFAULT_CACHE_MAX_CAPACITY; IjkAVDictionaryEntry *t = NULL; t = ijk_av_dict_get(*options, "cache_max_capacity", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { c->cache_max_capacity = strtoll(t->value, NULL, 10); } t = ijk_av_dict_get(*options, "cache_file_forwards_capacity", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { c->cache_file_forwards_capacity = strtoll(t->value, NULL, 10); } t = ijk_av_dict_get(*options, "cache_file_close", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { c->cache_file_close = (int)strtol(t->value, NULL, 10); c->cache_file_close = c->cache_file_close != 0 ? 1 : 0; } t = ijk_av_dict_get(*options, "cur_file_no", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { c->cur_file_no = (int)strtol(t->value, NULL, 10); } t = ijk_av_dict_get(*options, "only_read_file", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { c->only_read_file = (int)strtol(t->value, NULL, 10); if (c->only_read_file) { c->cache_file_forwards_capacity = 0; } } c->cache_file_path = c->ijkio_app_ctx->cache_file_path; if (c->cache_file_path == NULL || 0 == strlen(c->cache_file_path)) { c->cache_file_close = 1; } c->threadpool_ctx = c->ijkio_app_ctx->threadpool_ctx; c->cache_info_map = c->ijkio_app_ctx->cache_info_map; c->last_physical_pos = &c->ijkio_app_ctx->last_physical_pos; c->cache_count_bytes = &c->ijkio_app_ctx->cache_count_bytes; if (!c->last_physical_pos || !c->threadpool_ctx || !c->cache_info_map) { return -1; } if (!c->cache_file_close) { do { if (c->ijkio_app_ctx->fd >= 0) { c->fd = c->ijkio_app_ctx->fd; } else { if (ijk_map_size(c->cache_info_map) > 0) { av_log(NULL, AV_LOG_INFO, "ijkio cache will use the data that already exists\n"); c->fd = open(c->cache_file_path, O_RDWR | O_BINARY, 0600); c->async_open = 1; cur_exist_file_size = lseek(c->fd, 0, SEEK_END); if (cur_exist_file_size < *c->last_physical_pos) { av_log(NULL, AV_LOG_WARNING, "ijkio cache exist is error, will delete last_physical_pos = %lld, cur_exist_file_size = %lld\n", *c->last_physical_pos, cur_exist_file_size); ijk_map_traversal_handle(c->cache_info_map, NULL, tree_destroy); ijk_map_clear(c->cache_info_map); *c->last_physical_pos = 0; c->cache_physical_pos = 0; } } else { c->fd = open(c->cache_file_path, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0600); } c->ijkio_app_ctx->fd = c->fd; } if (c->fd < 0) { c->cache_file_close = 1; break; } int64_t seek_ret = lseek(c->fd, *c->last_physical_pos, SEEK_SET); if (seek_ret < 0) { c->cache_file_close = 1; close(c->fd); c->fd = -1; c->ijkio_app_ctx->fd = -1; break; } else { c->cache_physical_pos = *c->last_physical_pos; } c->tree_info = ijk_map_get(c->cache_info_map, (int64_t)c->cur_file_no); if (c->tree_info == NULL) { c->tree_info = calloc(1, sizeof(IjkCacheTreeInfo)); c->tree_info->physical_init_pos = *c->last_physical_pos; ijk_map_put(c->cache_info_map, (int64_t)c->cur_file_no, c->tree_info); } else { if (c->tree_info->physical_size > 200 * 1024 && c->tree_info->file_size > 0) { c->logical_size = c->tree_info->file_size; c->async_open = 1; } else { c->async_open = 0; } } } while(0); } ret = ijkio_alloc_url(&(c->inner), url); if (c->inner && !ret) { c->inner->ijkio_app_ctx = c->ijkio_app_ctx; if (c->logical_size <= 0 || c->async_open == 0) { c->async_open = 0; ret = ijkio_cache_io_open(h, url, flags, options); if (ret != 0) goto url_fail; } else { c->tree_info->file_size = c->logical_size; ijk_av_dict_copy(&c->inner_options, *options, 0); strcpy(c->inner_url, url); c->inner_flags = flags; call_inject_statistic(h); } } ret = pthread_mutex_init(&c->file_mutex, NULL); if (ret != 0) { av_log(NULL, AV_LOG_ERROR, "pthread_mutex_init failed : %s\n", av_err2str(ret)); goto file_mutex_fail; } ret = pthread_cond_init(&c->cond_wakeup_main, NULL); if (ret != 0) { av_log(NULL, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", av_err2str(ret)); goto cond_wakeup_main_fail; } ret = pthread_cond_init(&c->cond_wakeup_file_background, NULL); if (ret != 0) { av_log(NULL, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", av_err2str(ret)); goto cond_wakeup_file_background_fail; } ret = pthread_cond_init(&c->cond_wakeup_exit, NULL); if (ret != 0) { av_log(NULL, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", av_err2str(ret)); goto cond_wakeup_exit_fail; } if (!c->cache_file_close && c->cache_file_forwards_capacity) { c->task_is_running = 1; ret = ijk_threadpool_add(c->threadpool_ctx, ijkio_cache_task, h, NULL, 0); if (ret) { c->task_is_running = 0; pthread_cond_signal(&c->cond_wakeup_exit); goto thread_fail; } } return 0; thread_fail: pthread_cond_destroy(&c->cond_wakeup_exit); cond_wakeup_exit_fail: pthread_cond_destroy(&c->cond_wakeup_file_background); cond_wakeup_file_background_fail: pthread_cond_destroy(&c->cond_wakeup_main); cond_wakeup_main_fail: pthread_mutex_destroy(&c->file_mutex); file_mutex_fail: if (c->async_open) { if (c->inner_options) { ijk_av_dict_free(&c->inner_options); } } else { if (c->inner) { if (c->inner->prot && c->inner->prot->url_close) { c->inner->prot->url_close(c->inner); } } } url_fail: if (c->inner) { ijk_av_freep(&c->inner->priv_data); ijk_av_freep(&c->inner); } return ret; } static int ijkio_file_read(IjkURLContext *h, void *dest, int to_read) { IjkIOCacheContext *c = h->priv_data; IjkCacheEntry *entry = NULL; IjkCacheEntry *next[2] = {NULL, NULL}; int64_t ret = 0; int to_copy = 0; if (!c->tree_info) return 0; entry = ijk_av_tree_find(c->tree_info->root, &c->read_logical_pos, cmp, (void**)next); if (!entry) entry = next[0]; if (entry) { int64_t in_block_pos = c->read_logical_pos - entry->logical_pos; if (in_block_pos < entry->size && entry->logical_pos <= c->read_logical_pos) { int64_t physical_target = entry->physical_pos + in_block_pos; if (c->cache_physical_pos != physical_target) { ret = lseek(c->fd, physical_target, SEEK_SET); if (ret < 0) { c->file_handle_retry_count++; ijkio_cache_file_error(h); } } else { ret = c->cache_physical_pos; } if (ret >= 0) { to_copy = (int)FFMIN(to_read, entry->size - in_block_pos); ret = wrapped_file_read(h, dest, to_copy); if (ret < 0) { if(c->read_file_inner_error) { c->file_handle_retry_count++; ijkio_cache_file_error(h); } } } } } return (int)ret; } static int64_t sync_add_entry(IjkURLContext *h, const unsigned char *buf, int size) { IjkIOCacheContext *c= h->priv_data; int64_t pos = -1; int64_t ret = 0; IjkCacheEntry *entry = NULL, *next[2] = {NULL, NULL}; IjkCacheEntry *entry_ret = NULL; struct IjkAVTreeNode *node = NULL; int64_t free_space = 0; if (*c->last_physical_pos != c->cache_physical_pos) { pos = lseek(c->fd, *c->last_physical_pos, SEEK_SET); if (pos < 0) { return FILE_RW_ERROR; } else { c->cache_physical_pos = pos; *c->last_physical_pos = pos; } } else { pos = *c->last_physical_pos; } if (*c->last_physical_pos + size >= c->cache_max_capacity) { free_space = ijkio_cache_file_overrang(h, &pos, size); if (free_space < size || pos < 0) { return FILE_RW_ERROR; } c->cache_physical_pos = pos; *c->last_physical_pos = pos; } ret = write(c->fd, buf, size); if (ret < 0) { return FILE_RW_ERROR; } c->cache_physical_pos += ret; *c->last_physical_pos += ret; c->tree_info->physical_size += ret; entry = ijk_av_tree_find(c->tree_info->root, &c->read_logical_pos, cmp, (void**)next); if (!entry) entry = next[0]; if (!entry || entry->logical_pos + entry->size != c->read_logical_pos || entry->physical_pos + entry->size != pos) { entry = malloc(sizeof(*entry)); node = ijk_av_tree_node_alloc(); if (!entry || !node) { ret = IJKAVERROR(ENOMEM); goto fail; } entry->logical_pos = c->read_logical_pos; entry->physical_pos = pos; entry->size = ret; entry_ret = ijk_av_tree_insert(&c->tree_info->root, entry, cmp, &node); if (entry_ret && entry_ret != entry) { ret = -1; av_log(NULL, AV_LOG_ERROR, "sync_add_entry av_tree_insert failed\n"); goto fail; } } else { entry->size += ret; } return ret; fail: //we could truncate the file to pos here if pos >=0 but ftruncate isn't available in VS so //for simplicty we just leave the file a bit larger free(entry); free(node); return ret; } static int ijkio_cache_sync_read(IjkURLContext *h, unsigned char *buf, int size) { IjkIOCacheContext *c= h->priv_data; int64_t ret = 0; int to_read = size; int to_copy = 0; IjkCacheEntry *entry = NULL, *next_entry = NULL, *next[2] = {NULL, NULL}; if (!c || !c->inner || !c->inner->prot) return IJKAVERROR(ENOSYS); if (to_read <= 0) { return to_read; } if (c->tree_info) { entry = ijk_av_tree_find(c->tree_info->root, &c->read_logical_pos, cmp, (void**)next); } if (!entry) entry = next[0]; if (entry) { int64_t in_block_pos = c->read_logical_pos - entry->logical_pos; if (in_block_pos < entry->size && entry->logical_pos <= c->read_logical_pos) { int64_t physical_target = entry->physical_pos + in_block_pos; if (c->cache_physical_pos != physical_target) { ret = lseek(c->fd, physical_target, SEEK_SET); } else { ret = c->cache_physical_pos; } if (ret >= 0) { c->cache_physical_pos = ret; to_copy = (int)FFMIN(to_read, entry->size - in_block_pos); ret = wrapped_file_read(h, buf, to_copy); if (ret >= 0) { c->cache_physical_pos += ret; return (int)ret; } } av_log(NULL, AV_LOG_ERROR, "%s cache file is bad, will try recreate\n", __func__); ijk_map_traversal_handle(c->cache_info_map, NULL, tree_destroy); ijk_map_clear(c->cache_info_map); c->tree_info = NULL; *c->last_physical_pos = 0; c->cache_physical_pos = 0; c->io_eof_reached = 0; close(c->fd); c->fd = open(c->cache_file_path, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0600); c->ijkio_app_ctx->fd = c->fd; if (c->fd >= 0) { c->tree_info = calloc(1, sizeof(IjkCacheTreeInfo)); if (c->tree_info) { ijk_map_put(c->cache_info_map, (int64_t)c->cur_file_no, c->tree_info); } } } } if (c->read_logical_pos >= c->logical_size) { c->io_eof_reached = 1; return 0; } if (c->async_open > 0) { ret = ijkio_cache_io_open(h, c->inner_url, c->inner_flags, &c->inner_options); if (ret != 0) { return (int)ret; } c->async_open = 0; } if (c->read_inner_pos != c->read_logical_pos) { ret = c->inner->prot->url_seek(c->inner, c->read_logical_pos, SEEK_SET); if (ret < 0) { return (int)ret; } c->read_inner_pos = ret; } next_entry = next[1]; if (next_entry && next_entry->logical_pos > c->read_logical_pos) { to_copy = (int)FFMIN(to_read, next_entry->logical_pos - c->read_logical_pos); } else { to_copy = to_read; } ret = wrapped_url_read(h, buf, to_copy); if (ret <= 0) return (int)ret; c->read_inner_pos += ret; if (c->fd >= 0 && c->tree_info && !c->only_read_file) { sync_add_entry(h, buf, (int)ret); } return (int)ret; } static int ijkio_cache_read(IjkURLContext *h, unsigned char *buf, int size) { IjkIOCacheContext *c = h->priv_data; int64_t ret = 0; int to_read = size; unsigned char *dest = buf; int to_copy = 0; if (!c || !c->inner || !c->inner->prot) return IJKAVERROR(ENOSYS); if (c->cache_file_close) { return wrapped_url_read(h, dest, to_read); } if (!c->cache_file_forwards_capacity) { ret = ijkio_cache_sync_read(h, buf, size); if (ret >= 0) { c->read_logical_pos += ret; } call_inject_statistic(h); return (int)ret; } pthread_mutex_lock(&c->file_mutex); while (to_read > 0) { if (ijkio_cache_check_interrupt(h)) { ret = IJKAVERROR_EXIT; break; } if (c->cache_file_close) { ret = c->inner->prot->url_seek(c->inner, c->read_logical_pos, SEEK_SET); if (ret < 0) { pthread_mutex_unlock(&c->file_mutex); return (int)ret; } to_copy = wrapped_url_read(h, dest, to_read); to_read -= to_copy; ret = size - to_read; pthread_mutex_unlock(&c->file_mutex); return (int)ret; } to_copy = ijkio_file_read(h, dest, to_read); if (to_copy > 0) { to_read -= to_copy; ret = size - to_read; dest += to_copy; c->read_logical_pos += to_copy; if (to_read <= 0) break; } else if (c->io_eof_reached) { if (ret <= 0) { if (c->io_error) ret = c->io_error; else ret = IJKAVERROR_EOF; } break; } pthread_cond_signal(&c->cond_wakeup_file_background); pthread_cond_wait(&c->cond_wakeup_main, &c->file_mutex); } if (ret != size || (!c->io_eof_reached && (c->file_logical_pos - c->read_logical_pos) <= c->cache_file_forwards_capacity)) { pthread_cond_signal(&c->cond_wakeup_file_background); } pthread_mutex_unlock(&c->file_mutex); return (int)ret; } static int64_t ijkio_cache_seek(IjkURLContext *h, int64_t pos, int whence) { IjkIOCacheContext *c= h->priv_data; int64_t ret = 0; int64_t new_logical_pos = 0; if (!c || !c->inner || !c->inner->prot) return IJKAVERROR(ENOSYS); if (whence == IJKAVSEEK_SIZE) { return c->logical_size; } else if (whence == SEEK_CUR) { new_logical_pos = pos + c->read_logical_pos; } else if (whence == SEEK_SET){ new_logical_pos = pos; } else { return IJKAVERROR(EINVAL); } if (new_logical_pos < 0) return IJKAVERROR(EINVAL); if (c->cache_file_close) { return c->inner->prot->url_seek(c->inner, new_logical_pos, SEEK_SET); } if (!c->cache_file_forwards_capacity) { c->read_logical_pos = new_logical_pos; return new_logical_pos; } pthread_mutex_lock(&c->file_mutex); c->seek_request = 1; c->seek_pos = new_logical_pos; c->seek_whence = SEEK_SET; c->seek_completed = 0; while (1) { if (ijkio_cache_check_interrupt(h)) { ret = IJKAVERROR_EXIT; break; } if (c->seek_completed) { ret = c->seek_ret; break; } pthread_cond_signal(&c->cond_wakeup_file_background); pthread_cond_wait(&c->cond_wakeup_main, &c->file_mutex); } pthread_mutex_unlock(&c->file_mutex); return ret; } static int ijkio_cache_close(IjkURLContext *h) { IjkIOCacheContext *c = h->priv_data; int ret = 0; if (!c || !c->inner || !c->inner->prot) return IJKAVERROR(ENOSYS); if (c->cache_file_forwards_capacity) { pthread_mutex_lock(&c->file_mutex); c->abort_request = 1; pthread_cond_signal(&c->cond_wakeup_file_background); while (c->task_is_running) { pthread_cond_wait(&c->cond_wakeup_exit, &c->file_mutex); } pthread_mutex_unlock(&c->file_mutex); } else { c->abort_request = 1; } pthread_cond_destroy(&c->cond_wakeup_file_background); pthread_cond_destroy(&c->cond_wakeup_main); pthread_cond_destroy(&c->cond_wakeup_exit); pthread_mutex_destroy(&c->file_mutex); ret = c->inner->prot->url_close(c->inner); if (c->inner_options) { ijk_av_dict_free(&c->inner_options); } ijk_av_freep(&c->inner->priv_data); ijk_av_freep(&c->inner); return ret; } static int ijkio_cache_pause(IjkURLContext *h) { IjkIOCacheContext *c = h->priv_data; int ret = 0; if (!c || !c->inner || !c->inner->prot) return IJKAVERROR(ENOSYS); if (c->inner->prot->url_pause) { ret = c->inner->prot->url_pause(c->inner); } if (!c->cache_file_forwards_capacity) { c->abort_request = 1; } else { pthread_mutex_lock(&c->file_mutex); c->abort_request = 1; pthread_cond_signal(&c->cond_wakeup_file_background); while (c->task_is_running) { pthread_cond_wait(&c->cond_wakeup_exit, &c->file_mutex); } pthread_mutex_unlock(&c->file_mutex); } return ret; } static int ijkio_cache_resume(IjkURLContext *h) { IjkIOCacheContext *c = h->priv_data; int ret = 0; if (!c || !c->inner || !c->inner->prot) return IJKAVERROR(ENOSYS); if (!c->cache_file_path || 0 == strlen(c->cache_file_path) || c->cache_file_close) { c->cache_file_close = 1; } else { if (c->cache_file_forwards_capacity) { int64_t seek_ret = lseek(c->fd, *c->last_physical_pos, SEEK_SET); if (seek_ret < 0) { c->cache_file_close = 1; close(c->fd); c->fd = -1; c->ijkio_app_ctx->fd = -1; } else { c->cache_physical_pos = *c->last_physical_pos; } } } if (c->inner->prot->url_resume) { ret = c->inner->prot->url_resume(c->inner); if (ret != 0) { return ret; } } c->abort_request = 0; if (!c->cache_file_close && c->cache_file_forwards_capacity) { c->task_is_running = 1; ret = ijk_threadpool_add(c->threadpool_ctx, ijkio_cache_task, h, NULL, 0); if (ret) { c->task_is_running = 0; pthread_cond_signal(&c->cond_wakeup_exit); } } return ret; } IjkURLProtocol ijkio_cache_protocol = { .name = "ijkiocache", .url_open2 = ijkio_cache_open, .url_read = ijkio_cache_read, .url_seek = ijkio_cache_seek, .url_close = ijkio_cache_close, .url_pause = ijkio_cache_pause, .url_resume = ijkio_cache_resume, .priv_data_size = sizeof(IjkIOCacheContext), }; ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijkioffio.c ================================================ /* * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Raymond Zheng * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libavformat/url.h" #include "libavutil/avstring.h" #include "ijkplayer/ijkavutil/ijkutils.h" #include "ijkiourl.h" #include typedef struct IjkIOFFioContext { URLContext *inner; } IjkIOFFioContext; static int ijkio_copy_options(AVDictionary **dst, IjkAVDictionary *src) { IjkAVDictionaryEntry *t = NULL; while ((t = ijk_av_dict_get(src, "", t, IJK_AV_DICT_IGNORE_SUFFIX))) { int ret = av_dict_set(dst, t->key, t->value, 0); if (ret < 0) return ret; } return 0; } static int ijkio_ffio_open(IjkURLContext *h, const char *url, int flags, IjkAVDictionary **options) { int ret = -1; IjkIOFFioContext *c= h->priv_data; if (!c) return -1; AVDictionary *opts = NULL; ijkio_copy_options(&opts, *options); av_strstart(url, "ffio:", &url); if (h->ijkio_app_ctx) { ret = ffurl_open_whitelist(&c->inner, url, flags, (AVIOInterruptCB *)h->ijkio_app_ctx->ijkio_interrupt_callback, &opts, NULL, NULL, NULL); } else { ret = -1; } av_dict_free(&opts); return ret; } static int ijkio_ffio_read(IjkURLContext *h, unsigned char *buf, int size) { if (!h) return -1; IjkIOFFioContext *c= h->priv_data; if (!c || !c->inner) return -1; return ffurl_read(c->inner, buf, size); } static int64_t ijkio_ffio_seek(IjkURLContext *h, int64_t offset, int whence) { if (!h) return -1; IjkIOFFioContext *c= h->priv_data; if (!c || !c->inner) return -1; return ffurl_seek(c->inner, offset, whence); } static int ijkio_ffio_close(IjkURLContext *h) { if (!h) return -1; IjkIOFFioContext *c= h->priv_data; if (!c || !c->inner) return -1; return ffurl_close(c->inner); } IjkURLProtocol ijkio_ffio_protocol = { .name = "ijkffio", .url_open2 = ijkio_ffio_open, .url_read = ijkio_ffio_read, .url_seek = ijkio_ffio_seek, .url_close = ijkio_ffio_close, .priv_data_size = sizeof(IjkIOFFioContext), }; ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijkiomanager.c ================================================ /* * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Raymond Zheng * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijkiomanager.h" #include "ijkioprotocol.h" #include "ijkplayer/ijkavutil/ijkutils.h" #include "ijkplayer/ijkavutil/ijktree.h" #include "ijkplayer/ijkavutil/ijkstl.h" #include "libavutil/log.h" #include #include #include #include #define CONFIG_MAX_LINE 1024 static int ijkio_manager_alloc(IjkIOManagerContext **ph, void *opaque) { IjkIOManagerContext *h = NULL; h = (IjkIOManagerContext *)calloc(1, sizeof(IjkIOManagerContext)); if (!h) return -1; h->opaque = opaque; h->ijk_ctx_map = ijk_map_create(); ijkio_application_open(&h->ijkio_app_ctx, opaque); pthread_mutex_init(&h->ijkio_app_ctx->mutex, NULL); h->ijkio_app_ctx->threadpool_ctx = ijk_threadpool_create(5, 5, 0); h->ijkio_app_ctx->cache_info_map = ijk_map_create(); h->ijkio_app_ctx->fd = -1; *ph = h; return 0; } int ijkio_manager_create(IjkIOManagerContext **ph, void *opaque) { return ijkio_manager_alloc(ph, opaque); } static int enu_free(void *opaque, void *elem) { free(elem); return 0; } static int tree_destroy(void *parm, int64_t key, void *elem) { IjkCacheTreeInfo *info = elem; ijk_av_tree_enumerate(info->root, NULL, NULL, enu_free); ijk_av_tree_destroy(info->root); free(info); return 0; } static int enu_save(void *opaque, void *elem) { FILE *fp = opaque; IjkCacheEntry *entry = elem; char string[CONFIG_MAX_LINE] = {0}; if (entry && fp) { memset(string, 0, CONFIG_MAX_LINE); snprintf(string, CONFIG_MAX_LINE, "entry_logical_pos:%lld\n", entry->logical_pos); fwrite(string, strlen(string), 1, fp); memset(string, 0, CONFIG_MAX_LINE); snprintf(string, CONFIG_MAX_LINE, "entry_physical_pos:%lld\n", entry->physical_pos); fwrite(string, strlen(string), 1, fp); memset(string, 0, CONFIG_MAX_LINE); snprintf(string, CONFIG_MAX_LINE, "entry_size:%lld\n", entry->size); fwrite(string, strlen(string), 1, fp); memset(string, 0, CONFIG_MAX_LINE); snprintf(string, CONFIG_MAX_LINE, "entry-info-flush\n"); fwrite(string, strlen(string), 1, fp); } return 0; } static int ijkio_manager_save_tree_to_file(void *parm, int64_t key, void *elem) { IjkCacheTreeInfo *info = elem; FILE *fp = parm; char string[CONFIG_MAX_LINE] = {0}; if (key >= 0 && info) { memset(string, 0, CONFIG_MAX_LINE); snprintf(string, CONFIG_MAX_LINE, "tree_index:%lld\n", key); fwrite(string, strlen(string), 1, fp); memset(string, 0, CONFIG_MAX_LINE); snprintf(string, CONFIG_MAX_LINE, "tree_physical_init_pos:%lld\n", info->physical_init_pos); fwrite(string, strlen(string), 1, fp); memset(string, 0, CONFIG_MAX_LINE); snprintf(string, CONFIG_MAX_LINE, "tree_physical_size:%lld\n", info->physical_size); fwrite(string, strlen(string), 1, fp); memset(string, 0, CONFIG_MAX_LINE); snprintf(string, CONFIG_MAX_LINE, "tree_file_size:%lld\n", info->file_size); fwrite(string, strlen(string), 1, fp); memset(string, 0, CONFIG_MAX_LINE); snprintf(string, CONFIG_MAX_LINE, "tree-info-flush\n"); fwrite(string, strlen(string), 1, fp); ijk_av_tree_enumerate(info->root, parm, NULL, enu_save); } return 0; } void ijkio_manager_destroy(IjkIOManagerContext *h) { FILE *map_tree_info_fp = NULL; if (h->ijkio_app_ctx) { if (h->auto_save_map) { map_tree_info_fp = fopen(h->cache_map_path, "w"); if (map_tree_info_fp) { ijk_map_traversal_handle(h->ijkio_app_ctx->cache_info_map, map_tree_info_fp, ijkio_manager_save_tree_to_file); fclose(map_tree_info_fp); } } ijk_map_traversal_handle(h->ijkio_app_ctx->cache_info_map, NULL, tree_destroy); ijk_map_destroy(h->ijkio_app_ctx->cache_info_map); h->ijkio_app_ctx->cache_info_map = NULL; if (h->ijkio_app_ctx->threadpool_ctx) { ijk_threadpool_destroy(h->ijkio_app_ctx->threadpool_ctx, IJK_IMMEDIATE_SHUTDOWN); } if (0 != strlen(h->ijkio_app_ctx->cache_file_path)) { if (h->ijkio_app_ctx->fd >= 0) { close(h->ijkio_app_ctx->fd); } } pthread_mutex_destroy(&h->ijkio_app_ctx->mutex); ijkio_application_closep(&h->ijkio_app_ctx); } ijk_map_destroy(h->ijk_ctx_map); h->ijk_ctx_map = NULL; free(h); } void ijkio_manager_destroyp(IjkIOManagerContext **ph) { if (!ph || !*ph) return; ijkio_manager_destroy(*ph); *ph = NULL; } int ijkio_manager_set_callback(IjkIOManagerContext *h, void *callback) { if (!h) return -1; h->ijkio_app_ctx->func_ijkio_on_app_event = callback; return 0; } static void ijkio_manager_set_all_ctx_pause(IjkIOManagerContext *h) { IjkURLContext *url_ctx; int size = ijk_map_size(h->ijk_ctx_map); for(int i = 0; i < size; i++) { url_ctx = ijk_map_index_get(h->ijk_ctx_map, i); if (url_ctx == NULL || url_ctx->prot == NULL) break; if (url_ctx->prot->url_pause) url_ctx->prot->url_pause(url_ctx); url_ctx->state = IJKURL_PAUSED; } } static int cmp(const void *key, const void *node) { return FFDIFFSIGN(*(const int64_t *)key, ((const IjkCacheEntry *) node)->logical_pos); } static void ijkio_manager_parse_cache_info(IjkIOApplicationContext *app_ctx, char *file_path) { char string_line[CONFIG_MAX_LINE] = {0}; char **ptr = (char **)&string_line; uint64_t str_len = 0; int tree_index = 0; int64_t tree_physical_init_pos = 0; int64_t tree_physical_size = 0; int64_t tree_file_size = 0; int64_t entry_logical_pos = 0; int64_t entry_physical_pos = 0; int64_t entry_size = 0; void *cache_info_map = app_ctx->cache_info_map; IjkCacheTreeInfo *cur_tree_info = NULL; IjkCacheEntry *cur_entry = NULL; IjkCacheEntry *entry_ret = NULL; struct IjkAVTreeNode *cur_node = NULL; FILE *fp = fopen(file_path, "r"); if (!fp) { return; } while (!feof(fp)) { memset(string_line, 0 , CONFIG_MAX_LINE); fgets(string_line, CONFIG_MAX_LINE, fp); av_log(NULL, AV_LOG_INFO, "cache config info: %s\n", string_line); if (ijk_av_strstart(string_line, "tree_index:", (const char **)ptr)) { str_len = strlen(*ptr); for (int i = 0; i < str_len; i++) { if ((*ptr)[i] < '0' || (*ptr)[i] > '9') { (*ptr)[i] = '\0'; break; } } tree_index = (int)strtol(*ptr, NULL, 10); } else if (ijk_av_strstart(string_line, "tree_physical_init_pos:", (const char **)ptr)) { str_len = strlen(*ptr); for (int i = 0; i < str_len; i++) { if ((*ptr)[i] < '0' || (*ptr)[i] > '9') { (*ptr)[i] = '\0'; break; } } tree_physical_init_pos = strtoll(*ptr, NULL, 10); } else if (ijk_av_strstart(string_line, "tree_physical_size:", (const char **)ptr)) { str_len = strlen(*ptr); for (int i = 0; i < str_len; i++) { if ((*ptr)[i] < '0' || (*ptr)[i] > '9') { (*ptr)[i] = '\0'; break; } } tree_physical_size = strtoll(*ptr, NULL, 10); app_ctx->last_physical_pos += tree_physical_size; } else if (ijk_av_strstart(string_line, "tree_file_size:", (const char **)ptr)) { str_len = strlen(*ptr); for (int i = 0; i < str_len; i++) { if ((*ptr)[i] < '0' || (*ptr)[i] > '9') { (*ptr)[i] = '\0'; break; } } tree_file_size = strtoll(*ptr, NULL, 10); } else if (ijk_av_strstart(string_line, "tree-info-flush", (const char **)ptr)) { cur_tree_info = calloc(1, sizeof(IjkCacheTreeInfo)); if (cur_tree_info) { cur_tree_info->physical_init_pos = tree_physical_init_pos; cur_tree_info->physical_size = tree_physical_size; cur_tree_info->file_size = tree_file_size; ijk_map_put(cache_info_map, tree_index, cur_tree_info); } else { break; } tree_index = 0; tree_physical_init_pos = 0; tree_physical_size = 0; tree_file_size = 0; } else if (ijk_av_strstart(string_line, "entry_logical_pos:", (const char **)ptr)) { str_len = strlen(*ptr); for (int i = 0; i < str_len; i++) { if ((*ptr)[i] < '0' || (*ptr)[i] > '9') { (*ptr)[i] = '\0'; break; } } entry_logical_pos = strtoll(*ptr, NULL, 10); } else if (ijk_av_strstart(string_line, "entry_physical_pos:", (const char **)ptr)) { str_len = strlen(*ptr); for (int i = 0; i < str_len; i++) { if ((*ptr)[i] < '0' || (*ptr)[i] > '9') { (*ptr)[i] = '\0'; break; } } entry_physical_pos = strtoll(*ptr, NULL, 10); } else if (ijk_av_strstart(string_line, "entry_size:", (const char **)ptr)) { str_len = strlen(*ptr); for (int i = 0; i < str_len; i++) { if ((*ptr)[i] < '0' || (*ptr)[i] > '9') { (*ptr)[i] = '\0'; break; } } entry_size = strtoll(*ptr, NULL, 10); } else if (ijk_av_strstart(string_line, "entry-info-flush", (const char **)ptr)) { if (cur_tree_info) { cur_entry = calloc(1, sizeof(IjkCacheEntry)); cur_node = ijk_av_tree_node_alloc(); if (!cur_entry || !cur_node) { break; } cur_entry->logical_pos = entry_logical_pos; cur_entry->physical_pos = entry_physical_pos; cur_entry->size = entry_size; entry_ret = ijk_av_tree_insert(&cur_tree_info->root, cur_entry, cmp, &cur_node); if (entry_ret && entry_ret != cur_entry) { break; } } } } fclose(fp); } void ijkio_manager_will_share_cache_map(IjkIOManagerContext *h) { av_log(NULL, AV_LOG_INFO, "will share cache\n"); if (!h || !h->ijkio_app_ctx || !strlen(h->cache_map_path)) { return; } pthread_mutex_lock(&h->ijkio_app_ctx->mutex); FILE *map_tree_info_fp = fopen(h->cache_map_path, "w"); if (!map_tree_info_fp) { pthread_mutex_unlock(&h->ijkio_app_ctx->mutex); return; } h->ijkio_app_ctx->shared = 1; ijk_map_traversal_handle(h->ijkio_app_ctx->cache_info_map, map_tree_info_fp, ijkio_manager_save_tree_to_file); fclose(map_tree_info_fp); if (h->ijkio_app_ctx->fd >= 0) { fsync(h->ijkio_app_ctx->fd); } pthread_mutex_unlock(&h->ijkio_app_ctx->mutex); } void ijkio_manager_immediate_reconnect(IjkIOManagerContext *h) { av_log(NULL, AV_LOG_INFO, "ijkio manager immediate reconnect\n"); if (!h || !h->ijkio_app_ctx) { return; } h->ijkio_app_ctx->active_reconnect = 1; } void ijkio_manager_did_share_cache_map(IjkIOManagerContext *h) { av_log(NULL, AV_LOG_INFO, "did share cache\n"); if (!h || !h->ijkio_app_ctx) { return; } pthread_mutex_lock(&h->ijkio_app_ctx->mutex); h->ijkio_app_ctx->shared = 0; pthread_mutex_unlock(&h->ijkio_app_ctx->mutex); } int ijkio_manager_io_open(IjkIOManagerContext *h, const char *url, int flags, IjkAVDictionary **options) { int ret = -1; int parse_cache_map_file = 0; if (!h) return ret; if (!h->ijkio_app_ctx) { return -1; } IjkAVDictionaryEntry *t = NULL; t = ijk_av_dict_get(*options, "cache_file_path", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { strcpy(h->ijkio_app_ctx->cache_file_path, t->value); } t = ijk_av_dict_get(*options, "cache_map_path", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { strcpy(h->cache_map_path, t->value); t = ijk_av_dict_get(*options, "auto_save_map", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { h->auto_save_map = (int)strtol(t->value, NULL, 10); } if (h->ijkio_app_ctx->cache_info_map && !ijk_map_size(h->ijkio_app_ctx->cache_info_map)) { t = ijk_av_dict_get(*options, "parse_cache_map", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { parse_cache_map_file = (int)strtol(t->value, NULL, 10); if (parse_cache_map_file) { ijkio_manager_parse_cache_info(h->ijkio_app_ctx, h->cache_map_path); } } } } h->ijkio_app_ctx->ijkio_interrupt_callback = h->ijkio_interrupt_callback; IjkURLContext *inner = NULL; ijkio_alloc_url(&inner, url); if (inner) { inner->ijkio_app_ctx = h->ijkio_app_ctx; if (h->ijk_ctx_map) { ijkio_manager_set_all_ctx_pause(h); inner->state = IJKURL_STARTED; ijk_map_put(h->ijk_ctx_map, (int64_t)(intptr_t)h->cur_ffmpeg_ctx, inner); } ret = inner->prot->url_open2(inner, url, flags, options); if (ret != 0) goto fail; return ret; } fail: if (inner) { if (inner->prot && inner->prot->url_close) ret = inner->prot->url_close(inner); if (h->ijk_ctx_map) { ijk_map_remove(h->ijk_ctx_map, (int64_t)(intptr_t)h->cur_ffmpeg_ctx); } ijk_av_freep(&inner->priv_data); ijk_av_freep(&inner); } return -1; } int ijkio_manager_io_read(IjkIOManagerContext *h, unsigned char *buf, int size) { int ret = -1; if (!h) return ret; IjkURLContext *inner = ijk_map_get(h->ijk_ctx_map, (int64_t)(intptr_t)h->cur_ffmpeg_ctx); if (inner && inner->prot && inner->prot->url_read) { if (inner->state == IJKURL_PAUSED) { if (inner->prot->url_resume) { ret = inner->prot->url_resume(inner); if (ret != 0) { return ret; } } inner->state = IJKURL_STARTED; } ret = inner->prot->url_read(inner, buf, size); } return ret; } int64_t ijkio_manager_io_seek(IjkIOManagerContext *h, int64_t offset, int whence) { int64_t ret = -1; if (!h) return ret; IjkURLContext *inner = ijk_map_get(h->ijk_ctx_map, (int64_t)(intptr_t)h->cur_ffmpeg_ctx); if (inner && inner->prot && inner->prot->url_seek) { if (inner->state == IJKURL_PAUSED) { if (inner->prot->url_resume) { ret = (int64_t)inner->prot->url_resume(inner); if (ret < 0) { return ret; } } inner->state = IJKURL_STARTED; } ret = inner->prot->url_seek(inner, offset, whence & ~IJKAVSEEK_FORCE); } return ret; } int ijkio_manager_io_close(IjkIOManagerContext *h) { int ret = -1; if (!h) return ret; IjkURLContext *inner = ijk_map_get(h->ijk_ctx_map, (int64_t)(intptr_t)h->cur_ffmpeg_ctx); if (inner) { if (inner->prot && inner->prot->url_close) { ret = inner->prot->url_close(inner); } ijk_map_remove(h->ijk_ctx_map, (int64_t)(intptr_t)h->cur_ffmpeg_ctx); ijk_av_freep(&inner->priv_data); ijk_av_freep(&inner); } return ret; } ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijkiomanager.h ================================================ /* * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Raymond Zheng * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKAVFORMAT_IJKIOMANAGER_H #define IJKAVFORMAT_IJKIOMANAGER_H #include "ijkiourl.h" #include "ijkioapplication.h" #include #define CACHE_MAP_PATH_MAX_LEN 512 typedef struct IjkIOManagerContext IjkIOManagerContext; struct IjkIOManagerContext { IjkAVIOInterruptCB *ijkio_interrupt_callback; IjkIOApplicationContext *ijkio_app_ctx; int auto_save_map; void *cur_ffmpeg_ctx; void *ijk_ctx_map; void *opaque; char cache_map_path[CACHE_MAP_PATH_MAX_LEN]; }; int ijkio_manager_create(IjkIOManagerContext **ph, void *opaque); void ijkio_manager_destroy(IjkIOManagerContext *h); void ijkio_manager_destroyp(IjkIOManagerContext **ph); int ijkio_manager_set_callback(IjkIOManagerContext *h, void *callback); void ijkio_manager_will_share_cache_map(IjkIOManagerContext *h); void ijkio_manager_did_share_cache_map(IjkIOManagerContext *h); void ijkio_manager_immediate_reconnect(IjkIOManagerContext *h); int ijkio_manager_io_open(IjkIOManagerContext *h, const char *url, int flags, IjkAVDictionary **options); int ijkio_manager_io_read(IjkIOManagerContext *h, unsigned char *buf, int size); int64_t ijkio_manager_io_seek(IjkIOManagerContext *h, int64_t offset, int whence); int ijkio_manager_io_close(IjkIOManagerContext *h); #endif // IJKAVFORMAT_IJKIOMANAGER_H ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijkioprotocol.c ================================================ /* * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Raymond Zheng * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijkioprotocol.h" #include #include extern IjkURLProtocol ijkio_ffio_protocol; #ifdef __ANDROID__ extern IjkURLProtocol ijkio_androidio_protocol; #endif extern IjkURLProtocol ijkio_cache_protocol; extern IjkURLProtocol ijkio_httphook_protocol; int ijkio_alloc_url(IjkURLContext **ph, const char *url) { if (!ph) { return -1; } IjkURLContext *h = NULL; if (!strncmp(url, "cache:", strlen("cache:"))) { h = (IjkURLContext *)calloc(1, sizeof(IjkURLContext)); h->prot = &ijkio_cache_protocol; h->priv_data = calloc(1, ijkio_cache_protocol.priv_data_size); } else if (!strncmp(url, "ffio:", strlen("ffio:"))) { h = (IjkURLContext *)calloc(1, sizeof(IjkURLContext)); h->prot = &ijkio_ffio_protocol; h->priv_data = calloc(1, ijkio_ffio_protocol.priv_data_size); } else if (!strncmp(url, "httphook:", strlen("httphook:"))) { h = (IjkURLContext *)calloc(1, sizeof(IjkURLContext)); h->prot = &ijkio_httphook_protocol; h->priv_data = calloc(1, ijkio_httphook_protocol.priv_data_size); } #ifdef __ANDROID__ else if (!strncmp(url, "androidio:", strlen("androidio:"))) { h = (IjkURLContext *)calloc(1, sizeof(IjkURLContext)); h->prot = &ijkio_androidio_protocol; h->priv_data = calloc(1, ijkio_androidio_protocol.priv_data_size); } #endif else { return -1; } *ph = h; return 0; } ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijkioprotocol.h ================================================ /* * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Raymond Zheng * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijkiourl.h" int ijkio_alloc_url(IjkURLContext **inner, const char *url); ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijkiourl.h ================================================ /* * This file is part of ijkplayer. * * ijkplayer 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. * * ijkplayer 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 FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * unbuffered private I/O API */ #ifndef IJKAVFORMAT_IJKIOURL_H #define IJKAVFORMAT_IJKIOURL_H #include #include "ijkplayer/ijkavutil/ijkdict.h" #include "ijkioapplication.h" struct IjkURLProtocol; #define IJKURL_PAUSED 0x10 #define IJKURL_STARTED 0x20 typedef struct IjkURLContext { const struct IjkURLProtocol *prot; IjkIOApplicationContext *ijkio_app_ctx; int state; void *priv_data; } IjkURLContext; typedef struct IjkURLProtocol { const char *name; int (*url_open2)(IjkURLContext *h, const char *url, int flags, IjkAVDictionary **options); int (*url_read)( IjkURLContext *h, unsigned char *buf, int size); int64_t (*url_seek)( IjkURLContext *h, int64_t pos, int whence); int (*url_close)(IjkURLContext *h); int (*url_pause)(IjkURLContext *h); // option int (*url_resume)(IjkURLContext *h); // option int priv_data_size; int flags; } IjkURLProtocol; #endif // IJKAVFORMAT_IJKIOURL_H ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijkiourlhook.c ================================================ /* * Copyright (c) 2015 Bilibili * Copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "ijkiourl.h" #include "ijkioprotocol.h" #include "ijkplayer/ijkavutil/ijkutils.h" #include "libavutil/log.h" #include "libavutil/application.h" typedef struct Context { IjkURLContext *inner; int64_t logical_pos; int64_t logical_size; int io_error; AVAppIOControl app_io_ctrl; const char *scheme; const char *inner_scheme; IjkAVIOInterruptCB *ijkio_interrupt_callback; /* options */ int inner_flags; IjkAVDictionary *inner_options; int segment_index; int64_t test_fail_point; int64_t test_fail_point_next; int abort_request; AVApplicationContext *app_ctx; IjkIOApplicationContext *ijkio_app_ctx; } Context; static int ijkio_cache_check_interrupt(IjkURLContext *h) { Context *c = h->priv_data; if (!c) return 1; if (c->abort_request) return 1; if (c->ijkio_interrupt_callback && c->ijkio_interrupt_callback->callback && c->ijkio_interrupt_callback->callback(c->ijkio_interrupt_callback->opaque)) { c->abort_request = 1; } if (c->abort_request) return 1; return c->abort_request; } static int ijkio_urlhook_call_inject(IjkURLContext *h) { Context *c = h->priv_data; int ret = 0; if (ijkio_cache_check_interrupt(h)) { ret = IJKAVERROR_EXIT; goto fail; } if (c->app_ctx) { AVAppIOControl control_data_backup = c->app_io_ctrl; c->app_io_ctrl.is_handled = 0; c->app_io_ctrl.is_url_changed = 0; ret = av_application_on_io_control(c->app_ctx, AVAPP_CTRL_WILL_HTTP_OPEN, &c->app_io_ctrl); if (ret || !c->app_io_ctrl.url[0]) { ret = IJKAVERROR_EXIT; goto fail; } AVAppIOControl user_control_data = c->app_io_ctrl; if (strncmp(c->app_io_ctrl.url, "ffio:", strlen("ffio:"))) { snprintf(c->app_io_ctrl.url, sizeof(c->app_io_ctrl.url), "%s%s", "ffio:", user_control_data.url); } if (!c->app_io_ctrl.is_url_changed && strcmp(control_data_backup.url, c->app_io_ctrl.url)) { // force a url compare c->app_io_ctrl.is_url_changed = 1; } av_log(NULL, AV_LOG_INFO, "%s %s (%s)\n", h->prot->name, c->app_io_ctrl.url, c->app_io_ctrl.is_url_changed ? "changed" : "remain"); } if (ijkio_cache_check_interrupt(h)) { ret = IJKAVERROR_EXIT; av_log(NULL, AV_LOG_ERROR, "%s %s (%s)\n", h->prot->name, c->app_io_ctrl.url, c->app_io_ctrl.is_url_changed ? "changed" : "remain"); goto fail; } fail: return ret; } static int ijkio_urlhook_reconnect(IjkURLContext *h, IjkAVDictionary *extra) { Context *c = h->priv_data; int ret = 0; IjkURLContext *new_url = NULL; IjkAVDictionary *inner_options = NULL; c->test_fail_point_next += c->test_fail_point; assert(c->inner_options); ijk_av_dict_copy(&inner_options, c->inner_options, 0); if (extra) ijk_av_dict_copy(&inner_options, extra, 0); ret = ijkio_alloc_url(&new_url, c->app_io_ctrl.url); new_url->ijkio_app_ctx = c->ijkio_app_ctx; if (ret) goto fail0; ret = new_url->prot->url_open2(new_url, c->app_io_ctrl.url, c->inner_flags, &inner_options); if (ret) goto fail1; if (c->inner) { c->inner->prot->url_close(c->inner); ijk_av_freep(&c->inner->priv_data); ijk_av_freep(&c->inner); } c->inner = new_url; c->logical_pos = c->inner->prot->url_seek(c->inner, 0, SEEK_CUR); c->logical_size = c->inner->prot->url_seek(c->inner, 0, IJKAVSEEK_SIZE); c->io_error = 0; if (inner_options) { ijk_av_dict_free(&inner_options); } return ret; fail1: ijk_av_freep(&new_url->priv_data); ijk_av_freep(&new_url); fail0: if (inner_options) { ijk_av_dict_free(&inner_options); } return ret; } static int ijkio_urlhook_init(IjkURLContext *h, const char *arg, int flags, IjkAVDictionary **options) { Context *c = h->priv_data; int ret = 0; // ijk_av_strstart(arg, c->scheme, &arg); c->inner_flags = flags; if (options) ijk_av_dict_copy(&c->inner_options, *options, 0); ijk_av_dict_set_intptr(&c->inner_options, "ijkapplication", (uintptr_t )c->app_ctx, 0); ijk_av_dict_set_int(&c->inner_options, "ijkinject-segment-index", c->segment_index, 0); c->app_io_ctrl.size = sizeof(c->app_io_ctrl); c->app_io_ctrl.segment_index = c->segment_index; c->app_io_ctrl.retry_counter = 0; snprintf(c->app_io_ctrl.url, sizeof(c->app_io_ctrl.url), "%s", arg); return ret; } static int ijkio_httphook_close(IjkURLContext *h) { Context *c = h->priv_data; int ret = 0; if (!c || !c->inner || !c->inner->prot) return IJKAVERROR(ENOSYS); ret = c->inner->prot->url_close(c->inner); if (c->inner_options) { ijk_av_dict_free(&c->inner_options); } ijk_av_freep(&c->inner->priv_data); ijk_av_freep(&c->inner); return ret; } static int ijkio_urlhook_read(IjkURLContext *h, unsigned char *buf, int size) { Context *c = h->priv_data; int ret = 0; if (c->io_error < 0) return c->io_error; if (c->test_fail_point_next > 0 && c->logical_pos >= c->test_fail_point_next) { av_log(NULL, AV_LOG_ERROR, "test fail point:%"PRId64"\n", c->test_fail_point_next); c->io_error = IJKAVERROR(EIO); return IJKAVERROR(EIO); } ret = c->inner->prot->url_read(c->inner, buf, size); if (ret > 0) c->logical_pos += ret; else c->io_error = ret; return ret; } static int64_t ijkio_urlhook_seek(IjkURLContext *h, int64_t pos, int whence) { Context *c = h->priv_data; int64_t seek_ret = 0; seek_ret = c->inner->prot->url_seek(c->inner, pos, whence); if (seek_ret < 0) { c->io_error = (int)seek_ret; return seek_ret; } c->logical_pos = seek_ret; if (c->test_fail_point) c->test_fail_point_next = c->logical_pos + c->test_fail_point; c->io_error = 0; return seek_ret; } static int ijkio_httphook_reconnect_at(IjkURLContext *h, int64_t offset) { int ret = 0; IjkAVDictionary *extra_opts = NULL; ijk_av_dict_set_int(&extra_opts, "offset", offset, 0); ijk_av_dict_set_int(&extra_opts, "dns_cache_clear", 1, 0); ret = ijkio_urlhook_reconnect(h, extra_opts); ijk_av_dict_free(&extra_opts); return ret; } static int ijkio_httphook_open(IjkURLContext *h, const char *arg, int flags, IjkAVDictionary **options) { Context *c = h->priv_data; int ret = 0; IjkAVDictionaryEntry *t = NULL; c->ijkio_app_ctx = h->ijkio_app_ctx; c->ijkio_interrupt_callback = h->ijkio_app_ctx->ijkio_interrupt_callback; c->app_ctx = (AVApplicationContext *)ijk_av_dict_get_intptr(*options, "ijkapplication"); if (!c->app_ctx) { goto fail; } t = ijk_av_dict_get(*options, "ijkinject-segment-index", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { c->segment_index = (int)strtoll(t->value, NULL, 10); } t = ijk_av_dict_get(*options, "ijkhttphook-test-fail-point", NULL, IJK_AV_DICT_MATCH_CASE); if (t) { c->test_fail_point = (int64_t)strtoll(t->value, NULL, 10); } ijk_av_strstart(arg, "httphook:", &arg); ret = ijkio_urlhook_init(h, arg, flags, options); if (ret) goto fail; ret = ijkio_urlhook_call_inject(h); if (ret) goto fail; ret = ijkio_urlhook_reconnect(h, NULL); while (ret && c->abort_request == 0) { int inject_ret = 0; switch (ret) { case IJKAVERROR_EXIT: goto fail; } c->app_io_ctrl.retry_counter++; inject_ret = ijkio_urlhook_call_inject(h); if (inject_ret) { ret = IJKAVERROR_EXIT; goto fail; } if (!c->app_io_ctrl.is_handled) goto fail; av_log(NULL, AV_LOG_INFO, "%s: will reconnect at start\n", __func__); ret = ijkio_httphook_reconnect_at(h, 0); av_log(NULL, AV_LOG_INFO, "%s: did reconnect at start: %d\n", __func__, ret); } fail: return ret; } static int ijkio_httphook_read(IjkURLContext *h, unsigned char *buf, int size) { Context *c = h->priv_data; int ret = 0; int active_reconnect = c->ijkio_app_ctx->active_reconnect; c->app_io_ctrl.retry_counter = 0; if (active_reconnect == 0) { ret = ijkio_urlhook_read(h, buf, size); } while ((active_reconnect || ret < 0) && c->logical_pos < c->logical_size && c->abort_request == 0) { switch (ret) { case IJKAVERROR_EXIT: goto fail; } c->app_io_ctrl.retry_counter++; ret = ijkio_urlhook_call_inject(h); c->ijkio_app_ctx->active_reconnect = active_reconnect = 0; if (ret) goto fail; if (!c->app_io_ctrl.is_handled) goto fail; av_log(NULL, AV_LOG_INFO, "%s: will reconnect(%d) at %"PRId64"\n", __func__, c->app_io_ctrl.retry_counter, c->logical_pos); ret = ijkio_httphook_reconnect_at(h, c->logical_pos); av_log(NULL, AV_LOG_INFO, "%s: did reconnect(%d) at %"PRId64": %d\n", __func__, c->app_io_ctrl.retry_counter, c->logical_pos, ret); if (ret < 0) continue; ret = ijkio_urlhook_read(h, buf, size); } fail: if (ret <= 0) { c->io_error = ret; } return ret; } static int64_t ijkio_httphook_reseek_at(IjkURLContext *h, int64_t pos, int whence, int force_reconnect) { Context *c = h->priv_data; int ret = 0; if (!force_reconnect) return ijkio_urlhook_seek(h, pos, whence); if (whence == SEEK_CUR) pos += c->logical_pos; else if (whence == SEEK_END) pos += c->logical_size; else if (whence != SEEK_SET) return IJKAVERROR(EINVAL); if (pos < 0) return IJKAVERROR(EINVAL); ret = ijkio_httphook_reconnect_at(h, pos); if (ret) { c->io_error = ret; return ret; } c->io_error = 0; return c->logical_pos; } static int64_t ijkio_httphook_seek(IjkURLContext *h, int64_t pos, int whence) { Context *c = h->priv_data; int ret = 0; int64_t seek_ret = -1; if (whence == IJKAVSEEK_SIZE) return c->logical_size; else if ((whence == SEEK_CUR && pos == 0) || (whence == SEEK_SET && pos == c->logical_pos)) return c->logical_pos; else if ((c->logical_size < 0 && whence == SEEK_END)) return IJKAVERROR(ENOSYS); c->app_io_ctrl.retry_counter = 0; ret = ijkio_urlhook_call_inject(h); if (ret) { ret = IJKAVERROR_EXIT; goto fail; } seek_ret = ijkio_httphook_reseek_at(h, pos, whence, c->app_io_ctrl.is_url_changed); while (seek_ret < 0 && c->abort_request == 0) { switch (seek_ret) { case IJKAVERROR_EXIT: case IJKAVERROR_EOF: goto fail; } c->app_io_ctrl.retry_counter++; ret = ijkio_urlhook_call_inject(h); if (ret) { ret = IJKAVERROR_EXIT; goto fail; } if (!c->app_io_ctrl.is_handled) goto fail; av_log(NULL, AV_LOG_INFO, "%s: will reseek(%d) at pos=%"PRId64", whence=%d\n", __func__, c->app_io_ctrl.retry_counter, pos, whence); seek_ret = ijkio_httphook_reseek_at(h, pos, whence, c->app_io_ctrl.is_url_changed); av_log(NULL, AV_LOG_INFO, "%s: did reseek(%d) at pos=%"PRId64", whence=%d: %"PRId64"\n", __func__, c->app_io_ctrl.retry_counter, pos, whence, seek_ret); } if (c->test_fail_point) c->test_fail_point_next = c->logical_pos + c->test_fail_point; c->io_error = 0; if (seek_ret < 0) { return seek_ret; } return c->logical_pos; fail: return ret; } static int ijkio_httphook_pause(IjkURLContext *h) { Context *c = h->priv_data; int ret = 0; if (!c || !c->inner || !c->inner->prot) return IJKAVERROR(ENOSYS); c->abort_request = 1; if (c->inner->prot->url_pause) { ret = c->inner->prot->url_pause(c->inner); } return ret; } static int ijkio_httphook_resume(IjkURLContext *h) { Context *c = h->priv_data; int ret = 0; if (!c || !c->inner || !c->inner->prot) return IJKAVERROR(ENOSYS); if (c->inner->prot->url_resume) { ret = c->inner->prot->url_resume(c->inner); if (ret != 0) { return ret; } } c->abort_request = 0; return ret; } IjkURLProtocol ijkio_httphook_protocol = { .name = "ijkiohttphook", .url_open2 = ijkio_httphook_open, .url_read = ijkio_httphook_read, .url_seek = ijkio_httphook_seek, .url_close = ijkio_httphook_close, .url_pause = ijkio_httphook_pause, .url_resume = ijkio_httphook_resume, .priv_data_size = sizeof(Context), }; ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijklas.c ================================================ /** * @file * LAS demuxer * https://github.com/KwaiVideoTeam/las */ #include #include #ifdef __ANDROID__ #include #endif #ifdef __APPLE__ #include "TargetConditionals.h" #endif #include "libavutil/avstring.h" #include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" #include "libavutil/opt.h" #include "libavutil/dict.h" #include "libavutil/time.h" #include "libavformat/avformat.h" #include "libavformat/url.h" #include "libavformat/avio_internal.h" #include "libavformat/id3v2.h" #include "libavformat/flv.h" #include "ijksdl/ijksdl_thread.h" #include "ijksdl/ijksdl_mutex.h" #include "cJSON.h" #include "ff_ffplay_def.h" #include "ijklas.h" #define LAS_ERROR_BASE (-30000) #define LAS_ERROR_MUTEX_CREATE (-1 + LAS_ERROR_BASE) #define LAS_ERROR_THREAD_CREATE (-2 + LAS_ERROR_BASE) #define LAS_ERROR_MANIFEST_JSON (-3 + LAS_ERROR_BASE) #define LAS_ERROR_ADAPT_CONFIG_JSON (-4 + LAS_ERROR_BASE) #define LAS_ERROR_INVALID_REP_INDEX (-6 + LAS_ERROR_BASE) #define LAS_ERROR_SOCKET_CLOSED_BY_PEER (-11 + LAS_ERROR_BASE) #define LAS_ERROR_GET_WHOLE_TAG (-12 + LAS_ERROR_BASE) #define LAS_ERROR_ABORT_BY_USER (-14 + LAS_ERROR_BASE) #define LAS_ERROR_ABR_HISTORY_DATA_JSON (-15 + LAS_ERROR_BASE) #define LAS_ERROR_COND_CREATE (-16 + LAS_ERROR_BASE) #define INITIAL_BUFFER_SIZE 32768 #define FLV_HEADER_LEN 9 #define TAG_HEADER_LEN 11 #define PRE_TAG_SIZE_LEN 4 //las 2.0 Tag based #define AV_TAG_HEADER_LEN 16 // 11+1+1+3, 1 bytes for av parameters, 1 bytes for AVCPacketType, 3 bytes for CompositionTime #define TIME_ALGO_UPDATE_INTERVAL_MS (500) #define INIT_BUFFER_THRESHOLD_MAX_MS (8*1000) #define MAX_BUFFER_TIME 10000 #define MAX_STATE_CNT 30 #define NALU_HEAD_LEN 4 #define H264_NAL_SPS 7 #define H264_NAL_PPS 8 typedef struct AdaptiveConfig { int32_t buffer_init; double stable_buffer_diff_threshold_second; int32_t stable_buffer_interval_ms; int32_t generate_speed_gap_ms; int32_t buffer_check_interval_ms; double smoothed_speed_utilization_ratio; double small_speed_to_bitrate_ratio; double enough_speed_to_bitrate_ratio; double buffer_lower_limit_second; int32_t recent_buffered_size; double smoothed_speed_ratio; } AdaptiveConfig; typedef struct MultiRateAdaption { int32_t n_bitrates; int32_t bitrate_table_origin_order[MAX_STREAM_NUM]; int32_t disable_adaptive_table[MAX_STREAM_NUM]; int32_t next_expected_rep_index; struct PlayList* playlist; unsigned session_id; // algorithm related AdaptiveConfig conf; double past_buffer[MAX_STATE_CNT]; int64_t buffer_index; int32_t levels[MAX_STREAM_NUM]; int32_t current; int64_t stable_buffer_start_time; double generated_speed; double last_check_buffer; int64_t last_speed; int32_t buffer_init; } MultiRateAdaption; typedef struct FlvTag { uint8_t* buf; uint32_t tag_size; uint32_t buf_write_offset; uint32_t buf_read_offset; uint32_t av_tag_ts; enum FlvTagType type; int rep_index; int audio_only; int switch_index; } FlvTag; typedef struct Representation { char url[MAX_URL_SIZE]; int id; int bitrate; int disabled_from_adaptive; int default_selected; int index; } Representation; typedef struct AdaptationSet { int duration; Representation* representations[MAX_STREAM_NUM]; int n_representation; } AdaptationSet; typedef struct TagListNode { FlvTag tag; struct TagListNode* next; } TagListNode; typedef struct TagQueue { TagListNode* first_tag, *last_tag; int nb_tags; uint32_t last_video_ts; int64_t total_tag_bytes; int abort_request; SDL_mutex* mutex; SDL_cond* cond; } TagQueue; typedef struct GopReader { // real read context char realtime_url[MAX_URL_SIZE]; URLContext* input; int abort_request; int64_t last_gop_start_ts; int rep_index; int is_audio_only; int switch_index; AVFormatContext* parent; } GopReader; typedef struct PlayList { struct AdaptationSet adaptation_set; AVFormatContext* outermost_ctx; // demuxer related AVFormatContext* parent; uint8_t* read_buffer; AVIOContext pb; AVFormatContext* ctx; AVPacket pkt; int cur_rep_index; int cur_switch_index; int stream_index_map[MAX_STREAM_NUM]; int error_code; int read_abort_request; SDL_Thread _read_thread; SDL_Thread* read_thread; SDL_Thread _algo_thread; SDL_Thread* algo_thread; SDL_cond* algo_cond; SDL_mutex* rw_mutex; SDL_mutex* reading_tag_mutex; // las_mutex is privately used inside of #pragma PlayListLock's setters and getters SDL_mutex* las_mutex; MultiRateAdaption multi_rate_adaption; GopReader gop_reader; FlvTag reading_tag; TagQueue tag_queue; // cur playlist Qos LasStatistic* las_statistic; bool is_stream_ever_opened; int64_t bytes_read; unsigned session_id; FFTrackCacheStatistic* video_cache; FFTrackCacheStatistic* audio_cache; } PlayList; typedef struct LasContext { AVClass* class; // the outermost context AVFormatContext* ctx; AVIOInterruptCB* interrupt_callback; char* user_agent; ///< holds HTTP user agent set as an AVOption to the HTTP protocol context char* cookies; ///< holds HTTP cookie values set in either the initial response or as an AVOption to the HTTP protocol context char* headers; ///< holds HTTP headers set as an AVOption to the HTTP protocol context char* http_proxy; ///< holds the address of the HTTP proxy server char* server_ip; ///< holds the HTTP server ip char* manifest_string; int64_t network; char* abr_history_data; char* live_adapt_config; AVDictionary* avio_opts; // all info of las is in it PlayList playlist; LasStatistic las_statistic; unsigned session_id; int64_t video_cache_ptr; int64_t audio_cache_ptr; int las_switch_mode; int64_t first_audio_packet_pts; int block_duration; int audio_only_request; int audio_only_response; bool stream_reopened; } LasContext; #pragma mark common util inline static int64_t get_current_time_ms() { return av_gettime_relative() / 1000; } #pragma mark log util #define LOG_THREAD 1 // ------------------------------------ log util start------------------------------------ static inline void _log(unsigned session_id, const char* func_name, int av_log_level, ...) { va_list args; va_start(args, av_log_level); const char* fmt = va_arg(args, const char*); char tmp[1024] = {0}; vsprintf(tmp, fmt, args); va_end(args); #if LOG_THREAD av_log(NULL, av_log_level, "[%u][las][%s] %s\n", session_id, func_name, tmp); #endif } #define log_debug_tag(session_id, av_log_level, ...) _log(session_id, __func__, av_log_level, __VA_ARGS__) #define log_debug(...) log_debug_tag(playlist->session_id, AV_LOG_DEBUG, __VA_ARGS__) #define log_info(...) log_debug_tag(playlist->session_id, AV_LOG_INFO, __VA_ARGS__) #define log_error(...) log_debug_tag(playlist->session_id, AV_LOG_ERROR, __VA_ARGS__) #define algo_debug(...) log_debug_tag(thiz->session_id, AV_LOG_DEBUG, __VA_ARGS__) #define algo_info(...) log_debug_tag(thiz->session_id, AV_LOG_INFO, __VA_ARGS__) #define algo_error(...) log_debug_tag(thiz->session_id, AV_LOG_ERROR, __VA_ARGS__) #pragma mark PlayerControl int get_switch_mode(AVFormatContext* format) { LasContext* c = format->priv_data; return c->las_switch_mode; } int64_t get_first_audio_packet_pts(AVFormatContext* format) { LasContext* c = format->priv_data; return c->first_audio_packet_pts; } int get_audio_only_request(AVFormatContext* format) { LasContext* c = format->priv_data; return c->audio_only_request; } void set_audio_only_response(AVFormatContext* format, int audio_only) { LasContext* c = format->priv_data; c->audio_only_response = audio_only; } void set_stream_reopened(AVFormatContext* format, bool stream_reopened) { LasContext* c = format->priv_data; c->stream_reopened = stream_reopened; } int64_t get_cache_duration_ms(FFTrackCacheStatistic* cache) { if (cache) { return cache->duration; } return 0; } #pragma mark PlayListLock static int64_t get_bytes_read(PlayList* p) { SDL_LockMutex(p->las_mutex); int64_t ret = p->bytes_read; SDL_UnlockMutex(p->las_mutex); return ret; } static void add_bytes_read(PlayList* p, int64_t bytes_read) { SDL_LockMutex(p->las_mutex); p->bytes_read += bytes_read; SDL_UnlockMutex(p->las_mutex); } static void algo_cond_wait(PlayList* p) { SDL_LockMutex(p->las_mutex); SDL_CondWaitTimeout(p->algo_cond, p->las_mutex, TIME_ALGO_UPDATE_INTERVAL_MS); SDL_UnlockMutex(p->las_mutex); } static void algo_cond_signal(PlayList* p) { SDL_LockMutex(p->las_mutex); SDL_CondSignal(p->algo_cond); SDL_UnlockMutex(p->las_mutex); } #pragma mark TagQueue static int FlvTag_has_consume_all_data_l(struct FlvTag* tag) { if (tag->tag_size <= 0) { return 1; } // if reader->buf_size = 0 or reader->gop_size = 0, means that the reader is going to download data ,but not stared yet int ret = (tag->tag_size == tag->buf_read_offset); return ret; } int FlvTag_get_data_from_buffer(PlayList* playlist, struct FlvTag* tag, uint8_t* buf, uint32_t buf_size) { if (FlvTag_has_consume_all_data_l(tag)) { log_error("FlvTag_has_consume_all_data_l, illegal state"); return -1; } int to_read = FFMIN(buf_size, tag->buf_write_offset - tag->buf_read_offset); memcpy(buf, tag->buf + tag->buf_read_offset, to_read); tag->buf_read_offset += to_read; return to_read; } int FlvTag_alloc_buffer(PlayList* playlist, struct FlvTag* tag, int32_t tag_size) { tag->buf = av_malloc(tag_size); if (!tag->buf) { log_error("alloc tag->buf fail"); return AVERROR(ENOMEM); } tag->tag_size = tag_size; tag->buf_read_offset = tag->buf_write_offset = 0; return 0; } void FlvTag_dealloc(struct FlvTag* tag) { if (!tag) { return; } if (tag->buf) { av_freep(&tag->buf); } tag->tag_size = tag->buf_read_offset = tag->buf_write_offset = 0; } static int TagQueue_init(PlayList* playlist, TagQueue* q) { memset(q, 0, sizeof(TagQueue)); q->mutex = SDL_CreateMutex(); if (!q->mutex) { log_error("SDL_CreateMutex():fail"); return AVERROR(ENOMEM); } q->cond = SDL_CreateCond(); if (!q->cond) { log_error("SDL_CreateCond():fail"); return AVERROR(ENOMEM); } q->abort_request = 1; return 0; } static void TagQueue_start(TagQueue* q) { SDL_LockMutex(q->mutex); q->abort_request = 0; SDL_UnlockMutex(q->mutex); } static int TagQueue_put_private(TagQueue* q, FlvTag* tag) { TagListNode* tag1; if (q->abort_request) return -1; tag1 = av_malloc(sizeof(TagListNode)); if (!tag1) return -1; tag1->tag = *tag; tag1->next = NULL; if (!q->last_tag) q->first_tag = tag1; else q->last_tag->next = tag1; q->last_tag = tag1; q->nb_tags++; if (tag->type == FLV_TAG_TYPE_VIDEO) q->last_video_ts = tag->av_tag_ts; q->total_tag_bytes += tag->tag_size; SDL_CondSignal(q->cond); return 0; } static int TagQueue_put(TagQueue* q, FlvTag* tag) { int ret; SDL_LockMutex(q->mutex); ret = TagQueue_put_private(q, tag); SDL_UnlockMutex(q->mutex); if (ret < 0) { FlvTag_dealloc(tag); } return ret; } static int TagQueue_peek_first_video_ts(TagQueue* q) { TagListNode* tag_node, *tag_node1; int ret = -1; SDL_LockMutex(q->mutex); for (tag_node = q->first_tag; tag_node; tag_node = tag_node1) { tag_node1 = tag_node->next; if (tag_node->tag.type == FLV_TAG_TYPE_VIDEO) { ret = tag_node->tag.av_tag_ts; break; } } SDL_UnlockMutex(q->mutex); return ret; } /* return < 0 if aborted, 0 if no tag and > 0 if has tag. */ static int TagQueue_get(TagQueue* q, FlvTag* tag, int block) { TagListNode* tag_node; int ret; SDL_LockMutex(q->mutex); for (;;) { if (q->abort_request) { ret = -1; break; } tag_node = q->first_tag; if (tag_node) { q->first_tag = tag_node->next; if (!q->first_tag) q->last_tag = NULL; q->nb_tags--; *tag = tag_node->tag; // q->total_tag_bytes -= tag->tag_size; av_free(tag_node); ret = 1; break; } else if (!block) { ret = 0; break; } else { SDL_CondWait(q->cond, q->mutex); } } SDL_UnlockMutex(q->mutex); return ret; } static void TagQueue_flush(TagQueue* q) { TagListNode* tag_node, *tag_node_next; SDL_LockMutex(q->mutex); for (tag_node = q->first_tag; tag_node; tag_node = tag_node_next) { tag_node_next = tag_node->next; FlvTag_dealloc(&tag_node->tag); av_freep(&tag_node); } q->last_tag = NULL; q->first_tag = NULL; q->nb_tags = 0; q->last_video_ts = 0; SDL_UnlockMutex(q->mutex); } static void TagQueue_destroy(TagQueue* q) { TagQueue_flush(q); SDL_DestroyMutex(q->mutex); SDL_DestroyCond(q->cond); } static void TagQueue_abort(TagQueue* q) { SDL_LockMutex(q->mutex); q->abort_request = 1; SDL_CondSignal(q->cond); SDL_UnlockMutex(q->mutex); } static int32_t TagQueue_get_duration_ms(TagQueue* q) { int32_t ret = 0; int first_ts = TagQueue_peek_first_video_ts(q); if (first_ts >= 0) { SDL_LockMutex(q->mutex); ret = q->last_video_ts - first_ts; SDL_UnlockMutex(q->mutex); } return ret > 0 ? ret : 0; } static int64_t TagQueue_get_total_bytes(TagQueue* q) { int64_t ret = 0; SDL_LockMutex(q->mutex); ret = q->total_tag_bytes; SDL_UnlockMutex(q->mutex); return ret > 0 ? ret : 0; } #pragma mark LasStatistic int32_t get_video_bitrate(MultiRateAdaption* thiz) { return thiz->levels[thiz->current]; } int32_t get_buffer_current(MultiRateAdaption* thiz) { return thiz->last_check_buffer; } int32_t get_bw_fragment(MultiRateAdaption* thiz) { return thiz->last_speed; } void LasStatistic_reset(LasStatistic* stat) { if (stat) { memset(stat, 0, sizeof(LasStatistic)); } } void LasStatistic_init(LasStatistic* stat, PlayList* playlist) { LasStatistic_reset(stat); stat->flv_nb = playlist->adaptation_set.n_representation; for (int i = 0; i < playlist->adaptation_set.n_representation; i++) { stat->flvs[i].total_bandwidth_kbps = playlist->adaptation_set.representations[i]->bitrate; strncpy(stat->flvs[i].url, playlist->adaptation_set.representations[i]->url, MAX_URL_SIZE - 1); } } void LasStatistic_on_rep_http_url(LasStatistic* stat, char* request_url) { if (stat) { strncpy(stat->cur_playing_url, request_url, MAX_URL_SIZE - 1); } } void LasStatistic_on_rep_http_start(LasStatistic* stat, int64_t start_time) { if (stat) { stat->cur_rep_read_start_time = start_time; } } void LasStatistic_on_rep_http_open(LasStatistic* stat, int64_t open_time) { if (stat) { stat->cur_rep_http_open_time = open_time; } } void LasStatistic_on_rep_flv_header(LasStatistic* stat, int64_t header_time) { if (stat) { stat->cur_rep_read_header_time = header_time; } } void LasStatistic_on_rep_http_first_data(LasStatistic* stat, int64_t first_data_time) { if (stat) { stat->cur_rep_first_data_time = first_data_time; } } void LasStatistic_on_rep_start_timestamp(PlayList* playlist, int64_t start_time, int64_t request_time) { LasStatistic* stat = playlist->las_statistic; if (stat) { stat->cur_rep_start_time = start_time; stat->rep_switch_gap_time = request_time <= 0 ? 0 : start_time - request_time; log_info("rep_switch_gap_time=%lld", stat->rep_switch_gap_time); } } void LasStatistic_on_rep_read_error(LasStatistic* stat, int error) { if (stat) { stat->cur_rep_http_reading_error = error; } } void LasStatistic_on_read_packet(LasStatistic* stat, PlayList* playlist) { if (stat && playlist) { stat->cur_decoding_flv_index = playlist->cur_rep_index; } } void LasStatistic_on_buffer_time(LasStatistic* stat, PlayList* playlist) { if (stat && playlist) { stat->cached_a_dur_ms = get_cache_duration_ms(playlist->audio_cache); stat->cached_v_dur_ms = get_cache_duration_ms(playlist->video_cache);; stat->cached_tag_dur_ms = TagQueue_get_duration_ms(&playlist->tag_queue); log_info("a_buffer_time_ms=%lld, v_buffer_time_ms=%lld, CachedTagQueue_ms=%lld", stat->cached_a_dur_ms, stat->cached_v_dur_ms, stat->cached_tag_dur_ms); } } void LasStatistic_on_adaption_adapted(PlayList* playlist, MultiRateAdaption* adaption) { LasStatistic* stat = playlist->las_statistic; if (stat && adaption) { stat->bitrate_downloading = get_video_bitrate(adaption); } } void LasStatistic_on_bytes_downloaded(LasStatistic* stat, int64_t bytes) { if (stat) { stat->total_bytes_read += bytes; } } void LasStatistic_on_bandwidth_update(PlayList* playlist, MultiRateAdaption* adaption) { LasStatistic* stat = playlist->las_statistic; if (stat && adaption) { stat->bandwidth_fragment = get_bw_fragment(adaption); stat->current_buffer_ms = get_buffer_current(adaption); } } void LasStatistic_on_rep_switch_count(LasStatistic* stat, PlayList* playlist) { if (stat) { stat->rep_switch_cnt++; stat->switch_point_a_buffer_ms = get_cache_duration_ms(playlist->audio_cache); stat->switch_point_v_buffer_ms = get_cache_duration_ms(playlist->video_cache); } } #pragma mark MultiRateAdaption int32_t local_index_2_rep_index(MultiRateAdaption* thiz, int32_t local_index) { int32_t rep_index = 0; for (int i = 0; i < thiz->n_bitrates; i++) { if (thiz->levels[local_index] == thiz->bitrate_table_origin_order[i]) { rep_index = i; break; } } return rep_index; } int32_t rep_index_2_local_index(MultiRateAdaption* thiz, int32_t rep_index) { int32_t local_index = 0; for (int i = 0; i < thiz->n_bitrates; i++) { if (thiz->levels[i] == thiz->bitrate_table_origin_order[rep_index]) { local_index = i; break; } } return local_index; } int get_local_index_from_bitrate(MultiRateAdaption* thiz, int64_t bitrate) { for (int32_t i = thiz->n_bitrates - 1; i > 0; --i) { if (thiz->levels[i] <= bitrate) { return i; } } return 0; } int compare(const void* a, const void* b) { return (*(int32_t*)a - * (int32_t*)b); } void RateAdaptConfig_default_init(AdaptiveConfig* config, PlayList* playlist) { config->buffer_init = 2000; config->stable_buffer_diff_threshold_second = 0.15; config->stable_buffer_interval_ms = 2000; config->generate_speed_gap_ms = 3000; config->buffer_check_interval_ms = 500; config->smoothed_speed_utilization_ratio = 0.8; config->small_speed_to_bitrate_ratio = 0.4; config->enough_speed_to_bitrate_ratio = 0.9; config->buffer_lower_limit_second = 0.6; config->recent_buffered_size = 16; config->smoothed_speed_ratio = 0.9; } // return index of optimized Representation void MultiRateAdaption_init(MultiRateAdaption* thiz, AdaptiveConfig config, struct PlayList* playlist) { if (!thiz || !playlist || playlist->adaptation_set.n_representation <= 0) { log_error("thiz:%p, p:%p", thiz, playlist); return; } thiz->conf = config; thiz->n_bitrates = 0; thiz->playlist = playlist; thiz->session_id = playlist->session_id; int64_t default_select_bitrate = -1; for (int i = 0; i < playlist->adaptation_set.n_representation; i++) { Representation* rep = playlist->adaptation_set.representations[i]; thiz->bitrate_table_origin_order[i] = rep->bitrate; thiz->levels[i] = rep->bitrate; if (rep->default_selected) { default_select_bitrate = rep->bitrate; } thiz->disable_adaptive_table[i] = rep->disabled_from_adaptive; thiz->n_bitrates++; } qsort(thiz->levels, thiz->n_bitrates, sizeof(int32_t), compare); thiz->buffer_init = config.buffer_init; if (thiz->buffer_init > INIT_BUFFER_THRESHOLD_MAX_MS) { thiz->buffer_init = INIT_BUFFER_THRESHOLD_MAX_MS; } if (default_select_bitrate >= 0) { thiz->current = get_local_index_from_bitrate(thiz, default_select_bitrate); } else { thiz->current = (thiz->n_bitrates - 1) / 2; } while (thiz->current >= thiz->n_bitrates) { thiz->current -= 1; } int switch_mode = get_switch_mode(playlist->outermost_ctx); if (switch_mode >= 0 && switch_mode < thiz->n_bitrates) { thiz->current = rep_index_2_local_index(thiz, switch_mode); } LasStatistic_on_adaption_adapted(thiz->playlist, thiz); thiz->next_expected_rep_index = local_index_2_rep_index(thiz, thiz->current); thiz->past_buffer[0] = 0.1; thiz->buffer_index = 1; thiz->stable_buffer_start_time = get_current_time_ms(); thiz->generated_speed = 0; thiz->last_check_buffer = 0; thiz->last_speed = 0; } bool update_stable_buffer(MultiRateAdaption* thiz, double buffered) { double diff = buffered - thiz->last_check_buffer; double diff_ratio = diff / buffered; double now = get_current_time_ms(); if (diff < -thiz->conf.stable_buffer_diff_threshold_second || diff_ratio < -0.2) { algo_info("buffer_diff_down: %.2fs, diff_ratio: %.2f", diff, diff_ratio); thiz->stable_buffer_start_time = FFMAX(now, thiz->stable_buffer_start_time); } if (diff > thiz->conf.stable_buffer_diff_threshold_second && now - thiz->stable_buffer_start_time + thiz->conf.buffer_check_interval_ms > thiz->conf.stable_buffer_interval_ms) { thiz->stable_buffer_start_time = FFMAX( now - thiz->conf.buffer_check_interval_ms * 2, thiz->stable_buffer_start_time + thiz->conf.buffer_check_interval_ms * 2 ); algo_info("buffer_diff_up: %.2fs", diff); } thiz->last_check_buffer = buffered; return now - thiz->stable_buffer_start_time > thiz->conf.stable_buffer_interval_ms; } /** * check buffer periodically */ void check_buffer(MultiRateAdaption* thiz, PlayList* playlist) { double buffered = get_cache_duration_ms(playlist->audio_cache) / 1000.0; bool is_buffer_stable = update_stable_buffer(thiz, buffered); if (is_buffer_stable && thiz->current + 1 < thiz->n_bitrates) { thiz->generated_speed = thiz->levels[thiz->current + 1]; } else { thiz->generated_speed = 0; } thiz->past_buffer[thiz->buffer_index % thiz->conf.recent_buffered_size] = buffered; thiz->buffer_index += 1; } int32_t quantization(MultiRateAdaption* thiz, double speed) { int32_t index = 0; for (int i = thiz->n_bitrates - 1; i >= 0; i--) { if (speed >= thiz->levels[i]) { index = i; break; } } return index; } double get_past_buffer(MultiRateAdaption* thiz) { double max_buffer = 0.1; for (int i = 0; i < thiz->conf.recent_buffered_size && i < thiz->buffer_index; ++i) { double buffered = thiz->past_buffer[(thiz->buffer_index - 1 - i) % thiz->conf.recent_buffered_size]; if (buffered > max_buffer) { max_buffer = buffered; } } return max_buffer; } double get_smoothed_speed(MultiRateAdaption* thiz, double speed) { if (thiz->last_speed > 0) { return speed * (1 - thiz->conf.smoothed_speed_ratio) + thiz->last_speed * thiz->conf.smoothed_speed_ratio; } return speed; } double get_predicted_buffer(MultiRateAdaption* thiz, double buffered) { double past_buffer = get_past_buffer(thiz); return buffered + (buffered - past_buffer); } double get_buffer_speed(MultiRateAdaption* thiz, double buffered) { double past_buffer = get_past_buffer(thiz); double buffer_speed_ratio = 1 + (buffered - past_buffer) / FFMAX(past_buffer, 0.1); return buffer_speed_ratio * thiz->levels[thiz->current]; } bool is_speed_too_small(MultiRateAdaption* thiz, double speed) { return speed / thiz->levels[thiz->current] < thiz->conf.small_speed_to_bitrate_ratio; } bool is_speed_enough(MultiRateAdaption* thiz, double speed) { return speed / thiz->levels[thiz->current] > thiz->conf.enough_speed_to_bitrate_ratio; } int32_t next_local_rate_index(MultiRateAdaption* thiz, double speed, double buffered) { if (thiz->buffer_index <= 1 && buffered <= 0.1) { algo_info("empty past buffer"); return thiz->current; } double buffer_speed = get_buffer_speed(thiz, buffered); double smoothed_speed = get_smoothed_speed(thiz, speed); algo_info("gop_speed: %.0f, smoothed_speed: %.0f", speed, smoothed_speed); double predicted_buffered = get_predicted_buffer(thiz, buffered); algo_info("buffer_speed: %.0f, buffered: %.1f, predicted_buffered: %.1f", buffer_speed, buffered, predicted_buffered); int32_t next_index = thiz->current; if (predicted_buffered < thiz->conf.buffer_lower_limit_second || is_speed_too_small(thiz, buffer_speed)) { next_index = FFMIN(thiz->current, quantization(thiz, buffer_speed)); } else if (is_speed_enough(thiz, buffer_speed)) { if (thiz->generated_speed > 0) { algo_info("generated_speed used"); next_index = quantization(thiz, thiz->generated_speed); thiz->generated_speed = 0; } else { next_index = quantization(thiz, smoothed_speed * thiz->conf.smoothed_speed_utilization_ratio); } next_index = FFMIN(thiz->current + 1, FFMAX(next_index, thiz->current)); } algo_info("target_index = %u", next_index); return next_index; } int32_t next_representation_id(MultiRateAdaption* thiz, int switch_mode, double speed, double buffered) { if (switch_mode >= 0 && switch_mode < thiz->n_bitrates) { thiz->current = rep_index_2_local_index(thiz, switch_mode); return switch_mode; } int local_index = next_local_rate_index(thiz, speed, buffered); int rep_index = local_index_2_rep_index(thiz, local_index); while (local_index > 0 && thiz->disable_adaptive_table[rep_index]) { local_index -= 1; rep_index = local_index_2_rep_index(thiz, local_index); } if (local_index != thiz->current) { thiz->stable_buffer_start_time = get_current_time_ms() + thiz->conf.generate_speed_gap_ms; } if (local_index < thiz->current) { thiz->generated_speed = 0; thiz->last_speed = speed; thiz->buffer_index = 1; thiz->past_buffer[0] = buffered; } else { thiz->last_speed = get_smoothed_speed(thiz, speed); } thiz->current = local_index; return rep_index; } #pragma mark Download static void update_options(char** dest, const char* name, void* src) { av_freep(dest); av_opt_get(src, name, 0, (uint8_t**)dest); if (*dest && !strlen(*dest)) av_freep(dest); } static int open_url(LasContext* c, URLContext** uc, const char* url, AVDictionary* opts, AVDictionary* opts2, PlayList* playlist) { AVDictionary* tmp = NULL; const char* proto_name = NULL; int ret; av_dict_copy(&tmp, opts, 0); av_dict_copy(&tmp, opts2, 0); if (!proto_name) { proto_name = avio_find_protocol_name(url); } if (!proto_name) return AVERROR_INVALIDDATA; ret = ffurl_open_whitelist(uc, url, AVIO_FLAG_READ, c->interrupt_callback, &tmp, c->ctx->protocol_whitelist, c->ctx->protocol_blacklist, c->ctx); if (ret >= 0) { log_info("ffurl_open_whitelist succeeds"); // update cookies on http response with setcookies. char* new_cookies = NULL; if (!(c->ctx->flags & AVFMT_FLAG_CUSTOM_IO)) av_opt_get(*uc, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)&new_cookies); if (new_cookies) { if (c->cookies) { av_free(c->cookies); } c->cookies = new_cookies; } // update cookies on http response with setcookies. URLContext* u = *uc; update_options(&c->cookies, "cookies", u->priv_data); av_dict_set(&opts, "cookies", c->cookies, 0); } else { log_error("ffurl_open_whitelist fails: %s(0x%x)", av_err2str(ret), ret); } av_dict_copy(&c->ctx->metadata, tmp, 0); av_dict_free(&tmp); return ret; } enum ReadFromURLMode { READ_NORMAL, READ_COMPLETE, }; /* * This is actually read from the network, there is no buffer. * There are 12 bytes of redundancy in a 4096-byte tcp packet at most, * and other non-4096-byte packets are not redundant. */ static int read_from_url(URLContext* url_ctx, uint8_t* buf, int buf_size, enum ReadFromURLMode mode, PlayList* playlist) { int ret; if (mode == READ_COMPLETE) ret = ffurl_read_complete(url_ctx, buf, buf_size); else ret = ffurl_read(url_ctx, buf, buf_size); if (ret > 0) { add_bytes_read(playlist, ret); LasStatistic_on_bytes_downloaded(playlist->las_statistic, ret); } return ret; } static int url_block_read(URLContext* url_ctx, uint8_t* buf, int want_len, PlayList* playlist) { int offset = 0; int ret; int remain = want_len; while (remain > 0) { ret = read_from_url(url_ctx, buf + offset, remain, READ_NORMAL, playlist); if (ret <= 0) { if (ret < 0) { log_error("read_from_url fails: %s(0x%x)", av_err2str(ret), ret); } else { //ffurl_read means socket was closed by peer ret = LAS_ERROR_SOCKET_CLOSED_BY_PEER; log_error("read_from_url socket closed by peer"); } return ret; } offset += ret; remain -= ret; } if (remain != 0) { log_error("block_read fail, remain:%d", remain); return -1; } else { return want_len; } } #pragma mark Gop void GopReader_init(GopReader* reader, Representation* rep, AVFormatContext* s, PlayList* playlist) { memset(reader->realtime_url, 0, sizeof(reader->realtime_url)); strcat(reader->realtime_url, rep->url); if (strstr(reader->realtime_url, "?") != NULL) { strcat(reader->realtime_url, "&"); } else { strcat(reader->realtime_url, "?"); } // Tag based char str_starttime[256] = "\0"; sprintf(str_starttime, "startPts=%" PRId64, reader->last_gop_start_ts); strcat(reader->realtime_url, str_starttime); if (reader->is_audio_only) { strcat(reader->realtime_url, "&audioOnly=true"); } reader->rep_index = rep->index; reader->parent = s; log_error("rep->index:%d, realtime_url:%s", rep->index, reader->realtime_url); } int GopReader_open_input(GopReader* reader, LasContext* c, PlayList* playlist) { AVDictionary* opts = NULL; int ret = 0; // broker prior HTTP options that should be consistent across requests av_dict_set(&opts, "user_agent", c->user_agent, 0); av_dict_set(&opts, "cookies", c->cookies, 0); av_dict_set(&opts, "headers", c->headers, 0); av_dict_set(&opts, "http_proxy", c->http_proxy, 0); av_dict_set(&opts, "seekable", "0", 0); LasStatistic_on_rep_http_url(c->playlist.las_statistic, reader->realtime_url); ret = open_url(c, &reader->input, reader->realtime_url, c->avio_opts, opts, playlist); av_dict_free(&opts); return ret; } void GopReader_close(GopReader* reader, PlayList* playlist) { if (reader->rep_index < 0) { return; } ffurl_closep(&reader->input); log_info("ffurl_closep(rep_index: %d)", reader->rep_index); reader->switch_index += 1; } static int PlayList_algo_statistic_thread(void* data); int64_t GopReader_download_gop(GopReader* reader, MultiRateAdaption* adaption, PlayList* playlist) { LasContext* c = reader->parent->priv_data; uint8_t flv_header[FLV_HEADER_LEN + PRE_TAG_SIZE_LEN]; int ret = -1; bool rep_changed = true; bool first_video_tag = true; int to_read; int64_t start_time = 0; int64_t http_open_time = 0; int64_t first_data_time = 0; // got first tag time start_time = get_current_time_ms(); LasStatistic_on_rep_http_start(playlist->las_statistic, start_time); LasStatistic_on_rep_http_first_data(playlist->las_statistic, 0); if (!reader->input) { ret = GopReader_open_input(reader, c, playlist); if (ret < 0) { return ret; } http_open_time = get_current_time_ms(); LasStatistic_on_rep_http_open(playlist->las_statistic, http_open_time - start_time); memset(flv_header, 0, FLV_HEADER_LEN + PRE_TAG_SIZE_LEN); ret = url_block_read(reader->input, flv_header, FLV_HEADER_LEN + PRE_TAG_SIZE_LEN, playlist); LasStatistic_on_rep_flv_header(playlist->las_statistic, get_current_time_ms() - http_open_time); if (ret < 0) { return ret; } } // start algo update thread if (!playlist->algo_thread) { playlist->algo_thread = SDL_CreateThreadEx(&playlist->_algo_thread, PlayList_algo_statistic_thread, playlist, "playlist-algo-statistic-thread"); } //las 2.0 Tag based reading uint8_t av_tag_header[AV_TAG_HEADER_LEN]; int gop_duration = playlist->adaptation_set.duration; int64_t bytes_last = get_bytes_read(playlist); int64_t time_last = get_current_time_ms(); while (1) { if (playlist->read_abort_request || playlist->tag_queue.abort_request) { return LAS_ERROR_ABORT_BY_USER; } ret = playlist->error_code; if (ret < 0) { playlist->error_code = 0; return ret; } int request = get_audio_only_request(playlist->outermost_ctx); if (reader->is_audio_only != request) { reader->is_audio_only = request; int64_t current_playing_audio_ts = get_first_audio_packet_pts(playlist->outermost_ctx); log_info("current_playing_audio_ts: %lld", current_playing_audio_ts); int64_t request_ts = current_playing_audio_ts - playlist->adaptation_set.duration / 2; reader->last_gop_start_ts = request_ts > 0 ? request_ts : 0; return 0; } memset(av_tag_header, 0, AV_TAG_HEADER_LEN); to_read = AV_TAG_HEADER_LEN; ret = url_block_read(reader->input, av_tag_header, to_read, playlist); if (ret < 0) { return ret; } if (av_tag_header[0] == FLV_TAG_TYPE_VIDEO && ((av_tag_header[AV_TAG_HEADER_LEN - 5] >> 4) & 0x0F) == 1 && av_tag_header[AV_TAG_HEADER_LEN - 4] == 1) { //IDR, switch edge uint32_t new_rep_start_pts = AV_RB24(av_tag_header + 4); new_rep_start_pts |= (unsigned)AV_RB8(av_tag_header + 7) << 24; uint32_t cts = (AV_RB24(av_tag_header + 13) + 0xff800000) ^ 0xff800000; new_rep_start_pts += cts; log_info("video key Frame, pts=%lld, parameters=0x%x, video packet_type=0x%x", new_rep_start_pts, av_tag_header[AV_TAG_HEADER_LEN - 5], av_tag_header[AV_TAG_HEADER_LEN - 4]); if (!first_video_tag) { reader->last_gop_start_ts = new_rep_start_pts; int64_t bytes_now = get_bytes_read(playlist); int64_t time_now = get_current_time_ms(); int64_t speed = (bytes_now - bytes_last) * 8 / FFMAX(time_now - time_last, 50); bytes_last = bytes_now; time_last = time_now; adaption->next_expected_rep_index = next_representation_id( adaption, get_switch_mode(playlist->outermost_ctx), speed, get_cache_duration_ms(playlist->audio_cache) / 1000.0); if (reader->rep_index != adaption->next_expected_rep_index) { LasStatistic_on_adaption_adapted(playlist, adaption); LasStatistic_on_rep_switch_count(playlist->las_statistic, playlist); return 0; // switch url } } else { first_video_tag = false; LasStatistic_on_rep_start_timestamp(playlist, new_rep_start_pts, reader->last_gop_start_ts); } } //av_malloc tag size, -1(av parameter bytes) + -1(video packet_type) + -3(CompositionTime) + 4(pre tag size) to_read = AV_RB24(av_tag_header + 1) - 1; FlvTag tag; memset(&tag, 0, sizeof(FlvTag)); if (av_tag_header[0] == FLV_TAG_TYPE_VIDEO || av_tag_header[0] == FLV_TAG_TYPE_AUDIO) { tag.av_tag_ts = AV_RB24(av_tag_header + 4); tag.av_tag_ts |= (unsigned)AV_RB8(av_tag_header + 7) << 24; tag.type = av_tag_header[0]; } int tag_size = 0; if (rep_changed) tag_size = to_read + AV_TAG_HEADER_LEN + FLV_HEADER_LEN + PRE_TAG_SIZE_LEN; else tag_size = to_read + AV_TAG_HEADER_LEN; ret = FlvTag_alloc_buffer(playlist, &tag, tag_size); if (ret) { return ret; } if (rep_changed) { memcpy(tag.buf + tag.buf_write_offset, flv_header, FLV_HEADER_LEN + PRE_TAG_SIZE_LEN); tag.buf_write_offset += FLV_HEADER_LEN + PRE_TAG_SIZE_LEN; } memcpy(tag.buf + tag.buf_write_offset, av_tag_header, AV_TAG_HEADER_LEN); tag.buf_write_offset += AV_TAG_HEADER_LEN; if (playlist->read_abort_request || playlist->tag_queue.abort_request) { FlvTag_dealloc(&tag); return LAS_ERROR_ABORT_BY_USER; } ret = url_block_read(reader->input, tag.buf + tag.buf_write_offset, to_read, playlist); if (ret < 0) { FlvTag_dealloc(&tag); return ret; } else { tag.buf_write_offset += to_read; } if (tag.buf_write_offset != tag.tag_size) { log_error("ERROR! tag.buf_write_offset(%d) != tag.tag_size(%d)", tag.buf_write_offset, tag.tag_size); FlvTag_dealloc(&tag); return LAS_ERROR_GET_WHOLE_TAG; } if (first_data_time == 0) { first_data_time = get_current_time_ms(); LasStatistic_on_rep_http_first_data(playlist->las_statistic, first_data_time); } tag.rep_index = playlist->gop_reader.rep_index; tag.audio_only = playlist->gop_reader.is_audio_only; tag.switch_index = playlist->gop_reader.switch_index; TagQueue_put(&playlist->tag_queue, &tag); if (rep_changed) { rep_changed = false; } } } #pragma mark PlayList static int PlayList_prepare_reading_tag(PlayList* playlist) { SDL_LockMutex(playlist->reading_tag_mutex); int ret = 0; if (FlvTag_has_consume_all_data_l(&playlist->reading_tag)) { FlvTag_dealloc(&playlist->reading_tag); SDL_UnlockMutex(playlist->reading_tag_mutex); FlvTag tag; ret = TagQueue_get(&playlist->tag_queue, &tag, 1); if (ret < 0) { log_error("TagQueue_get fail"); } else { SDL_LockMutex(playlist->reading_tag_mutex); playlist->reading_tag = tag; SDL_UnlockMutex(playlist->reading_tag_mutex); } return ret; } else { SDL_UnlockMutex(playlist->reading_tag_mutex); return 0; } } static int PlayList_read_from_reading_tag(PlayList* playlist, uint8_t* buf, uint32_t buf_size) { SDL_LockMutex(playlist->reading_tag_mutex); int ret = FlvTag_get_data_from_buffer(playlist, &playlist->reading_tag, buf, buf_size); SDL_UnlockMutex(playlist->reading_tag_mutex); return ret; } static int PlayList_read_data(void* opaque, uint8_t* buf, int buf_size) { PlayList* playlist = opaque; int ret; ret = PlayList_prepare_reading_tag(playlist); if (ret < 0) { return ret; } if (playlist->reading_tag.switch_index != playlist->cur_switch_index) { return AVERROR_EOF; } ret = PlayList_read_from_reading_tag(playlist, buf, buf_size); if (ret < 0) { return ret; } return ret; } static void PlayList_reset_state(PlayList* p) { p->parent = NULL; p->read_buffer = NULL; p->cur_switch_index = 0; p->cur_rep_index = p->multi_rate_adaption.next_expected_rep_index; } static int PlayList_algo_statistic_thread(void* data) { PlayList* playlist = (PlayList*)data; TagQueue* tag_queue = &playlist->tag_queue; while (!tag_queue->abort_request) { algo_cond_wait(playlist); if (tag_queue->abort_request || playlist->read_abort_request) { break; } check_buffer(&playlist->multi_rate_adaption, playlist); LasStatistic_on_bandwidth_update(playlist, &playlist->multi_rate_adaption); } return 0; } int PlayList_is_valid_index_l(PlayList* playlist, int index) { if (!playlist) return 0; return index >= 0 && index < playlist->adaptation_set.n_representation; } static int PlayList_read_thread(void* data) { PlayList* playlist = (PlayList*)data; log_info("Start las reading"); AVFormatContext* s = playlist->outermost_ctx; GopReader* gop_reader = &playlist->gop_reader; TagQueue* tag_queue = &playlist->tag_queue; int64_t ret = 0; while (!tag_queue->abort_request) { // change GopReader if needed int new_index = playlist->multi_rate_adaption.next_expected_rep_index; if (!PlayList_is_valid_index_l(playlist, new_index)) { log_error("invalid rep index:%d, IGNORE!!!", new_index); break; } GopReader_close(gop_reader, playlist); Representation* rep = playlist->adaptation_set.representations[new_index]; if (ff_check_interrupt(&s->interrupt_callback)) { break; } GopReader_init(gop_reader, rep, s, playlist); ret = GopReader_download_gop(gop_reader, &playlist->multi_rate_adaption, playlist); if (ret < 0) { LasStatistic_on_rep_read_error(playlist->las_statistic, ret); break; } } TagQueue_abort(&playlist->tag_queue); if (playlist->algo_thread) { log_info("Signals algo_thread"); algo_cond_signal(playlist); } if (gop_reader->input) { log_info("Calls GopReader_close"); GopReader_close(gop_reader, playlist); } log_error("Thread is over, playlist->read_abort_request=%d, ret:%s(0x%x)", playlist->read_abort_request, av_err2str(ret), ret); return playlist->read_abort_request ? 0 : ret; } int PlayList_open_rep(PlayList* playlist, FlvTag* tag, AVFormatContext* s) { int ret = 0; Representation* rep = NULL; if (!PlayList_is_valid_index_l(playlist, tag->rep_index)) { ret = LAS_ERROR_INVALID_REP_INDEX; goto fail; } rep = playlist->adaptation_set.representations[tag->rep_index]; if (!(playlist->ctx = avformat_alloc_context())) { ret = AVERROR(ENOMEM); goto fail; } playlist->read_buffer = av_malloc(INITIAL_BUFFER_SIZE); if (!playlist->read_buffer) { ret = AVERROR(ENOMEM); avformat_free_context(playlist->ctx); playlist->ctx = NULL; goto fail; } ffio_init_context(&playlist->pb, playlist->read_buffer, INITIAL_BUFFER_SIZE, 0, playlist, PlayList_read_data, NULL, NULL); playlist->ctx->pb = &playlist->pb; playlist->ctx->flags |= s->flags & ~AVFMT_FLAG_CUSTOM_IO; SDL_LockMutex(playlist->rw_mutex); playlist->cur_switch_index = tag->switch_index; SDL_UnlockMutex(playlist->rw_mutex); playlist->ctx->fps_probe_size = 0; // fix me ,url should be read reading_gop 's url ret = avformat_open_input(&playlist->ctx, playlist->gop_reader.realtime_url, NULL, NULL); if (ret < 0) { if (playlist->read_thread && playlist->read_thread->retval) { log_error("PlayList_read_thread() already Fails!"); ret = playlist->read_thread->retval; } log_error("avformat_open_input() ret:%s(0x%x)", av_err2str(ret), ret); goto fail; } ret = avformat_find_stream_info(playlist->ctx, NULL); if (ret < 0) { goto fail; } // transcoder_group used in current flv stream AVDictionaryEntry* tsc_group = av_dict_get(playlist->ctx->metadata, "tsc_group", NULL, 0); if (tsc_group && tsc_group->value) { av_dict_set(&playlist->outermost_ctx->metadata, "tsc_group", tsc_group->value, 0); } if (!playlist->is_stream_ever_opened) { // first inited, add streams to outermost AVFormatContext /* Create new AVStreams for each stream in this playlist */ for (int j = 0; j < playlist->ctx->nb_streams; j++) { AVStream* st = avformat_new_stream(s, NULL); AVStream* ist = playlist->ctx->streams[j]; if (!st) { ret = AVERROR(ENOMEM); goto fail; } st->id = 0; avcodec_parameters_copy(st->codecpar, playlist->ctx->streams[j]->codecpar); avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); } playlist->is_stream_ever_opened = true; } else { set_stream_reopened(playlist->outermost_ctx, true); } for (int j = 0; j < playlist->ctx->nb_streams && j < MAX_STREAM_NUM; j++) { AVCodecParameters* new_codec = playlist->ctx->streams[j]->codecpar; for (int k = 0; k < s->nb_streams; k++) { AVCodecParameters* old_codec = s->streams[k]->codecpar; if (new_codec->codec_type == old_codec->codec_type) { playlist->stream_index_map[j] = k; break; } } } playlist->cur_rep_index = tag->rep_index; set_audio_only_response(playlist->outermost_ctx, tag->audio_only); log_info("open_index:%d, audio_only:%d finished", tag->rep_index, tag->audio_only); return 0; fail: return ret; } int PlayList_open_read_thread(PlayList* playlist) { int ret; AVFormatContext* s = playlist->outermost_ctx; playlist->read_abort_request = 0; playlist->rw_mutex = SDL_CreateMutex(); if (!playlist->rw_mutex) { log_error("SDL_CreateMutex playlist->rw_mutex fail"); return LAS_ERROR_MUTEX_CREATE; } playlist->reading_tag_mutex = SDL_CreateMutex(); if (!playlist->reading_tag_mutex) { log_error("SDL_CreateMutex playlist->reading_tag_mutex fail"); return LAS_ERROR_MUTEX_CREATE; } playlist->las_mutex = SDL_CreateMutex(); if (!playlist->las_mutex) { log_error("SDL_CreateMutex playlist->las_mutex fail"); return LAS_ERROR_MUTEX_CREATE; } playlist->algo_cond = SDL_CreateCond(); if (!playlist->algo_cond) { log_error("SDL_CreateCond playlist->algo_cond fail"); return LAS_ERROR_COND_CREATE; } // init and start TagQueue TagQueue_init(playlist, &playlist->tag_queue); TagQueue_start(&playlist->tag_queue); // init GopReader playlist->gop_reader.switch_index = 0; playlist->gop_reader.rep_index = -1; playlist->gop_reader.last_gop_start_ts = (int)(playlist->multi_rate_adaption.buffer_init) * (-1); // start downloading thread playlist->read_thread = SDL_CreateThreadEx(&playlist->_read_thread, PlayList_read_thread, playlist, "playlist-read-thread"); if (!playlist->read_thread) { log_error("SDL_CreateThreadEx fail"); return LAS_ERROR_THREAD_CREATE; } if (playlist->read_thread->retval) { log_error("PlayList_read_thread() fails: %s(0x%x)", av_err2str(playlist->read_thread->retval), playlist->read_thread->retval); return playlist->read_thread->retval; } ret = PlayList_prepare_reading_tag(playlist); if (ret < 0) { return ret; } ret = PlayList_open_rep(playlist, &playlist->reading_tag, s); if (ret) { log_error("PlayList_open_rep() fails: %s(0x%x)", av_err2str(ret), ret); return ret; } return 0; } static void PlayList_abort(PlayList* playlist) { TagQueue_abort(&playlist->tag_queue); SDL_LockMutex(playlist->rw_mutex); playlist->read_abort_request = 1; SDL_UnlockMutex(playlist->rw_mutex); } void PlayList_close_rep(PlayList* playlist) { SDL_LockMutex(playlist->rw_mutex); avformat_close_input(&playlist->ctx); av_freep(&playlist->pb.buffer); log_info("close_index:%d finished", playlist->cur_rep_index); SDL_UnlockMutex(playlist->rw_mutex); } void PlayList_close_read_thread(PlayList* playlist) { // abort request if (playlist->rw_mutex) { PlayList_abort(playlist); PlayList_close_rep(playlist); } SDL_WaitThread(playlist->read_thread, NULL); playlist->read_thread = NULL; SDL_WaitThread(playlist->algo_thread, NULL); playlist->algo_thread = NULL; SDL_DestroyMutexP(&playlist->rw_mutex); SDL_DestroyMutexP(&playlist->reading_tag_mutex); SDL_DestroyMutexP(&playlist->las_mutex); TagQueue_destroy(&playlist->tag_queue); SDL_DestroyCondP(&playlist->algo_cond); } #pragma mark parser void free_multi_rate_flv_context(PlayList* c) { if (!c) return; AdaptationSet* adaptation_set_item = &c->adaptation_set; for (int j = 0; j < adaptation_set_item->n_representation; j++) { if (adaptation_set_item->representations[j]) { av_freep(&adaptation_set_item->representations[j]); } } } static void dump_multi_rate_flv_context(PlayList* c) { if (!c) return; AdaptationSet* adaptation_set_item = &c->adaptation_set; for (int j = 0; j < adaptation_set_item->n_representation; j++) { Representation* representation_item = adaptation_set_item->representations[j]; av_log(NULL, AV_LOG_DEBUG, "{\n"); av_log(NULL, AV_LOG_DEBUG, " id: %d \n", representation_item->id); av_log(NULL, AV_LOG_DEBUG, " bitrate: %d \n", representation_item->bitrate); av_log(NULL, AV_LOG_DEBUG, " url: \"%s\" \n", representation_item->url); av_log(NULL, AV_LOG_DEBUG, "}\n"); } } static int parse_representation_set(Representation* c, cJSON* root) { int len = cJSON_GetArraySize(root); for (int i = 0; i < len; i++) { cJSON* child_json = cJSON_GetArrayItem(root, i); switch (child_json->type) { case cJSON_Number: if (!strcmp(child_json->string, "id")) { c->id = (int)child_json->valuedouble; } else if (!strcmp(child_json->string, "maxBitrate")) { c->bitrate = (int)child_json->valuedouble; } break; case cJSON_String: if (!strcmp(child_json->string, "url")) { strcpy(c->url, child_json->valuestring); } break; case cJSON_NULL: case cJSON_True: if (!strcmp(child_json->string, "defaultSelected")) { c->default_selected = 1; } else if (!strcmp(child_json->string, "disabledFromAdaptive")) { c->disabled_from_adaptive = 1; } break; case cJSON_Array: case cJSON_Object: case cJSON_False: break; } } return 0; } static int parse_adaptation_set(AdaptationSet* c, cJSON* root) { int len = cJSON_GetArraySize(root); for (int i = 0; i < len; i++) { cJSON* child_json = cJSON_GetArrayItem(root, i); switch (child_json->type) { case cJSON_Number: if (!strcmp(child_json->string, "duration")) { c->duration = (int)child_json->valuedouble; } break; case cJSON_Array: if (child_json->string && !strcmp(child_json->string, "representation")) { int len = cJSON_GetArraySize(child_json); for (int i = 0; i < len; i++) { Representation* representation_item = NULL; representation_item = av_mallocz(sizeof(Representation)); if (!representation_item) { return -1; } c->representations[c->n_representation] = representation_item; representation_item->index = c->n_representation; representation_item->disabled_from_adaptive = 0; representation_item->default_selected = 0; c->n_representation++; cJSON* root_json = cJSON_GetArrayItem(child_json, i); parse_representation_set(representation_item, root_json); } } break; case cJSON_False: case cJSON_True: case cJSON_String: case cJSON_NULL: case cJSON_Object: break; } } return 0; } int parse_root(char* file_name, PlayList* c) { cJSON* root = cJSON_Parse(file_name); if (!root) return LAS_ERROR_MANIFEST_JSON; if (cJSON_Object == root->type) { int len = cJSON_GetArraySize(root); for (int i = 0; i < len; i++) { cJSON* child_json = cJSON_GetArrayItem(root, i); switch (child_json->type) { case cJSON_Array: if (child_json->string && !strcmp(child_json->string, "adaptationSet")) { cJSON* adaptation_set = cJSON_GetArrayItem(child_json, 0); if (adaptation_set) { parse_adaptation_set(&c->adaptation_set, adaptation_set); } } break; case cJSON_Number: case cJSON_String: case cJSON_NULL: case cJSON_False: case cJSON_True: case cJSON_Object: break; } printf("\n"); } } cJSON_Delete(root); dump_multi_rate_flv_context(c); return 0; } int parse_adapt_config(char* config_string, AdaptiveConfig* config, PlayList* playlist) { cJSON* root = cJSON_Parse(config_string); if (!root) return LAS_ERROR_ADAPT_CONFIG_JSON; if (cJSON_Object == root->type) { int len = cJSON_GetArraySize(root); for (int i = 0; i < len; i++) { cJSON* child_json = cJSON_GetArrayItem(root, i); switch (child_json->type) { case cJSON_Number: if (!strcmp(child_json->string, "bufferInit")) { config->buffer_init = child_json->valueint; } else if (!strcmp(child_json->string, "stableBufferDiffThresholdSecond")) { config->stable_buffer_diff_threshold_second = child_json->valuedouble; } else if (!strcmp(child_json->string, "stableBufferIntervalMs")) { config->stable_buffer_interval_ms = child_json->valuedouble; } else if (!strcmp(child_json->string, "generateSpeedGapMs")) { config->generate_speed_gap_ms = child_json->valuedouble; } else if (!strcmp(child_json->string, "bufferCheckIntervalMs")) { config->buffer_check_interval_ms = child_json->valuedouble; } else if (!strcmp(child_json->string, "smoothedSpeedUtilizationRatio")) { config->smoothed_speed_utilization_ratio = child_json->valuedouble; } else if (!strcmp(child_json->string, "smallSpeedToBitrateRatio")) { config->small_speed_to_bitrate_ratio = child_json->valuedouble; } else if (!strcmp(child_json->string, "enoughSpeedToBitrateRatio")) { config->enough_speed_to_bitrate_ratio = child_json->valuedouble; } else if (!strcmp(child_json->string, "bufferLowerLimitSecond")) { config->buffer_lower_limit_second = child_json->valuedouble; } else if (!strcmp(child_json->string, "recentBufferedSize")) { config->recent_buffered_size = child_json->valuedouble; } else if (!strcmp(child_json->string, "smoothedSpeedRatio")) { config->smoothed_speed_ratio = child_json->valuedouble; } break; case cJSON_Object: case cJSON_False: case cJSON_NULL: case cJSON_Array: case cJSON_True: break; } } } cJSON_Delete(root); return 0; } static int parse_int_from(cJSON* json, const char* key) { cJSON* entry = cJSON_GetObjectItemCaseSensitive(json, key); if (cJSON_IsNumber(entry)) { return entry->valueint; } return 0; } #pragma mark las static int las_close(AVFormatContext* s) { LasContext* c = s->priv_data; PlayList* playlist = &c->playlist; PlayList_close_read_thread(playlist); free_multi_rate_flv_context(playlist); av_freep(&c->user_agent); av_freep(&c->cookies); av_freep(&c->headers); av_freep(&c->server_ip); av_freep(&c->manifest_string); av_freep(&c->live_adapt_config); av_dict_free(&c->avio_opts); return 0; } static int las_probe(AVProbeData* p) { if (p->filename && av_strstart(p->filename, "ijklas:", NULL)) return AVPROBE_SCORE_MAX; return 0; } static int las_read_header(AVFormatContext* s) { // for debug #ifdef __ANDROID__ pthread_setname_np(pthread_self(), "ffplay_read_thread"); #elif defined(__APPLE__) pthread_setname_np("ffplay_read_thread"); #endif LasContext* c = s->priv_data; PlayList* playlist = &c->playlist; AdaptiveConfig config; AVDictionaryEntry* entry; int ret = 0; c->ctx = s; c->interrupt_callback = &s->interrupt_callback; c->server_ip = NULL; playlist->session_id = c->session_id; av_dict_set(&c->avio_opts, "timeout", "10000000", 0); if ((ret = parse_root(c->manifest_string, playlist)) < 0) { log_error("Illegal manifest Json String"); goto fail; } log_info("Finish parsing las manifest, switch_mode:%d", c->las_switch_mode); if (c->audio_cache_ptr && c->video_cache_ptr) { playlist->video_cache = (FFTrackCacheStatistic*)c->video_cache_ptr; playlist->audio_cache = (FFTrackCacheStatistic*)c->audio_cache_ptr; } else { log_error("FFTrackCacheStatistic is null"); goto fail; } playlist->las_statistic = &c->las_statistic; LasStatistic_init(playlist->las_statistic, playlist); RateAdaptConfig_default_init(&config, playlist); if (parse_adapt_config(c->live_adapt_config, &config, playlist) < 0) { log_error("Illegal adaptation Configure Json String"); } playlist->outermost_ctx = s; MultiRateAdaption_init(&playlist->multi_rate_adaption, config, playlist); PlayList_reset_state(playlist); ret = PlayList_open_read_thread(playlist); if (ret != 0) { goto fail; } return ret; fail: las_close(s); return ret == 0 ? 0 : AVERROR_EXIT; } /* * Used to reset a statically allocated AVPacket to a clean slate, * containing no data. */ static void reset_packet(AVPacket* pkt) { if (pkt) { av_init_packet(pkt); pkt->data = NULL; } } static bool h264_check_sps_pps(const AVPacket* pkt) { if (pkt && pkt->data && pkt->size >= 5) { int offset = 0; while (offset >= 0 && offset + 5 <= pkt->size) { uint8_t* nal_start = pkt->data + offset; int nal_size = AV_RB32(nal_start); int nal_type = nal_start[4] & 0x1f; if (nal_type == H264_NAL_SPS || nal_type == H264_NAL_PPS) { return true; } offset += nal_size + 4; } } return false; } static bool read_sps_pps_by_avcc(uint8_t* extradata, uint32_t extrasize, uint8_t** sps, int* sps_len, uint8_t** pps, int* pps_len) { uint8_t* spc = extradata + 6; uint32_t sps_size = AV_RB16(spc); if (sps_size) { *sps_len = sps_size; *sps = (uint8_t*)av_mallocz(sps_size); if (!*sps) { return false; } spc += 2; memcpy(*sps, spc, sps_size); spc += sps_size; } spc += 1; uint32_t pps_size = AV_RB16(spc); if (pps_size) { *pps_len = pps_size; *pps = (uint8_t*)av_mallocz(pps_size); if (!*pps) { if (*sps) { free(*sps); } return false; } spc += 2; memcpy(*pps, spc, pps_size); } return true; } static void insert_sps_pps_into_avpacket(AVPacket* packet, uint8_t* new_extradata, int new_extradata_size, PlayList* playlist) { uint8_t* sps = NULL, *pps = NULL; int sps_len = 0, pps_len = 0; if (read_sps_pps_by_avcc(new_extradata, new_extradata_size, &sps, &sps_len, &pps, &pps_len)) { int size = packet->size; if (sps) { size += NALU_HEAD_LEN + sps_len; } if (pps) { size += NALU_HEAD_LEN + pps_len; } if (size == packet->size) { return; } AVPacket new_pack; int res = av_new_packet(&new_pack, size); if (res < 0) { log_error("Failed memory allocation"); } else { av_packet_copy_props(&new_pack, packet); uint8_t* data = new_pack.data; if (sps) { AV_WB32(data, sps_len); data += NALU_HEAD_LEN; memcpy(data, sps, sps_len); data += sps_len; log_info("insert sps, size:%d", sps_len); } else { log_info("sps is null"); } if (pps) { AV_WB32(data, pps_len); data += NALU_HEAD_LEN; memcpy(data, pps, pps_len); data += pps_len; log_info("insert pps, size:%d", pps_len); } else { log_info("pps is null"); } memcpy(data, packet->data, packet->size); av_packet_unref(packet); *packet = new_pack; } } } static int las_read_packet(AVFormatContext* s, AVPacket* pkt) { LasContext* c = s->priv_data; PlayList* playlist = &c->playlist; int ret = 0; while (1) { if (!playlist->ctx) { log_error("playlist->ctx is null"); ret = AVERROR_EOF; goto fail; } ret = av_read_frame(playlist->ctx, &playlist->pkt); if (ret < 0) { reset_packet(&playlist->pkt); if (avio_feof(&playlist->pb) || ret == AVERROR_EOF) { // change rep if needed if (playlist->cur_switch_index != playlist->reading_tag.switch_index) { PlayList_close_rep(playlist); PlayList_open_rep(playlist, &playlist->reading_tag, s); continue; } } break; } else if (!playlist->pkt.data) { // success, but no packet data yet continue; } else { // go packet *pkt = playlist->pkt; if (pkt->stream_index >= 0 && pkt->stream_index < MAX_STREAM_NUM) { pkt->stream_index = playlist->stream_index_map[pkt->stream_index]; } AVCodecParameters* codec = playlist->ctx->streams[pkt->stream_index]->codecpar; if (codec->extradata) { if (codec->codec_id == AV_CODEC_ID_H264 && !h264_check_sps_pps(pkt)) { insert_sps_pps_into_avpacket(pkt, codec->extradata, codec->extradata_size, playlist); } uint8_t *side = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, codec->extradata_size); if (side) { memcpy(side, codec->extradata, codec->extradata_size); av_freep(&codec->extradata); codec->extradata_size = 0; } } break; } } reset_packet(&playlist->pkt); LasStatistic_on_read_packet(playlist->las_statistic, playlist); fail: return ret == 0 ? 0 : AVERROR_EXIT; } static int las_read_seek(AVFormatContext* s, int stream_index, int64_t timestamp, int flags) { // LasContext *c = s->priv_data; return 0; } #define OFFSET(x) offsetof(LasContext, x) #define FLAGS AV_OPT_FLAG_DECODING_PARAM static const AVOption las_options[] = { { "user-agent", "user agent", OFFSET(user_agent), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, FLAGS }, { "headers", "headers", OFFSET(headers), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, FLAGS }, { "manifest_string", "manifest_string", OFFSET(manifest_string), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, FLAGS }, { "abr_history_data", "abr_history_data", OFFSET(abr_history_data), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, FLAGS }, { "device-network-type", "device-network-type", OFFSET(network), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, FLAGS }, { "liveAdaptConfig", "liveAdaptConfig", OFFSET(live_adapt_config), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, FLAGS }, { "session_id", "session_id", OFFSET(session_id), AV_OPT_TYPE_INT, {.i64 = 0}, INT32_MIN, INT32_MAX, FLAGS }, { "video_cache_ptr", "video_cache_ptr", OFFSET(video_cache_ptr), AV_OPT_TYPE_INT64, {.i64 = 0}, INT64_MIN, INT64_MAX, FLAGS }, { "audio_cache_ptr", "audio_cache_ptr", OFFSET(audio_cache_ptr), AV_OPT_TYPE_INT64, {.i64 = 0}, INT64_MIN, INT64_MAX, FLAGS }, { "las_switch_mode", "las_switch_mode", OFFSET(las_switch_mode), AV_OPT_TYPE_INT, {.i64 = LAS_AUTO_MODE}, INT_MIN, INT_MAX, FLAGS }, { "first_audio_packet_pts", "first_audio_packet_pts", OFFSET(first_audio_packet_pts), AV_OPT_TYPE_INT64, {.i64 = 0}, INT64_MIN, INT64_MAX, FLAGS }, { "block_duration", "block_duration", OFFSET(block_duration), AV_OPT_TYPE_INT, {.i64 = 0}, INT64_MIN, INT64_MAX, FLAGS }, { "audio_only_request", "audio_only_request", OFFSET(audio_only_request), AV_OPT_TYPE_INT, {.i64 = 0}, INT64_MIN, INT64_MAX, FLAGS }, { "audio_only_response", "audio_only_response", OFFSET(audio_only_response), AV_OPT_TYPE_INT, {.i64 = 0}, INT64_MIN, INT64_MAX, FLAGS }, { "stream_reopened", "stream_reopened", OFFSET(stream_reopened), AV_OPT_TYPE_INT, {.i64 = 0}, INT64_MIN, INT64_MAX, FLAGS }, {NULL} }; static const AVClass ijklas_class = { .class_name = "las demuxer", .item_name = av_default_item_name, .option = las_options, .version = LIBAVUTIL_VERSION_INT, }; AVInputFormat ijkff_ijklas_demuxer = { .name = "ijklas", .long_name = "Live Adaptive Streaming", .priv_class = &ijklas_class, .priv_data_size = sizeof(LasContext), .read_probe = las_probe, .read_header = las_read_header, .read_packet = las_read_packet, .read_close = las_close, .read_seek = las_read_seek, .extensions = "las", .flags = AVFMT_NOFILE }; ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijklas.h ================================================ #ifndef LAS_DEMUX #define LAS_DEMUX #include #include #include #define MAX_URL_SIZE 4096 #define MAX_STREAM_NUM 10 #define LAS_AUTO_MODE (-1) typedef struct FlvInfo { int total_bandwidth_kbps; char url[MAX_URL_SIZE]; } FlvInfo; typedef struct LasStatistic { // info from manifest.json FlvInfo flvs[MAX_STREAM_NUM]; int flv_nb; // algo specific int64_t bandwidth_fragment; int64_t bitrate_downloading; int64_t current_buffer_ms; // status int cur_decoding_flv_index; int64_t switch_point_a_buffer_ms; int64_t switch_point_v_buffer_ms; char cur_playing_url[MAX_URL_SIZE]; // rep switch speed int64_t cur_rep_read_start_time; int64_t cur_rep_http_open_time; int64_t cur_rep_read_header_time; int64_t cur_rep_first_data_time; // first tag time int64_t cur_rep_start_time; int64_t rep_switch_gap_time; //new_rep_start_pts - request_pts int64_t rep_switch_cnt; int cur_rep_http_reading_error; // errors during gop reading int64_t cached_tag_dur_ms; int64_t cached_a_dur_ms; // 上层播放器packet_queue长度 int64_t cached_v_dur_ms; int64_t total_bytes_read; } LasStatistic; #endif ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijklivehook.c ================================================ /* * Copyright (c) 2015 Bilibili * Copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libavformat/avformat.h" #include "libavformat/url.h" #include "libavutil/avstring.h" #include "libavutil/opt.h" #include "ijkplayer/ijkavutil/opt.h" #include "ijkavformat.h" #include "libavutil/application.h" typedef struct { AVClass *class; AVFormatContext *inner; AVAppIOControl io_control; int discontinuity; int error; /* options */ AVDictionary *open_opts; char * app_ctx_intptr; AVApplicationContext *app_ctx; } Context; static int ijkurlhook_call_inject(AVFormatContext *h) { Context *c = h->priv_data; int ret = 0; if (ff_check_interrupt(&h->interrupt_callback)) { ret = AVERROR_EXIT; goto fail; } if (c->app_ctx) { av_log(h, AV_LOG_INFO, "livehook %s\n", c->io_control.url); c->io_control.is_handled = 0; ret = av_application_on_io_control(c->app_ctx, AVAPP_CTRL_WILL_LIVE_OPEN, &c->io_control); if (ret || !c->io_control.url[0]) { ret = AVERROR_EXIT; goto fail; } } if (ff_check_interrupt(&h->interrupt_callback)) { ret = AVERROR_EXIT; goto fail; } fail: return ret; } static int ijklivehook_probe(AVProbeData *probe) { if (av_strstart(probe->filename, "ijklivehook:", NULL)) return AVPROBE_SCORE_MAX; return 0; } static int ijklivehook_read_close(AVFormatContext *avf) { Context *c = avf->priv_data; avformat_close_input(&c->inner); return 0; } // FIXME: install libavformat/internal.h int ff_alloc_extradata(AVCodecParameters *par, int size); static int copy_stream_props(AVStream *st, AVStream *source_st) { int ret; if (st->codecpar->codec_id || !source_st->codecpar->codec_id) { if (st->codecpar->extradata_size < source_st->codecpar->extradata_size) { if (st->codecpar->extradata) { av_freep(&st->codecpar->extradata); st->codecpar->extradata_size = 0; } ret = ff_alloc_extradata(st->codecpar, source_st->codecpar->extradata_size); if (ret < 0) return ret; } memcpy(st->codecpar->extradata, source_st->codecpar->extradata, source_st->codecpar->extradata_size); return 0; } if ((ret = avcodec_parameters_copy(st->codecpar, source_st->codecpar)) < 0) return ret; st->r_frame_rate = source_st->r_frame_rate; st->avg_frame_rate = source_st->avg_frame_rate; st->time_base = source_st->time_base; st->sample_aspect_ratio = source_st->sample_aspect_ratio; av_dict_copy(&st->metadata, source_st->metadata, 0); return 0; } static int open_inner(AVFormatContext *avf) { Context *c = avf->priv_data; AVDictionary *tmp_opts = NULL; AVFormatContext *new_avf = NULL; int ret = -1; int i = 0; AVDictionaryEntry *t = NULL; int fps_flag = 0; new_avf = avformat_alloc_context(); if (!new_avf) { ret = AVERROR(ENOMEM); goto fail; } if (c->open_opts) av_dict_copy(&tmp_opts, c->open_opts, 0); av_dict_set_int(&tmp_opts, "probesize", avf->probesize, 0); av_dict_set_int(&tmp_opts, "formatprobesize", avf->format_probesize, 0); av_dict_set_int(&tmp_opts, "analyzeduration", avf->max_analyze_duration, 0); av_dict_set_int(&tmp_opts, "fpsprobesize", avf->fps_probe_size, 0); av_dict_set_int(&tmp_opts, "max_ts_probe", avf->max_ts_probe, 0); t = av_dict_get(tmp_opts, "skip-calc-frame-rate", NULL, AV_DICT_MATCH_CASE); if (t) { fps_flag = (int) strtol(t->value, NULL, 10); if (fps_flag > 0) { av_dict_set_int(&new_avf->metadata, "skip-calc-frame-rate", fps_flag, 0); } } new_avf->interrupt_callback = avf->interrupt_callback; ret = avformat_open_input(&new_avf, c->io_control.url, NULL, &tmp_opts); if (ret < 0) goto fail; ret = avformat_find_stream_info(new_avf, NULL); if (ret < 0) goto fail; for (i = 0; i < new_avf->nb_streams; i++) { AVStream *st = avformat_new_stream(avf, NULL); if (!st) { ret = AVERROR(ENOMEM); goto fail; } ret = copy_stream_props(st, new_avf->streams[i]); if (ret < 0) goto fail; } avformat_close_input(&c->inner); c->inner = new_avf; new_avf = NULL; ret = 0; fail: av_dict_free(&tmp_opts); avformat_close_input(&new_avf); return ret; } static int ijklivehook_read_header(AVFormatContext *avf, AVDictionary **options) { Context *c = avf->priv_data; const char *inner_url = NULL; int ret = -1; c->app_ctx = (AVApplicationContext *)av_dict_strtoptr(c->app_ctx_intptr); av_strstart(avf->filename, "ijklivehook:", &inner_url); c->io_control.size = sizeof(c->io_control); strlcpy(c->io_control.url, inner_url, sizeof(c->io_control.url)); if (av_stristart(c->io_control.url, "rtmp", NULL) || av_stristart(c->io_control.url, "rtsp", NULL)) { // There is total different meaning for 'timeout' option in rtmp av_log(avf, AV_LOG_WARNING, "remove 'timeout' option for rtmp.\n"); av_dict_set(options, "timeout", NULL, 0); } if (options) av_dict_copy(&c->open_opts, *options, 0); c->io_control.retry_counter = 0; ret = ijkurlhook_call_inject(avf); if (ret) { ret = AVERROR_EXIT; goto fail; } ret = open_inner(avf); while (ret < 0) { // no EOF in live mode switch (ret) { case AVERROR_EXIT: goto fail; } c->io_control.retry_counter++; ret = ijkurlhook_call_inject(avf); if (ret) { ret = AVERROR_EXIT; goto fail; } c->discontinuity = 1; ret = open_inner(avf); } return 0; fail: return ret; } static int ijklivehook_read_packet(AVFormatContext *avf, AVPacket *pkt) { Context *c = avf->priv_data; int ret = -1; if (c->error) return c->error; if (c->inner) ret = av_read_frame(c->inner, pkt); c->io_control.retry_counter = 0; while (ret < 0) { if (c->inner && c->inner->pb && c->inner->pb->error && avf->pb) avf->pb->error = c->inner->pb->error; // no EOF in live mode switch (ret) { case AVERROR_EXIT: c->error = AVERROR_EXIT; goto fail; case AVERROR(EAGAIN): goto continue_read; } c->io_control.retry_counter++; ret = ijkurlhook_call_inject(avf); if (ret) { ret = AVERROR_EXIT; goto fail; } c->discontinuity = 1; ret = open_inner(avf); if (ret) continue; continue_read: ret = av_read_frame(c->inner, pkt); } if (c->discontinuity) { pkt->flags |= AV_PKT_FLAG_DISCONTINUITY; c->discontinuity = 0; } return 0; fail: return ret; } #define OFFSET(x) offsetof(Context, x) #define D AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { { "ijkapplication", "AVApplicationContext", OFFSET(app_ctx_intptr), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, .flags = D }, { NULL } }; #undef D #undef OFFSET static const AVClass ijklivehook_class = { .class_name = "LiveHook demuxer", .item_name = av_default_item_name, .option = options, .version = LIBAVUTIL_VERSION_INT, }; AVInputFormat ijkff_ijklivehook_demuxer = { .name = "ijklivehook", .long_name = "Live Hook Controller", .flags = AVFMT_NOFILE | AVFMT_TS_DISCONT, .priv_data_size = sizeof(Context), .read_probe = ijklivehook_probe, .read_header2 = ijklivehook_read_header, .read_packet = ijklivehook_read_packet, .read_close = ijklivehook_read_close, .priv_class = &ijklivehook_class, }; ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijklongurl.c ================================================ /* * Copyright (c) 2015 Bilibili * Copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "libavformat/avformat.h" #include "libavformat/url.h" #include "libavutil/avstring.h" #include "libavutil/log.h" #include "libavutil/opt.h" typedef struct Context { AVClass *class; URLContext *inner; /* options */ char *url; } Context; static int ijklongurl_open(URLContext *h, const char *arg, int flags, AVDictionary **options) { Context *c = h->priv_data; if (!c->url || !*c->url) return AVERROR_EXTERNAL; return ffurl_open_whitelist(&c->inner, c->url, flags, &h->interrupt_callback, options, h->protocol_whitelist, h->protocol_blacklist, h); } static int ijklongurl_close(URLContext *h) { Context *c = h->priv_data; return ffurl_close(c->inner); } static int ijklongurl_read(URLContext *h, unsigned char *buf, int size) { Context *c = h->priv_data; return ffurl_read(c->inner, buf, size); } static int64_t ijklongurl_seek(URLContext *h, int64_t pos, int whence) { Context *c = h->priv_data; return ffurl_seek(c->inner, pos, whence); } #define OFFSET(x) offsetof(Context, x) #define D AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { { "ijklongurl-url", "real url to access", OFFSET(url), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, D }, { NULL } }; #undef D #undef OFFSET static const AVClass ijklongurl_context_class = { .class_name = "LongUrl", .item_name = av_default_item_name, .option = options, .version = LIBAVUTIL_VERSION_INT, }; URLProtocol ijkimp_ff_ijklongurl_protocol = { .name = "ijklongurl", .url_open2 = ijklongurl_open, .url_read = ijklongurl_read, .url_seek = ijklongurl_seek, .url_close = ijklongurl_close, .priv_data_size = sizeof(Context), .priv_data_class = &ijklongurl_context_class, }; ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijkmediadatasource.c ================================================ /* * Copyright (c) 2015 Bilibili * Copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef __ANDROID__ #include #include "libavformat/avformat.h" #include "libavformat/url.h" #include "libavutil/avstring.h" #include "libavutil/log.h" #include "libavutil/opt.h" #include "ijkavformat/ijkavformat.h" #include "ijkplayer/ijkavutil/opt.h" #include "j4a/class/tv/danmaku/ijk/media/player/misc/IMediaDataSource.h" #include "ijksdl/android/ijksdl_android_jni.h" typedef struct Context { AVClass *class; /* options */ int64_t logical_pos; int64_t logical_size; int64_t media_data_source_ptr; jobject media_data_source; jbyteArray jbuffer; int jbuffer_capacity; } Context; static int ijkmds_open(URLContext *h, const char *arg, int flags, AVDictionary **options) { Context *c = h->priv_data; JNIEnv *env = NULL; jobject media_data_source = NULL; char *final = NULL; av_strstart(arg, "ijkmediadatasource:", &arg); media_data_source = (jobject) (intptr_t) strtoll(arg, &final, 10); if (!media_data_source) return AVERROR(EINVAL); if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { av_log(h, AV_LOG_ERROR, "%s: SDL_JNI_SetupThreadEnv: failed", __func__); return AVERROR(EINVAL); } c->logical_size = J4AC_IMediaDataSource__getSize(env, media_data_source); if (J4A_ExceptionCheck__catchAll(env)) { return AVERROR(EINVAL); } else if (c->logical_size < 0) { h->is_streamed = 1; c->logical_size = -1; } c->media_data_source = (*env)->NewGlobalRef(env, media_data_source); if (J4A_ExceptionCheck__catchAll(env) || !c->media_data_source) { return AVERROR(ENOMEM); } return 0; } static int ijkmds_close(URLContext *h) { Context *c = h->priv_data; JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { av_log(h, AV_LOG_ERROR, "%s: SDL_JNI_SetupThreadEnv: failed", __func__); return AVERROR(EINVAL); } J4A_DeleteGlobalRef__p(env, &c->jbuffer); if (c->media_data_source) { J4AC_IMediaDataSource__close__catchAll(env, c->media_data_source); J4A_DeleteGlobalRef__p(env, &c->media_data_source); } c->media_data_source_ptr = 0; return 0; } static jobject jbuffer_grow(JNIEnv *env, URLContext *h, int new_capacity) { Context *c = h->priv_data; if (c->jbuffer && c->jbuffer_capacity >= new_capacity) return c->jbuffer; new_capacity = FFMAX(new_capacity, c->jbuffer_capacity * 2); J4A_DeleteGlobalRef__p(env, &c->jbuffer); c->jbuffer_capacity = 0; c->jbuffer = J4A_NewByteArray__asGlobalRef__catchAll(env, new_capacity); if (J4A_ExceptionCheck__catchAll(env) || !c->jbuffer) { c->jbuffer = NULL; return NULL; } c->jbuffer_capacity = new_capacity; return c->jbuffer; } static int ijkmds_read(URLContext *h, unsigned char *buf, int size) { Context *c = h->priv_data; JNIEnv *env = NULL; jbyteArray jbuffer = NULL; jint ret = 0; if (!c->media_data_source) return AVERROR(EINVAL); if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { av_log(h, AV_LOG_ERROR, "%s: SDL_JNI_SetupThreadEnv: failed", __func__); return AVERROR(EINVAL); } jbuffer = jbuffer_grow(env, h, size); if (!jbuffer) return AVERROR(ENOMEM); ret = J4AC_IMediaDataSource__readAt(env, c->media_data_source, c->logical_pos, jbuffer, 0, size); if (J4A_ExceptionCheck__catchAll(env)) return AVERROR(EIO); else if (ret < 0) return AVERROR_EOF; else if (ret == 0) return AVERROR(EAGAIN); (*env)->GetByteArrayRegion(env, jbuffer, 0, ret, (jbyte*)buf); if (J4A_ExceptionCheck__catchAll(env)) return AVERROR(EIO); c->logical_pos += ret; return ret; } static int64_t ijkmds_seek(URLContext *h, int64_t pos, int whence) { Context *c = h->priv_data; int64_t ret; int64_t new_logical_pos; JNIEnv *env = NULL; jobject jbuffer = NULL; if (!c->media_data_source) return AVERROR(EINVAL); if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { av_log(h, AV_LOG_ERROR, "%s: SDL_JNI_SetupThreadEnv: failed", __func__); return AVERROR(EINVAL); } if (whence == AVSEEK_SIZE) { av_log(h, AV_LOG_TRACE, "%s: AVSEEK_SIZE: %"PRId64"\n", __func__, (int64_t)c->logical_size); return c->logical_size; } else if (whence == SEEK_CUR) { av_log(h, AV_LOG_TRACE, "%s: %"PRId64"\n", __func__, pos); new_logical_pos = pos + c->logical_pos; } else if (whence == SEEK_SET){ av_log(h, AV_LOG_TRACE, "%s: %"PRId64"\n", __func__, pos); new_logical_pos = pos; } else { return AVERROR(EINVAL); } if (new_logical_pos < 0) return AVERROR(EINVAL); jbuffer = jbuffer_grow(env, h, 0); if (!jbuffer) return AVERROR(ENOMEM); ret = J4AC_IMediaDataSource__readAt(env, c->media_data_source, new_logical_pos, jbuffer, 0, 0); if (J4A_ExceptionCheck__catchAll(env)) return AVERROR(EIO); else if (ret < 0) return AVERROR_EOF; c->logical_pos = new_logical_pos; return c->logical_pos; } #define OFFSET(x) offsetof(Context, x) #define D AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { { NULL } }; #undef D #undef OFFSET static const AVClass ijkmediadatasource_context_class = { .class_name = "IjkMediaDataSource", .item_name = av_default_item_name, .option = options, .version = LIBAVUTIL_VERSION_INT, }; URLProtocol ijkimp_ff_ijkmediadatasource_protocol = { .name = "ijkmediadatasource", .url_open2 = ijkmds_open, .url_read = ijkmds_read, .url_seek = ijkmds_seek, .url_close = ijkmds_close, .priv_data_size = sizeof(Context), .priv_data_class = &ijkmediadatasource_context_class, }; #endif ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijksegment.c ================================================ /* * Copyright (c) 2015 Bilibili * Copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "libavformat/avformat.h" #include "libavformat/url.h" #include "libavutil/avstring.h" #include "libavutil/log.h" #include "libavutil/opt.h" #include "libavutil/application.h" typedef struct Context { AVClass *class; URLContext *inner; /* options */ char *http_hook; char * app_ctx_intptr; } Context; static int ijksegment_open(URLContext *h, const char *arg, int flags, AVDictionary **options) { Context *c = h->priv_data; AVAppIOControl io_control = {0}; AVApplicationContext *app_ctx = (AVApplicationContext *)av_dict_strtoptr(c->app_ctx_intptr); int ret = -1; int segment_index = -1; av_strstart(arg, "ijksegment:", &arg); if (!arg || !*arg) return AVERROR_EXTERNAL; segment_index = (int)strtol(arg, NULL, 0); io_control.size = sizeof(io_control); io_control.segment_index = segment_index; strlcpy(io_control.url, arg, sizeof(io_control.url)); if (app_ctx && io_control.segment_index < 0) { ret = AVERROR_EXTERNAL; goto fail; } ret = av_application_on_io_control(app_ctx, AVAPP_CTRL_WILL_CONCAT_SEGMENT_OPEN, &io_control); if (ret || !io_control.url[0]) { ret = AVERROR_EXIT; goto fail; } av_dict_set_intptr(options, "ijkapplication", (uintptr_t )app_ctx, 0); av_dict_set_int(options, "ijkinject-segment-index", segment_index, 0); ret = ffurl_open_whitelist(&c->inner, io_control.url, flags, &h->interrupt_callback, options, h->protocol_whitelist, h->protocol_blacklist, h); if (ret) goto fail; return 0; fail: return ret; } static int ijksegment_close(URLContext *h) { Context *c = h->priv_data; return ffurl_close(c->inner); } static int ijksegment_read(URLContext *h, unsigned char *buf, int size) { Context *c = h->priv_data; return ffurl_read(c->inner, buf, size); } static int64_t ijksegment_seek(URLContext *h, int64_t pos, int whence) { Context *c = h->priv_data; return ffurl_seek(c->inner, pos, whence); } #define OFFSET(x) offsetof(Context, x) #define D AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { { "ijkapplication", "AVApplicationContext", OFFSET(app_ctx_intptr), AV_OPT_TYPE_INT64, { .i64 = 0 }, INT64_MIN, INT64_MAX, .flags = D }, { NULL } }; #undef D #undef OFFSET static const AVClass ijksegment_context_class = { .class_name = "Inject", .item_name = av_default_item_name, .option = options, .version = LIBAVUTIL_VERSION_INT, }; URLProtocol ijkimp_ff_ijksegment_protocol = { .name = "ijksegment", .url_open2 = ijksegment_open, .url_read = ijksegment_read, .url_seek = ijksegment_seek, .url_close = ijksegment_close, .priv_data_size = sizeof(Context), .priv_data_class = &ijksegment_context_class, }; ================================================ FILE: ijkmedia/ijkplayer/ijkavformat/ijkurlhook.c ================================================ /* * Copyright (c) 2015 Bilibili * Copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "libavformat/avformat.h" #include "libavformat/url.h" #include "libavutil/avstring.h" #include "libavutil/log.h" #include "libavutil/opt.h" #include "libavutil/application.h" typedef struct Context { AVClass *class; URLContext *inner; int64_t logical_pos; int64_t logical_size; int io_error; AVAppIOControl app_io_ctrl; const char *scheme; const char *inner_scheme; /* options */ int inner_flags; AVDictionary *inner_options; int segment_index; int64_t test_fail_point; int64_t test_fail_point_next; char* app_ctx_intptr; AVApplicationContext *app_ctx; } Context; static int ijkurlhook_call_inject(URLContext *h) { Context *c = h->priv_data; int ret = 0; if (ff_check_interrupt(&h->interrupt_callback)) { ret = AVERROR_EXIT; goto fail; } if (c->app_ctx) { AVAppIOControl control_data_backup = c->app_io_ctrl; c->app_io_ctrl.is_handled = 0; c->app_io_ctrl.is_url_changed = 0; ret = av_application_on_io_control(c->app_ctx, AVAPP_CTRL_WILL_HTTP_OPEN, &c->app_io_ctrl); if (ret || !c->app_io_ctrl.url[0]) { ret = AVERROR_EXIT; goto fail; } if (!c->app_io_ctrl.is_url_changed && strcmp(control_data_backup.url, c->app_io_ctrl.url)) { // force a url compare c->app_io_ctrl.is_url_changed = 1; } av_log(h, AV_LOG_INFO, "%s %s (%s)\n", h->prot->name, c->app_io_ctrl.url, c->app_io_ctrl.is_url_changed ? "changed" : "remain"); } if (ff_check_interrupt(&h->interrupt_callback)) { ret = AVERROR_EXIT; av_log(h, AV_LOG_ERROR, "%s %s (%s)\n", h->prot->name, c->app_io_ctrl.url, c->app_io_ctrl.is_url_changed ? "changed" : "remain"); goto fail; } fail: return ret; } static int ijkurlhook_reconnect(URLContext *h, AVDictionary *extra) { Context *c = h->priv_data; int ret = 0; URLContext *new_url = NULL; AVDictionary *inner_options = NULL; c->test_fail_point_next += c->test_fail_point; assert(c->inner_options); av_dict_copy(&inner_options, c->inner_options, 0); if (extra) av_dict_copy(&inner_options, extra, 0); ret = ffurl_open_whitelist(&new_url, c->app_io_ctrl.url, c->inner_flags, &h->interrupt_callback, &inner_options, h->protocol_whitelist, h->protocol_blacklist, h); if (ret) goto fail; ffurl_closep(&c->inner); c->inner = new_url; h->is_streamed = c->inner->is_streamed; c->logical_pos = ffurl_seek(c->inner, 0, SEEK_CUR); if (c->inner->is_streamed) c->logical_size = -1; else c->logical_size = ffurl_seek(c->inner, 0, AVSEEK_SIZE); c->io_error = 0; fail: av_dict_free(&inner_options); return ret; } static int ijkurlhook_init(URLContext *h, const char *arg, int flags, AVDictionary **options) { Context *c = h->priv_data; int ret = 0; av_strstart(arg, c->scheme, &arg); c->inner_flags = flags; if (options) av_dict_copy(&c->inner_options, *options, 0); av_dict_set_intptr(&c->inner_options, "ijkapplication", (uintptr_t )c->app_ctx, 0); av_dict_set_int(&c->inner_options, "ijkinject-segment-index", c->segment_index, 0); c->app_io_ctrl.size = sizeof(c->app_io_ctrl); c->app_io_ctrl.segment_index = c->segment_index; c->app_io_ctrl.retry_counter = 0; if (av_strstart(arg, c->inner_scheme, NULL)) { snprintf(c->app_io_ctrl.url, sizeof(c->app_io_ctrl.url), "%s", arg); } else { snprintf(c->app_io_ctrl.url, sizeof(c->app_io_ctrl.url), "%s%s", c->inner_scheme, arg); } return ret; } static int ijktcphook_open(URLContext *h, const char *arg, int flags, AVDictionary **options) { Context *c = h->priv_data; int ret = 0; c->app_ctx = (AVApplicationContext *)av_dict_strtoptr(c->app_ctx_intptr); c->scheme = "ijktcphook:"; c->inner_scheme = "tcp:"; ret = ijkurlhook_init(h, arg, flags, options); if (ret) goto fail; ret = ijkurlhook_reconnect(h, NULL); if (ret) goto fail; fail: return ret; } static int ijkurlhook_close(URLContext *h) { Context *c = h->priv_data; av_dict_free(&c->inner_options); return ffurl_closep(&c->inner); } static int ijkurlhook_read(URLContext *h, unsigned char *buf, int size) { Context *c = h->priv_data; int ret = 0; if (c->io_error < 0) return c->io_error; if (c->test_fail_point_next > 0 && c->logical_pos >= c->test_fail_point_next) { av_log(h, AV_LOG_ERROR, "test fail point:%"PRId64"\n", c->test_fail_point_next); c->io_error = AVERROR(EIO); return AVERROR(EIO); } ret = ffurl_read(c->inner, buf, size); if (ret > 0) c->logical_pos += ret; else c->io_error = ret; return ret; } static int ijkurlhook_write(URLContext *h, const unsigned char *buf, int size) { Context *c = h->priv_data; return ffurl_write(c->inner, buf, size); } static int64_t ijkurlhook_seek(URLContext *h, int64_t pos, int whence) { Context *c = h->priv_data; int64_t seek_ret = 0; seek_ret = ffurl_seek(c->inner, pos, whence); if (seek_ret < 0) { c->io_error = (int)seek_ret; return seek_ret; } c->logical_pos = seek_ret; if (c->test_fail_point) c->test_fail_point_next = c->logical_pos + c->test_fail_point; c->io_error = 0; return seek_ret; } static int ijkhttphook_reconnect_at(URLContext *h, int64_t offset) { int ret = 0; AVDictionary *extra_opts = NULL; av_dict_set_int(&extra_opts, "offset", offset, 0); av_dict_set_int(&extra_opts, "dns_cache_clear", 1, 0); ret = ijkurlhook_reconnect(h, extra_opts); av_dict_free(&extra_opts); return ret; } static int ijkhttphook_open(URLContext *h, const char *arg, int flags, AVDictionary **options) { Context *c = h->priv_data; int ret = 0; c->app_ctx = (AVApplicationContext *)av_dict_strtoptr(c->app_ctx_intptr); c->scheme = "ijkhttphook:"; if (av_stristart(arg, "ijkhttphook:https:", NULL)) c->inner_scheme = "https:"; else c->inner_scheme = "http:"; ret = ijkurlhook_init(h, arg, flags, options); if (ret) goto fail; ret = ijkurlhook_call_inject(h); if (ret) goto fail; ret = ijkurlhook_reconnect(h, NULL); while (ret) { int inject_ret = 0; switch (ret) { case AVERROR_EXIT: goto fail; } c->app_io_ctrl.retry_counter++; inject_ret = ijkurlhook_call_inject(h); if (inject_ret) { ret = AVERROR_EXIT; goto fail; } if (!c->app_io_ctrl.is_handled) goto fail; av_log(h, AV_LOG_INFO, "%s: will reconnect at start\n", __func__); ret = ijkhttphook_reconnect_at(h, 0); av_log(h, AV_LOG_INFO, "%s: did reconnect at start: %d\n", __func__, ret); } fail: return ret; } static int ijkhttphook_read(URLContext *h, unsigned char *buf, int size) { Context *c = h->priv_data; int ret = 0; c->app_io_ctrl.retry_counter = 0; ret = ijkurlhook_read(h, buf, size); while (ret < 0 && !h->is_streamed && c->logical_pos < c->logical_size) { switch (ret) { case AVERROR_EXIT: goto fail; } c->app_io_ctrl.retry_counter++; ret = ijkurlhook_call_inject(h); if (ret) goto fail; if (!c->app_io_ctrl.is_handled) goto fail; av_log(h, AV_LOG_INFO, "%s: will reconnect(%d) at %"PRId64"\n", __func__, c->app_io_ctrl.retry_counter, c->logical_pos); ret = ijkhttphook_reconnect_at(h, c->logical_pos); av_log(h, AV_LOG_INFO, "%s: did reconnect(%d) at %"PRId64": %d\n", __func__, c->app_io_ctrl.retry_counter, c->logical_pos, ret); if (ret < 0) continue; ret = ijkurlhook_read(h, buf, size); } fail: if (ret <= 0) { c->io_error = ret; } return ret; } static int64_t ijkhttphook_reseek_at(URLContext *h, int64_t pos, int whence, int force_reconnect) { Context *c = h->priv_data; int ret = 0; if (!force_reconnect) return ijkurlhook_seek(h, pos, whence); if (whence == SEEK_CUR) pos += c->logical_pos; else if (whence == SEEK_END) pos += c->logical_size; else if (whence != SEEK_SET) return AVERROR(EINVAL); if (pos < 0) return AVERROR(EINVAL); ret = ijkhttphook_reconnect_at(h, pos); if (ret) { c->io_error = ret; return ret; } c->io_error = 0; return c->logical_pos; } static int64_t ijkhttphook_seek(URLContext *h, int64_t pos, int whence) { Context *c = h->priv_data; int ret = 0; int64_t seek_ret = -1; if (whence == AVSEEK_SIZE) return c->logical_size; else if ((whence == SEEK_CUR && pos == 0) || (whence == SEEK_SET && pos == c->logical_pos)) return c->logical_pos; else if ((c->logical_size < 0 && whence == SEEK_END) || h->is_streamed) return AVERROR(ENOSYS); c->app_io_ctrl.retry_counter = 0; ret = ijkurlhook_call_inject(h); if (ret) { ret = AVERROR_EXIT; goto fail; } seek_ret = ijkhttphook_reseek_at(h, pos, whence, c->app_io_ctrl.is_url_changed); while (seek_ret < 0) { switch (seek_ret) { case AVERROR_EXIT: case AVERROR_EOF: goto fail; } c->app_io_ctrl.retry_counter++; ret = ijkurlhook_call_inject(h); if (ret) { ret = AVERROR_EXIT; goto fail; } if (!c->app_io_ctrl.is_handled) goto fail; av_log(h, AV_LOG_INFO, "%s: will reseek(%d) at pos=%"PRId64", whence=%d\n", __func__, c->app_io_ctrl.retry_counter, pos, whence); seek_ret = ijkhttphook_reseek_at(h, pos, whence, c->app_io_ctrl.is_url_changed); av_log(h, AV_LOG_INFO, "%s: did reseek(%d) at pos=%"PRId64", whence=%d: %"PRId64"\n", __func__, c->app_io_ctrl.retry_counter, pos, whence, seek_ret); } if (c->test_fail_point) c->test_fail_point_next = c->logical_pos + c->test_fail_point; c->io_error = 0; return c->logical_pos; fail: return ret; } #define OFFSET(x) offsetof(Context, x) #define D AV_OPT_FLAG_DECODING_PARAM static const AVOption ijktcphook_options[] = { { "ijktcphook-test-fail-point", "test fail point, in bytes", OFFSET(test_fail_point), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D }, { "ijkapplication", "AVApplicationContext", OFFSET(app_ctx_intptr), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, .flags = D }, { NULL } }; static const AVOption ijkhttphook_options[] = { { "ijkinject-segment-index", "segment index of current url", OFFSET(segment_index), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D }, { "ijkhttphook-test-fail-point", "test fail point, in bytes", OFFSET(test_fail_point), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D }, { "ijkapplication", "AVApplicationContext", OFFSET(app_ctx_intptr), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, .flags = D }, { NULL } }; #undef D #undef OFFSET static const AVClass ijktcphook_context_class = { .class_name = "TcpHook", .item_name = av_default_item_name, .option = ijktcphook_options, .version = LIBAVUTIL_VERSION_INT, }; URLProtocol ijkimp_ff_ijktcphook_protocol = { .name = "ijktcphook", .url_open2 = ijktcphook_open, .url_read = ijkurlhook_read, .url_write = ijkurlhook_write, .url_close = ijkurlhook_close, .priv_data_size = sizeof(Context), .priv_data_class = &ijktcphook_context_class, }; static const AVClass ijkhttphook_context_class = { .class_name = "HttpHook", .item_name = av_default_item_name, .option = ijkhttphook_options, .version = LIBAVUTIL_VERSION_INT, }; URLProtocol ijkimp_ff_ijkhttphook_protocol = { .name = "ijkhttphook", .url_open2 = ijkhttphook_open, .url_read = ijkhttphook_read, .url_write = ijkurlhook_write, .url_seek = ijkhttphook_seek, .url_close = ijkurlhook_close, .priv_data_size = sizeof(Context), .priv_data_class = &ijkhttphook_context_class, }; ================================================ FILE: ijkmedia/ijkplayer/ijkavutil/ijkdict.c ================================================ /* * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Raymond Zheng * * This file is part of FFmpeg. * * FFmpeg 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. * * FFmpeg 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 FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijkdict.h" #include "ijkutils.h" #include #include #include #include #include struct IjkAVDictionary { int count; IjkAVDictionaryEntry *elems; }; int ijk_av_dict_count(const IjkAVDictionary *m) { return m ? m->count : 0; } IjkAVDictionaryEntry *ijk_av_dict_get(const IjkAVDictionary *m, const char *key, const IjkAVDictionaryEntry *prev, int flags) { unsigned int i, j; if (!m) return NULL; if (prev) i = prev - m->elems + 1; else i = 0; for (; i < m->count; i++) { const char *s = m->elems[i].key; if (flags & IJK_AV_DICT_MATCH_CASE) for (j = 0; s[j] == key[j] && key[j]; j++) ; else for (j = 0; toupper(s[j]) == toupper(key[j]) && key[j]; j++) ; if (key[j]) continue; if (s[j] && !(flags & IJK_AV_DICT_IGNORE_SUFFIX)) continue; return &m->elems[i]; } return NULL; } int ijk_av_dict_set(IjkAVDictionary **pm, const char *key, const char *value, int flags) { IjkAVDictionary *m = *pm; IjkAVDictionaryEntry *tag = NULL; char *oldval = NULL, *copy_key = NULL, *copy_value = NULL; if (!(flags & IJK_AV_DICT_MULTIKEY)) { tag = ijk_av_dict_get(m, key, NULL, flags); } if (flags & IJK_AV_DICT_DONT_STRDUP_KEY) copy_key = (void *)key; else copy_key = strdup(key); if (flags & IJK_AV_DICT_DONT_STRDUP_VAL) copy_value = (void *)value; else if (copy_key) copy_value = strdup(value); if (!m) m = *pm = (IjkAVDictionary *)calloc(1, sizeof(*m)); if (!m || (key && !copy_key) || (value && !copy_value)) goto err_out; if (tag) { if (flags & IJK_AV_DICT_DONT_OVERWRITE) { free(copy_key); free(copy_value); return 0; } if (flags & IJK_AV_DICT_APPEND) oldval = tag->value; else free(tag->value); free(tag->key); *tag = m->elems[--m->count]; } else if (copy_value) { IjkAVDictionaryEntry *tmp = (IjkAVDictionaryEntry *)realloc(m->elems, (m->count + 1) * sizeof(*m->elems)); if (!tmp) goto err_out; m->elems = tmp; } if (copy_value) { m->elems[m->count].key = copy_key; m->elems[m->count].value = copy_value; if (oldval && flags & IJK_AV_DICT_APPEND) { size_t len = strlen(oldval) + strlen(copy_value) + 1; char *newval = (char *)calloc(1, len); if (!newval) goto err_out; strlcat(newval, oldval, len); ijk_av_freep(&oldval); strlcat(newval, copy_value, len); m->elems[m->count].value = newval; ijk_av_freep(©_value); } m->count++; } else { ijk_av_freep(©_key); } if (!m->count) { ijk_av_freep(&m->elems); ijk_av_freep(pm); } return 0; err_out: if (m && !m->count) { ijk_av_freep(&m->elems); ijk_av_freep(pm); } free(copy_key); free(copy_value); return -1; } int ijk_av_dict_set_int(IjkAVDictionary **pm, const char *key, int64_t value, int flags) { char valuestr[22]; snprintf(valuestr, sizeof(valuestr), "%"PRId64, value); flags &= ~IJK_AV_DICT_DONT_STRDUP_VAL; return ijk_av_dict_set(pm, key, valuestr, flags); } int ijk_av_dict_set_intptr(IjkAVDictionary **pm, const char *key, uintptr_t value, int flags) { char valuestr[22]; snprintf(valuestr, sizeof(valuestr), "%p", value); flags &= ~IJK_AV_DICT_DONT_STRDUP_VAL; return ijk_av_dict_set(pm, key, valuestr, flags); } uintptr_t ijk_av_dict_strtoptr(char * value) { uintptr_t ptr = NULL; char *next = NULL; if(value[0] !='0' || (value[1]|0x20)!='x') { return NULL; } ptr = strtoll(value, &next, 16); if (next == value) { return NULL; } return ptr; } uintptr_t ijk_av_dict_get_intptr(const IjkAVDictionary *m, const char* key) { uintptr_t ptr = NULL; IjkAVDictionaryEntry *t = NULL; if ((t = av_dict_get(m, key, NULL, 0))) { return ijk_av_dict_strtoptr(t->value); } return NULL; } void ijk_av_dict_free(IjkAVDictionary **pm) { IjkAVDictionary *m = *pm; if (m) { while (m->count--) { ijk_av_freep(&m->elems[m->count].key); ijk_av_freep(&m->elems[m->count].value); } ijk_av_freep(&m->elems); } ijk_av_freep(pm); } int ijk_av_dict_copy(IjkAVDictionary **dst, const IjkAVDictionary *src, int flags) { IjkAVDictionaryEntry *t = NULL; while ((t = ijk_av_dict_get(src, "", t, IJK_AV_DICT_IGNORE_SUFFIX))) { int ret = ijk_av_dict_set(dst, t->key, t->value, flags); if (ret < 0) return ret; } return 0; } ================================================ FILE: ijkmedia/ijkplayer/ijkavutil/ijkdict.h ================================================ /* * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * Public dictionary API. * @deprecated * AVDictionary is provided for compatibility with libav. It is both in * implementation as well as API inefficient. It does not scale and is * extremely slow with large dictionaries. * It is recommended that new code uses our tree container from tree.c/h * where applicable, which uses AVL trees to achieve O(log n) performance. */ #ifndef IJKAVUTIL_IJKDICT_H #define IJKAVUTIL_IJKDICT_H #include #define IJK_AV_DICT_MATCH_CASE 1 /**< Only get an entry with exact-case key match. Only relevant in av_dict_get(). */ #define IJK_AV_DICT_IGNORE_SUFFIX 2 /**< Return first entry in a dictionary whose first part corresponds to the search key, ignoring the suffix of the found key string. Only relevant in av_dict_get(). */ #define IJK_AV_DICT_DONT_STRDUP_KEY 4 /**< Take ownership of a key that's been allocated with av_malloc() or another memory allocation function. */ #define IJK_AV_DICT_DONT_STRDUP_VAL 8 /**< Take ownership of a value that's been allocated with av_malloc() or another memory allocation function. */ #define IJK_AV_DICT_DONT_OVERWRITE 16 ///< Don't overwrite existing entries. #define IJK_AV_DICT_APPEND 32 /**< If the entry already exists, append to it. Note that no delimiter is added, the strings are simply concatenated. */ #define IJK_AV_DICT_MULTIKEY 64 /**< Allow to store several equal keys in the dictionary */ typedef struct IjkAVDictionaryEntry { char *key; char *value; } IjkAVDictionaryEntry; typedef struct IjkAVDictionary IjkAVDictionary; /** * Get a dictionary entry with matching key. * * The returned entry key or value must not be changed, or it will * cause undefined behavior. * * To iterate through all the dictionary entries, you can set the matching key * to the null string "" and set the AV_DICT_IGNORE_SUFFIX flag. * * @param prev Set to the previous matching element to find the next. * If set to NULL the first matching element is returned. * @param key matching key * @param flags a collection of AV_DICT_* flags controlling how the entry is retrieved * @return found entry or NULL in case no matching entry was found in the dictionary */ IjkAVDictionaryEntry *ijk_av_dict_get(const IjkAVDictionary *m, const char *key, const IjkAVDictionaryEntry *prev, int flags); /** * Get number of entries in dictionary. * * @param m dictionary * @return number of entries in dictionary */ int ijk_av_dict_count(const IjkAVDictionary *m); /** * Set the given entry in *pm, overwriting an existing entry. * * Note: If AV_DICT_DONT_STRDUP_KEY or AV_DICT_DONT_STRDUP_VAL is set, * these arguments will be freed on error. * * Warning: Adding a new entry to a dictionary invalidates all existing entries * previously returned with av_dict_get. * * @param pm pointer to a pointer to a dictionary struct. If *pm is NULL * a dictionary struct is allocated and put in *pm. * @param key entry key to add to *pm (will either be av_strduped or added as a new key depending on flags) * @param value entry value to add to *pm (will be av_strduped or added as a new key depending on flags). * Passing a NULL value will cause an existing entry to be deleted. * @return >= 0 on success otherwise an error code <0 */ int ijk_av_dict_set(IjkAVDictionary **pm, const char *key, const char *value, int flags); /** * Convenience wrapper for av_dict_set that converts the value to a string * and stores it. * * Note: If AV_DICT_DONT_STRDUP_KEY is set, key will be freed on error. */ int ijk_av_dict_set_int(IjkAVDictionary **pm, const char *key, int64_t value, int flags); int ijk_av_dict_set_intptr(IjkAVDictionary **pm, const char *key, uintptr_t value, int flags); uintptr_t ijk_av_dict_get_intptr(const IjkAVDictionary *m, const char* key); /** * Copy entries from one AVDictionary struct into another. * @param dst pointer to a pointer to a AVDictionary struct. If *dst is NULL, * this function will allocate a struct for you and put it in *dst * @param src pointer to source AVDictionary struct * @param flags flags to use when setting entries in *dst * @note metadata is read using the AV_DICT_IGNORE_SUFFIX flag * @return 0 on success, negative AVERROR code on failure. If dst was allocated * by this function, callers should free the associated memory. */ int ijk_av_dict_copy(IjkAVDictionary **dst, const IjkAVDictionary *src, int flags); /** * Free all the memory allocated for an AVDictionary struct * and all keys and values. */ void ijk_av_dict_free(IjkAVDictionary **m); /** * @} */ #endif /* IJKAVUTIL_IJKDICT_H */ ================================================ FILE: ijkmedia/ijkplayer/ijkavutil/ijkfifo.c ================================================ /* * a very simple circular buffer FIFO implementation * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * Copyright (c) 2006 Roman Shaposhnik * * This file is part of Ijkplayer. * * Ijkplayer 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. * * Ijkplayer 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 Ijkplayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijkfifo.h" #include "ijkutils.h" #include #include #include static IjkFifoBuffer *fifo_alloc_common(void *buffer, size_t size) { IjkFifoBuffer *f; if (!buffer) return NULL; f = calloc(1, sizeof(IjkFifoBuffer)); if (!f) { free(buffer); return NULL; } f->buffer = buffer; f->end = f->buffer + size; ijk_av_fifo_reset(f); return f; } IjkFifoBuffer *ijk_av_fifo_alloc(unsigned int size) { void *buffer = malloc(size); return fifo_alloc_common(buffer, size); } IjkFifoBuffer *ijk_av_fifo_alloc_array(size_t nmemb, size_t size) { void *buffer = calloc(nmemb, size); return fifo_alloc_common(buffer, nmemb * size); } void ijk_av_fifo_free(IjkFifoBuffer *f) { if (f) { ijk_av_freep(&f->buffer); free(f); } } void ijk_av_fifo_freep(IjkFifoBuffer **f) { if (f) { ijk_av_fifo_free(*f); *f = NULL; } } void ijk_av_fifo_reset(IjkFifoBuffer *f) { f->wptr = f->rptr = f->buffer; f->wndx = f->rndx = 0; } int ijk_av_fifo_size(const IjkFifoBuffer *f) { return (uint32_t)(f->wndx - f->rndx); } int ijk_av_fifo_space(const IjkFifoBuffer *f) { return f->end - f->buffer - ijk_av_fifo_size(f); } int ijk_av_fifo_realloc2(IjkFifoBuffer *f, unsigned int new_size) { unsigned int old_size = f->end - f->buffer; if (old_size < new_size) { int len = ijk_av_fifo_size(f); IjkFifoBuffer *f2 = ijk_av_fifo_alloc(new_size); if (!f2) return -1; ijk_av_fifo_generic_read(f, f2->buffer, len, NULL); f2->wptr += len; f2->wndx += len; free(f->buffer); *f = *f2; free(f2); } return 0; } int ijk_av_fifo_grow(IjkFifoBuffer *f, unsigned int size) { unsigned int old_size = f->end - f->buffer; if(size + (unsigned)ijk_av_fifo_size(f) < size) return -1; size += ijk_av_fifo_size(f); if (old_size < size) return ijk_av_fifo_realloc2(f, FFMAX(size, 2*old_size)); return 0; } /* src must NOT be const as it can be a context for func that may need * updating (like a pointer or byte counter) */ int ijk_av_fifo_generic_write(IjkFifoBuffer *f, void *src, int size, int (*func)(void *, void *, int)) { int total = size; uint32_t wndx= f->wndx; uint8_t *wptr= f->wptr; do { int len = FFMIN(f->end - wptr, size); if (func) { len = func(src, wptr, len); if (len <= 0) break; } else { memcpy(wptr, src, len); src = (uint8_t *)src + len; } // Write memory barrier needed for SMP here in theory wptr += len; if (wptr >= f->end) wptr = f->buffer; wndx += len; size -= len; } while (size > 0); f->wndx= wndx; f->wptr= wptr; return total - size; } int ijk_av_fifo_generic_peek_at(IjkFifoBuffer *f, void *dest, int offset, int buf_size, void (*func)(void*, void*, int)) { uint8_t *rptr = f->rptr; assert(offset >= 0); /* * *ndx are indexes modulo 2^32, they are intended to overflow, * to handle *ndx greater than 4gb. */ assert(buf_size + (unsigned)offset <= f->wndx - f->rndx); if (offset >= f->end - rptr) rptr += offset - (f->end - f->buffer); else rptr += offset; while (buf_size > 0) { int len; if (rptr >= f->end) rptr -= f->end - f->buffer; len = FFMIN(f->end - rptr, buf_size); if (func) func(dest, rptr, len); else { memcpy(dest, rptr, len); dest = (uint8_t *)dest + len; } buf_size -= len; rptr += len; } return 0; } int ijk_av_fifo_generic_peek(IjkFifoBuffer *f, void *dest, int buf_size, void (*func)(void *, void *, int)) { // Read memory barrier needed for SMP here in theory uint8_t *rptr = f->rptr; do { int len = FFMIN(f->end - rptr, buf_size); if (func) func(dest, rptr, len); else { memcpy(dest, rptr, len); dest = (uint8_t *)dest + len; } // memory barrier needed for SMP here in theory rptr += len; if (rptr >= f->end) rptr -= f->end - f->buffer; buf_size -= len; } while (buf_size > 0); return 0; } int ijk_av_fifo_generic_read(IjkFifoBuffer *f, void *dest, int buf_size, void (*func)(void *, void *, int)) { // Read memory barrier needed for SMP here in theory do { int len = FFMIN(f->end - f->rptr, buf_size); if (func) func(dest, f->rptr, len); else { memcpy(dest, f->rptr, len); dest = (uint8_t *)dest + len; } // memory barrier needed for SMP here in theory ijk_av_fifo_drain(f, len); buf_size -= len; } while (buf_size > 0); return 0; } /** Discard data from the FIFO. */ void ijk_av_fifo_drain(IjkFifoBuffer *f, int size) { assert(ijk_av_fifo_size(f) >= size); f->rptr += size; if (f->rptr >= f->end) f->rptr -= f->end - f->buffer; f->rndx += size; } ================================================ FILE: ijkmedia/ijkplayer/ijkavutil/ijkfifo.h ================================================ /* * This file is part of Ijkplayer. * * Ijkplayer 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. * * Ijkplayer 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 Ijkplayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * a very simple circular buffer FIFO implementation */ #ifndef IJKUTIL_IJKFIFO_H #define IJKUTIL_IJKFIFO_H #include #include typedef struct IjkFifoBuffer { uint8_t *buffer; uint8_t *rptr, *wptr, *end; uint64_t rndx, wndx; } IjkFifoBuffer; /** * Initialize an IjkFifoBuffer. * @param size of FIFO * @return IjkFifoBuffer or NULL in case of memory allocation failure */ IjkFifoBuffer *ijk_av_fifo_alloc(unsigned int size); /** * Initialize an IjkFifoBuffer. * @param nmemb number of elements * @param size size of the single element * @return IjkFifoBuffer or NULL in case of memory allocation failure */ IjkFifoBuffer *ijk_av_fifo_alloc_array(size_t nmemb, size_t size); /** * Free an IjkFifoBuffer. * @param f IjkFifoBuffer to free */ void ijk_av_fifo_free(IjkFifoBuffer *f); /** * Free an IjkFifoBuffer and reset pointer to NULL. * @param f IjkFifoBuffer to free */ void ijk_av_fifo_freep(IjkFifoBuffer **f); /** * Reset the IjkFifoBuffer to the state right after ijk_av_fifo_alloc, in particular it is emptied. * @param f IjkFifoBuffer to reset */ void ijk_av_fifo_reset(IjkFifoBuffer *f); /** * Return the amount of data in bytes in the IjkFifoBuffer, that is the * amount of data you can read from it. * @param f IjkFifoBuffer to read from * @return size */ int ijk_av_fifo_size(const IjkFifoBuffer *f); /** * Return the amount of space in bytes in the IjkFifoBuffer, that is the * amount of data you can write into it. * @param f IjkFifoBuffer to write into * @return size */ int ijk_av_fifo_space(const IjkFifoBuffer *f); /** * Feed data at specific position from an IjkFifoBuffer to a user-supplied callback. * Similar as ijk_av_fifo_gereric_read but without discarding data. * @param f IjkFifoBuffer to read from * @param offset offset from current read position * @param buf_size number of bytes to read * @param func generic read function * @param dest data destination */ int ijk_av_fifo_generic_peek_at(IjkFifoBuffer *f, void *dest, int offset, int buf_size, void (*func)(void*, void*, int)); /** * Feed data from an IjkFifoBuffer to a user-supplied callback. * Similar as ijk_av_fifo_gereric_read but without discarding data. * @param f IjkFifoBuffer to read from * @param buf_size number of bytes to read * @param func generic read function * @param dest data destination */ int ijk_av_fifo_generic_peek(IjkFifoBuffer *f, void *dest, int buf_size, void (*func)(void*, void*, int)); /** * Feed data from an IjkFifoBuffer to a user-supplied callback. * @param f IjkFifoBuffer to read from * @param buf_size number of bytes to read * @param func generic read function * @param dest data destination */ int ijk_av_fifo_generic_read(IjkFifoBuffer *f, void *dest, int buf_size, void (*func)(void*, void*, int)); /** * Feed data from a user-supplied callback to an IjkFifoBuffer. * @param f IjkFifoBuffer to write to * @param src data source; non-const since it may be used as a * modifiable context by the function defined in func * @param size number of bytes to write * @param func generic write function; the first parameter is src, * the second is dest_buf, the third is dest_buf_size. * func must return the number of bytes written to dest_buf, or <= 0 to * indicate no more data available to write. * If func is NULL, src is interpreted as a simple byte array for source data. * @return the number of bytes written to the FIFO */ int ijk_av_fifo_generic_write(IjkFifoBuffer *f, void *src, int size, int (*func)(void*, void*, int)); /** * Resize an IjkFifoBuffer. * In case of reallocation failure, the old FIFO is kept unchanged. * * @param f IjkFifoBuffer to resize * @param size new IjkFifoBuffer size in bytes * @return <0 for failure, >=0 otherwise */ int ijk_av_fifo_realloc2(IjkFifoBuffer *f, unsigned int size); /** * Enlarge an IjkFifoBuffer. * In case of reallocation failure, the old FIFO is kept unchanged. * The new fifo size may be larger than the requested size. * * @param f IjkFifoBuffer to resize * @param additional_space the amount of space in bytes to allocate in addition to ijk_av_fifo_size() * @return <0 for failure, >=0 otherwise */ int ijk_av_fifo_grow(IjkFifoBuffer *f, unsigned int additional_space); /** * Read and discard the specified amount of data from an IjkFifoBuffer. * @param f IjkFifoBuffer to read from * @param size amount of data to read in bytes */ void ijk_av_fifo_drain(IjkFifoBuffer *f, int size); /** * Return a pointer to the data stored in a FIFO buffer at a certain offset. * The FIFO buffer is not modified. * * @param f IjkFifoBuffer to peek at, f must be non-NULL * @param offs an offset in bytes, its absolute value must be less * than the used buffer size or the returned pointer will * point outside to the buffer data. * The used buffer size can be checked with ijk_av_fifo_size(). */ static inline uint8_t *ijk_av_fifo_peek2(const IjkFifoBuffer *f, int offs) { uint8_t *ptr = f->rptr + offs; if (ptr >= f->end) ptr = f->buffer + (ptr - f->end); else if (ptr < f->buffer) ptr = f->end - (f->buffer - ptr); return ptr; } #endif /* IJKUTIL_IJKFIFO_H */ ================================================ FILE: ijkmedia/ijkplayer/ijkavutil/ijkstl.cpp ================================================ /* * Copyright (c) 2016 Raymond Zheng * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include using namespace std; typedef map IjkMap; extern "C" void* ijk_map_create(); extern "C" void ijk_map_put(void *data, int64_t key, void *value); extern "C" void* ijk_map_get(void *data, int64_t key); extern "C" int ijk_map_remove(void *data, int64_t key); extern "C" int ijk_map_size(void *data); extern "C" int ijk_map_max_size(void *data); extern "C" void* ijk_map_index_get(void *data, int index); extern "C" int64_t ijk_map_get_min_key(void *data); extern "C" void ijk_map_clear(void *data); extern "C" void ijk_map_destroy(void *data); extern "C" void ijk_map_traversal_handle(void *data, void *parm, int (*enu)(void *parm, int64_t key, void *elem)); void* ijk_map_create() { IjkMap *data = new IjkMap(); return data; } void ijk_map_put(void *data, int64_t key, void *value) { IjkMap *map_data = reinterpret_cast(data); if (!map_data) return; (*map_data)[key] = value; } void* ijk_map_get(void *data, int64_t key) { IjkMap *map_data = reinterpret_cast(data); if (!map_data) return NULL; IjkMap::iterator it = map_data->find(key); if (it != map_data->end()) { return it->second; } return NULL; } int ijk_map_remove(void *data, int64_t key) { IjkMap *map_data = reinterpret_cast(data); if (!map_data) return -1; map_data->erase(key); return 0; } int ijk_map_size(void *data) { IjkMap *map_data = reinterpret_cast(data); if (!map_data) return 0; return map_data->size(); } int ijk_map_max_size(void *data) { IjkMap *map_data = reinterpret_cast(data); if (!map_data) return 0; return map_data->max_size(); } void* ijk_map_index_get(void *data, int index) { IjkMap *map_data = reinterpret_cast(data); if (!map_data || map_data->empty()) return NULL; IjkMap::iterator it; it = map_data->begin(); for (int i = 0; i < index; i++) { it = it++; if (it == map_data->end()) { return NULL; } } return it->second; } void ijk_map_traversal_handle(void *data, void *parm, int (*enu)(void *parm, int64_t key, void *elem)) { IjkMap *map_data = reinterpret_cast(data); if (!map_data || map_data->empty()) return; IjkMap::iterator it; for (it = map_data->begin(); it != map_data->end(); it++) { enu(parm, it->first, it->second); } } int64_t ijk_map_get_min_key(void *data) { IjkMap *map_data = reinterpret_cast(data); if (!map_data || map_data->empty()) return -1; IjkMap::iterator it = map_data->begin(); int64_t min_key = it->first; for (; it != map_data->end(); it++) { min_key = min_key < it->first ? min_key : it->first; } return min_key; } void ijk_map_clear(void *data) { IjkMap *map_data = reinterpret_cast(data); if (!map_data) return; map_data->clear(); } void ijk_map_destroy(void *data) { IjkMap *map_data = reinterpret_cast(data); if (!map_data) return; map_data->clear(); delete(map_data); } ================================================ FILE: ijkmedia/ijkplayer/ijkavutil/ijkstl.h ================================================ /* * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Raymond Zheng * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKAVUTIL_IJKSTL_H #define IJKAVUTIL_IJKSTL_H #include void* ijk_map_create(); void ijk_map_put(void *data, int64_t key, void *value); void* ijk_map_get(void *data, int64_t key); int ijk_map_remove(void *data, int64_t key); int ijk_map_size(void *data); int ijk_map_max_size(void *data); void* ijk_map_index_get(void *data, int index); void ijk_map_traversal_handle(void *data, void *parm, int (*enu)(void *parm, int64_t key, void *elem)); int64_t ijk_map_get_min_key(void *data); void ijk_map_clear(void *data); void ijk_map_destroy(void *data); #endif /* IJKAVUTIL_IJKSTL_H */ ================================================ FILE: ijkmedia/ijkplayer/ijkavutil/ijkthreadpool.c ================================================ /* * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Raymond Zheng * * This file is part of ijkplayer. * * ijkplayer 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. * * ijkplayer 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 ijkplayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijkthreadpool.h" #include "libavutil/log.h" #include #include /** * @function void *threadpool_thread(void *threadpool) * @brief the worker thread * @param threadpool the pool which own the thread */ static void *ijk_threadpool_thread(void *pool_ctx) { IjkThreadPoolContext *ctx = (IjkThreadPoolContext *)pool_ctx; IjkThreadPoolTask task; for(;;) { pthread_mutex_lock(&(ctx->lock)); while((ctx->pending_count == 0) && (!ctx->shutdown)) { pthread_cond_wait(&(ctx->notify), &(ctx->lock)); } if((ctx->shutdown == IJK_IMMEDIATE_SHUTDOWN) || ((ctx->shutdown == IJK_LEISURELY_SHUTDOWN) && (ctx->pending_count == 0))) { break; } /* Grab our task */ task.function = ctx->queue[ctx->queue_head].function; task.in_arg = ctx->queue[ctx->queue_head].in_arg; task.out_arg = ctx->queue[ctx->queue_head].out_arg; ctx->queue_head = (ctx->queue_head + 1) % ctx->queue_size; ctx->pending_count -= 1; pthread_mutex_unlock(&(ctx->lock)); (*(task.function))(task.in_arg, task.out_arg); } ctx->started_count--; pthread_mutex_unlock(&(ctx->lock)); pthread_exit(NULL); return(NULL); } int ijk_threadpool_free(IjkThreadPoolContext *ctx) { if(ctx == NULL || ctx->started_count > 0) { return -1; } /* Did we manage to allocate ? */ if(ctx->threads) { free(ctx->threads); free(ctx->queue); /* Because we allocate pool->threads after initializing the mutex and condition variable, we're sure they're initialized. Let's lock the mutex just in case. */ pthread_mutex_lock(&(ctx->lock)); pthread_mutex_destroy(&(ctx->lock)); pthread_cond_destroy(&(ctx->notify)); } free(ctx); return 0; } IjkThreadPoolContext *ijk_threadpool_create(int thread_count, int queue_size, int flags) { IjkThreadPoolContext *ctx; int i; if(thread_count <= 0 || thread_count > MAX_THREADS || queue_size <= 0 || queue_size > MAX_QUEUE) { return NULL; } if((ctx = (IjkThreadPoolContext *)calloc(1, sizeof(IjkThreadPoolContext))) == NULL) { goto err; } ctx->queue_size = queue_size; /* Allocate thread and task queue */ ctx->threads = (pthread_t *)calloc(1, sizeof(pthread_t) * thread_count); ctx->queue = (IjkThreadPoolTask *)calloc (queue_size, sizeof(IjkThreadPoolTask)); /* Initialize mutex and conditional variable first */ if((pthread_mutex_init(&(ctx->lock), NULL) != 0) || (pthread_cond_init(&(ctx->notify), NULL) != 0) || (ctx->threads == NULL) || (ctx->queue == NULL)) { goto err; } /* Start worker threads */ for(i = 0; i < thread_count; i++) { if(pthread_create(&(ctx->threads[i]), NULL, ijk_threadpool_thread, (void*)ctx) != 0) { ijk_threadpool_destroy(ctx, 0); return NULL; } ctx->thread_count++; ctx->started_count++; } return ctx; err: if(ctx) { ijk_threadpool_free(ctx); } return NULL; } int ijk_threadpool_add(IjkThreadPoolContext *ctx, Runable function, void *in_arg, void *out_arg, int flags) { int err = 0; int next; if(ctx == NULL || function == NULL) { return IJK_THREADPOOL_INVALID; } if(pthread_mutex_lock(&(ctx->lock)) != 0) { return IJK_THREADPOOL_LOCK_FAILURE; } if (ctx->pending_count == MAX_QUEUE || ctx->pending_count == ctx->queue_size) { pthread_mutex_unlock(&ctx->lock); return IJK_THREADPOOL_QUEUE_FULL; } if(ctx->pending_count == ctx->queue_size - 1) { int new_pueue_size = (ctx->queue_size * 2) > MAX_QUEUE ? MAX_QUEUE : (ctx->queue_size * 2); IjkThreadPoolTask *new_queue = (IjkThreadPoolTask *)realloc(ctx->queue, sizeof(IjkThreadPoolTask) * new_pueue_size); if (new_queue) { ctx->queue = new_queue; ctx->queue_size = new_pueue_size; } } next = (ctx->queue_tail + 1) % ctx->queue_size; do { /* Are we shutting down ? */ if(ctx->shutdown) { err = IJK_THREADPOOL_SHUTDOWN; break; } /* Add task to queue */ ctx->queue[ctx->queue_tail].function = function; ctx->queue[ctx->queue_tail].in_arg = in_arg; ctx->queue[ctx->queue_tail].out_arg = out_arg; ctx->queue_tail = next; ctx->pending_count += 1; /* pthread_cond_broadcast */ if(pthread_cond_signal(&(ctx->notify)) != 0) { err = IJK_THREADPOOL_LOCK_FAILURE; break; } } while(0); if(pthread_mutex_unlock(&ctx->lock) != 0) { err = IJK_THREADPOOL_LOCK_FAILURE; } return err; } static int ijk_threadpool_freep(IjkThreadPoolContext **ctx) { int ret = 0; if (!ctx || !*ctx) return -1; ret = ijk_threadpool_free(*ctx); *ctx = NULL; return ret; } int ijk_threadpool_destroy(IjkThreadPoolContext *ctx, int flags) { int i, err = 0; if(ctx == NULL) { return IJK_THREADPOOL_INVALID; } if(pthread_mutex_lock(&(ctx->lock)) != 0) { return IJK_THREADPOOL_LOCK_FAILURE; } do { /* Already shutting down */ if(ctx->shutdown) { err = IJK_THREADPOOL_SHUTDOWN; break; } ctx->shutdown = flags; /* Wake up all worker threads */ if((pthread_cond_broadcast(&(ctx->notify)) != 0) || (pthread_mutex_unlock(&(ctx->lock)) != 0)) { err = IJK_THREADPOOL_LOCK_FAILURE; break; } /* Join all worker thread */ for(i = 0; i < ctx->thread_count; i++) { if(pthread_join(ctx->threads[i], NULL) != 0) { err = IJK_THREADPOOL_THREAD_FAILURE; } } } while(0); /* Only if everything went well do we deallocate the pool */ if(!err) { return ijk_threadpool_freep(&ctx); } return err; } ================================================ FILE: ijkmedia/ijkplayer/ijkavutil/ijkthreadpool.h ================================================ /* * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _IJK_THREADPOOL_H_ #define _IJK_THREADPOOL_H_ #include #define MAX_THREADS 100 #define MAX_QUEUE 1024 typedef enum { IJK_THREADPOOL_INVALID = -1, IJK_THREADPOOL_LOCK_FAILURE = -2, IJK_THREADPOOL_QUEUE_FULL = -3, IJK_THREADPOOL_SHUTDOWN = -4, IJK_THREADPOOL_THREAD_FAILURE = -5 } IjkThreadPoolErrorType; typedef enum { IJK_IMMEDIATE_SHUTDOWN = 1, IJK_LEISURELY_SHUTDOWN = 2 } IjkThreadPoolShutdownType; typedef void (*Runable)(void *, void *); /** * @struct ThreadPoolTask * @brief the work struct * * @var function Pointer to the function that will perform the task. * @var in_arg Argument to be passed to the function. * @var out_arg Argument to be passed to the call function. */ typedef struct IjkThreadPoolTask { Runable function; void *in_arg; void *out_arg; } IjkThreadPoolTask; /** * @struct ThreadPoolContext * @brief The threadpool context struct * * @var notify Condition variable to notify worker threads. * @var threads Array containing worker threads ID. * @var thread_count Number of threads * @var queue Array containing the task queue. * @var queue_size Size of the task queue. * @var queue_head Index of the first element. * @var queue_tail Index of the next element. * @var pending_count Number of pending tasks * @var shutdown Flag indicating if the pool is shutting down * @var started Number of started threads */ typedef struct IjkThreadPoolContext { pthread_mutex_t lock; pthread_cond_t notify; pthread_t *threads; IjkThreadPoolTask *queue; int thread_count; int queue_size; int queue_head; int queue_tail; int pending_count; int shutdown; int started_count; } IjkThreadPoolContext; IjkThreadPoolContext *ijk_threadpool_create(int thread_count, int queue_size, int flags); int ijk_threadpool_add(IjkThreadPoolContext *ctx, Runable function, void *in_arg, void *out_arg, int flags); int ijk_threadpool_destroy(IjkThreadPoolContext *ctx, int flags); #endif /* _IJK_THREADPOOL_H_ */ ================================================ FILE: ijkmedia/ijkplayer/ijkavutil/ijktree.c ================================================ /* * copyright (c) 2006 Michael Niedermayer * * This file is part of FFmpeg. * * FFmpeg 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. * * FFmpeg 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 FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijktree.h" #include #include #include #include typedef struct IjkAVTreeNode { struct IjkAVTreeNode *child[2]; void *elem; int state; } IjkAVTreeNode; const int ijk_av_tree_node_size = sizeof(IjkAVTreeNode); struct IjkAVTreeNode *ijk_av_tree_node_alloc(void) { return calloc(1, sizeof(struct IjkAVTreeNode)); } void *ijk_av_tree_find(const IjkAVTreeNode *t, void *key, int (*cmp)(const void *key, const void *b), void *next[2]) { if (t) { unsigned int v = cmp(key, t->elem); if (v) { if (next) next[v >> 31] = t->elem; return ijk_av_tree_find(t->child[(v >> 31) ^ 1], key, cmp, next); } else { if (next) { ijk_av_tree_find(t->child[0], key, cmp, next); ijk_av_tree_find(t->child[1], key, cmp, next); } return t->elem; } } return NULL; } void *ijk_av_tree_insert(IjkAVTreeNode **tp, void *key, int (*cmp)(const void *key, const void *b), IjkAVTreeNode **next) { IjkAVTreeNode *t = *tp; if (t) { unsigned int v = cmp(t->elem, key); void *ret; if (!v) { if (*next) return t->elem; else if (t->child[0] || t->child[1]) { int i = !t->child[0]; void *next_elem[2]; ijk_av_tree_find(t->child[i], key, cmp, next_elem); key = t->elem = next_elem[i]; v = -i; } else { *next = t; *tp = NULL; return NULL; } } ret = ijk_av_tree_insert(&t->child[v >> 31], key, cmp, next); if (!ret) { int i = (v >> 31) ^ !!*next; IjkAVTreeNode **child = &t->child[i]; t->state += 2 * i - 1; if (!(t->state & 1)) { if (t->state) { /* The following code is equivalent to * if ((*child)->state * 2 == -t->state) * rotate(child, i ^ 1); * rotate(tp, i); * * with rotate(): * static void rotate(AVTreeNode **tp, int i) * { * AVTreeNode *t= *tp; * * *tp = t->child[i]; * t->child[i] = t->child[i]->child[i ^ 1]; * (*tp)->child[i ^ 1] = t; * i = 4 * t->state + 2 * (*tp)->state + 12; * t->state = ((0x614586 >> i) & 3) - 1; * (*tp)->state = ((0x400EEA >> i) & 3) - 1 + * ((*tp)->state >> 1); * } * but such a rotate function is both bigger and slower */ if ((*child)->state * 2 == -t->state) { *tp = (*child)->child[i ^ 1]; (*child)->child[i ^ 1] = (*tp)->child[i]; (*tp)->child[i] = *child; *child = (*tp)->child[i ^ 1]; (*tp)->child[i ^ 1] = t; (*tp)->child[0]->state = -((*tp)->state > 0); (*tp)->child[1]->state = (*tp)->state < 0; (*tp)->state = 0; } else { *tp = *child; *child = (*child)->child[i ^ 1]; (*tp)->child[i ^ 1] = t; if ((*tp)->state) t->state = 0; else t->state >>= 1; (*tp)->state = -t->state; } } } if (!(*tp)->state ^ !!*next) return key; } return ret; } else { *tp = *next; *next = NULL; if (*tp) { (*tp)->elem = key; return NULL; } else return key; } } void ijk_av_tree_destroy(IjkAVTreeNode *t) { if (t) { ijk_av_tree_destroy(t->child[0]); ijk_av_tree_destroy(t->child[1]); free(t); } } void ijk_av_tree_enumerate(IjkAVTreeNode *t, void *opaque, int (*cmp)(void *opaque, void *elem), int (*enu)(void *opaque, void *elem)) { if (t) { int v = cmp ? cmp(opaque, t->elem) : 0; if (v >= 0) ijk_av_tree_enumerate(t->child[0], opaque, cmp, enu); if (v == 0) enu(opaque, t->elem); if (v <= 0) ijk_av_tree_enumerate(t->child[1], opaque, cmp, enu); } } ================================================ FILE: ijkmedia/ijkplayer/ijkavutil/ijktree.h ================================================ /* * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Raymond Zheng * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKAVUTIL_IJKTREE_H #define IJKAVUTIL_IJKTREE_H /** * @addtogroup lavu_tree IjkAVTree * @ingroup lavu_data * * Low-complexity tree container * * Insertion, removal, finding equal, largest which is smaller than and * smallest which is larger than, all have O(log n) worst-case complexity. * @{ */ struct IjkAVTreeNode; extern const int ijk_av_tree_node_size; /** * Allocate an IjkAVTreeNode. */ struct IjkAVTreeNode *ijk_av_tree_node_alloc(void); /** * Find an element. * @param root a pointer to the root node of the tree * @param next If next is not NULL, then next[0] will contain the previous * element and next[1] the next element. If either does not exist, * then the corresponding entry in next is unchanged. * @param cmp compare function used to compare elements in the tree, * API identical to that of Standard C's qsort * It is guranteed that the first and only the first argument to cmp() * will be the key parameter to av_tree_find(), thus it could if the * user wants, be a different type (like an opaque context). * @return An element with cmp(key, elem) == 0 or NULL if no such element * exists in the tree. */ void *ijk_av_tree_find(const struct IjkAVTreeNode *root, void *key, int (*cmp)(const void *key, const void *b), void *next[2]); /** * Insert or remove an element. * * If *next is NULL, then the supplied element will be removed if it exists. * If *next is non-NULL, then the supplied element will be inserted, unless * it already exists in the tree. * * @param rootp A pointer to a pointer to the root node of the tree; note that * the root node can change during insertions, this is required * to keep the tree balanced. * @param key pointer to the element key to insert in the tree * @param next Used to allocate and free AVTreeNodes. For insertion the user * must set it to an allocated and zeroed object of at least * av_tree_node_size bytes size. av_tree_insert() will set it to * NULL if it has been consumed. * For deleting elements *next is set to NULL by the user and * av_tree_insert() will set it to the AVTreeNode which was * used for the removed element. * This allows the use of flat arrays, which have * lower overhead compared to many malloced elements. * You might want to define a function like: * @code * void *tree_insert(struct AVTreeNode **rootp, void *key, * int (*cmp)(void *key, const void *b), * AVTreeNode **next) * { * if (!*next) * *next = av_mallocz(av_tree_node_size); * return av_tree_insert(rootp, key, cmp, next); * } * void *tree_remove(struct AVTreeNode **rootp, void *key, * int (*cmp)(void *key, const void *b, AVTreeNode **next)) * { * av_freep(next); * return av_tree_insert(rootp, key, cmp, next); * } * @endcode * @param cmp compare function used to compare elements in the tree, API identical * to that of Standard C's qsort * @return If no insertion happened, the found element; if an insertion or * removal happened, then either key or NULL will be returned. * Which one it is depends on the tree state and the implementation. You * should make no assumptions that it's one or the other in the code. */ void *ijk_av_tree_insert(struct IjkAVTreeNode **rootp, void *key, int (*cmp)(const void *key, const void *b), struct IjkAVTreeNode **next); void ijk_av_tree_destroy(struct IjkAVTreeNode *t); /** * Apply enu(opaque, &elem) to all the elements in the tree in a given range. * * @param cmp a comparison function that returns < 0 for an element below the * range, > 0 for an element above the range and == 0 for an * element inside the range * * @note The cmp function should use the same ordering used to construct the * tree. */ void ijk_av_tree_enumerate(struct IjkAVTreeNode *t, void *opaque, int (*cmp)(void *opaque, void *elem), int (*enu)(void *opaque, void *elem)); /** * @} */ #endif /* IJKAVUTIL_IJKTREE_H */ ================================================ FILE: ijkmedia/ijkplayer/ijkavutil/ijkutils.c ================================================ #include "ijkutils.h" #include #include #include #include #include void ijk_av_freep(void *arg) { void *val; memcpy(&val, arg, sizeof(val)); memcpy(arg, &(void *){ NULL }, sizeof(val)); free(val); } int ijk_av_strstart(const char *str, const char *pfx, const char **ptr) { while (*pfx && *pfx == *str) { pfx++; str++; } if (!*pfx && ptr) *ptr = str; return !*pfx; } ================================================ FILE: ijkmedia/ijkplayer/ijkavutil/ijkutils.h ================================================ /* * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Raymond Zheng * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKAVUTIL_IJKUTILS_H #define IJKAVUTIL_IJKUTILS_H #include "ijktree.h" #include #include #include typedef struct IjkAVIOInterruptCB { int (*callback)(void*); void *opaque; } IjkAVIOInterruptCB; typedef struct IjkCacheTreeInfo { struct IjkAVTreeNode *root; int64_t physical_init_pos; int64_t physical_size; int64_t file_size; } IjkCacheTreeInfo; #define FFDIFFSIGN(x,y) (((x)>(y)) - ((x)<(y))) #define FFMAX(a,b) ((a) > (b) ? (a) : (b)) #define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c) #define FFMIN(a,b) ((a) > (b) ? (b) : (a)) #define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c) #define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24)) /* error handling */ #if EDOM > 0 #define IJKAVERROR(e) (-(e)) ///< Returns a negative error code from a POSIX error code, to return from library functions. #define IJKAVUNERROR(e) (-(e)) ///< Returns a POSIX error code from a library function error return value. #else /* Some platforms have E* and errno already negated. */ #define IJKAVERROR(e) (e) #define IJKAVUNERROR(e) (e) #endif #define FFERRTAG(a, b, c, d) (-(int)MKTAG(a, b, c, d)) #define IJKAVERROR_BSF_NOT_FOUND FFERRTAG(0xF8,'B','S','F') ///< Bitstream filter not found #define IJKAVERROR_BUG FFERRTAG( 'B','U','G','!') ///< Internal bug, also see AVERROR_BUG2 #define IJKAVERROR_BUFFER_TOO_SMALL FFERRTAG( 'B','U','F','S') ///< Buffer too small #define IJKAVERROR_DECODER_NOT_FOUND FFERRTAG(0xF8,'D','E','C') ///< Decoder not found #define IJKAVERROR_DEMUXER_NOT_FOUND FFERRTAG(0xF8,'D','E','M') ///< Demuxer not found #define IJKAVERROR_ENCODER_NOT_FOUND FFERRTAG(0xF8,'E','N','C') ///< Encoder not found #define IJKAVERROR_EOF FFERRTAG( 'E','O','F',' ') ///< End of file #define IJKAVERROR_EXIT FFERRTAG( 'E','X','I','T') ///< Immediate exit was requested; the called function should not be restarted #define IJKAVERROR_EXTERNAL FFERRTAG( 'E','X','T',' ') ///< Generic error in an external library #define IJKAVERROR_FILTER_NOT_FOUND FFERRTAG(0xF8,'F','I','L') ///< Filter not found #define IJKAVERROR_INVALIDDATA FFERRTAG( 'I','N','D','A') ///< Invalid data found when processing input #define IJKAVERROR_MUXER_NOT_FOUND FFERRTAG(0xF8,'M','U','X') ///< Muxer not found #define IJKAVERROR_OPTION_NOT_FOUND FFERRTAG(0xF8,'O','P','T') ///< Option not found #define IJKAVERROR_PATCHWELCOME FFERRTAG( 'P','A','W','E') ///< Not yet implemented in FFmpeg, patches welcome #define IJKAVERROR_PROTOCOL_NOT_FOUND FFERRTAG(0xF8,'P','R','O') ///< Protocol not found #define IJKAVERROR_STREAM_NOT_FOUND FFERRTAG(0xF8,'S','T','R') ///< Stream not found /** * ORing this as the "whence" parameter to a seek function causes it to * return the filesize without seeking anywhere. Supporting this is optional. * If it is not supported then the seek function will return <0. */ #define IJKAVSEEK_SIZE 0x10000 /** * Passing this flag as the "whence" parameter to a seek function causes it to * seek by any means (like reopening and linear reading) or other normally unreasonable * means that can be extremely slow. * This may be ignored by the seek code. */ #define IJKAVSEEK_FORCE 0x20000 void ijk_av_freep(void *arg); int ijk_av_strstart(const char *str, const char *pfx, const char **ptr); #endif // IJKAVUTIL_IJKUTILS_H ================================================ FILE: ijkmedia/ijkplayer/ijkavutil/opt.h ================================================ /* * opt.h * * Copyright (c) 2015 Bilibili * Copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__IJKOPT_H #define FFPLAY__IJKOPT_H #include "libavutil/opt.h" #define IJKAV_OPTION_INT(default__, min__, max__) \ .type = AV_OPT_TYPE_INT, \ { .i64 = default__ }, \ .min = min__, \ .max = max__, \ .flags = AV_OPT_FLAG_DECODING_PARAM #define IJKAV_OPTION_INT64(default__, min__, max__) \ .type = AV_OPT_TYPE_INT64, \ { .i64 = default__ }, \ .min = min__, \ .max = max__, \ .flags = AV_OPT_FLAG_DECODING_PARAM #define IJKAV_OPTION_CONST(default__) \ .type = AV_OPT_TYPE_CONST, \ { .i64 = default__ }, \ .min = INT_MIN, \ .max = INT_MAX, \ .flags = AV_OPT_FLAG_DECODING_PARAM #define IJKAV_OPTION_STR(default__) \ .type = AV_OPT_TYPE_STRING, \ { .str = default__ }, \ .min = 0, \ .max = 0, \ .flags = AV_OPT_FLAG_DECODING_PARAM #endif ================================================ FILE: ijkmedia/ijkplayer/ijkmeta.c ================================================ /* * ijkmeta.c * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijkmeta.h" #include "ff_ffinc.h" #include "ijksdl/ijksdl_misc.h" #define IJK_META_INIT_CAPACITY 13 struct IjkMediaMeta { SDL_mutex *mutex; AVDictionary *dict; size_t children_count; size_t children_capacity; IjkMediaMeta **children; }; IjkMediaMeta *ijkmeta_create() { IjkMediaMeta *meta = (IjkMediaMeta *)calloc(1, sizeof(IjkMediaMeta)); if (!meta) return NULL; meta->mutex = SDL_CreateMutex(); if (!meta->mutex) goto fail; return meta; fail: ijkmeta_destroy(meta); return NULL; } void ijkmeta_reset(IjkMediaMeta *meta) { if (meta && meta->dict) av_dict_free(&meta->dict); } void ijkmeta_destroy(IjkMediaMeta *meta) { if (!meta) return; if (meta->dict) { av_dict_free(&meta->dict); } if (meta->children) { for(int i = 0; i < meta->children_count; ++i) { IjkMediaMeta *child = meta->children[i]; if (child) { ijkmeta_destroy(child); } } free(meta->children); meta->children = NULL; } SDL_DestroyMutexP(&meta->mutex); free(meta); } void ijkmeta_destroy_p(IjkMediaMeta **meta) { if (!meta) return; ijkmeta_destroy(*meta); *meta = NULL; } void ijkmeta_lock(IjkMediaMeta *meta) { if (!meta || !meta->mutex) return; SDL_LockMutex(meta->mutex); } void ijkmeta_unlock(IjkMediaMeta *meta) { if (!meta || !meta->mutex) return; SDL_UnlockMutex(meta->mutex); } void ijkmeta_append_child_l(IjkMediaMeta *meta, IjkMediaMeta *child) { if (!meta || !child) return; if (!meta->children) { meta->children = (IjkMediaMeta **)calloc(IJK_META_INIT_CAPACITY, sizeof(IjkMediaMeta *)); if (!meta->children) return; meta->children_count = 0; meta->children_capacity = IJK_META_INIT_CAPACITY; } else if (meta->children_count >= meta->children_capacity) { size_t new_capacity = meta->children_capacity * 2; IjkMediaMeta **new_children = (IjkMediaMeta **)calloc(new_capacity, sizeof(IjkMediaMeta *)); if (!new_children) return; memcpy(new_children, meta->children, meta->children_capacity * sizeof(IjkMediaMeta *)); free(meta->children); meta->children = new_children; meta->children_capacity = new_capacity; } meta->children[meta->children_count] = child; meta->children_count++; } void ijkmeta_set_int64_l(IjkMediaMeta *meta, const char *name, int64_t value) { if (!meta) return; av_dict_set_int(&meta->dict, name, value, 0); } void ijkmeta_set_string_l(IjkMediaMeta *meta, const char *name, const char *value) { if (!meta) return; av_dict_set(&meta->dict, name, value, 0); } static int64_t get_bit_rate(AVCodecParameters *codecpar) { int64_t bit_rate; int bits_per_sample; switch (codecpar->codec_type) { case AVMEDIA_TYPE_VIDEO: case AVMEDIA_TYPE_DATA: case AVMEDIA_TYPE_SUBTITLE: case AVMEDIA_TYPE_ATTACHMENT: bit_rate = codecpar->bit_rate; break; case AVMEDIA_TYPE_AUDIO: bits_per_sample = av_get_bits_per_sample(codecpar->codec_id); bit_rate = bits_per_sample ? codecpar->sample_rate * codecpar->channels * bits_per_sample : codecpar->bit_rate; break; default: bit_rate = 0; break; } return bit_rate; } void ijkmeta_set_avformat_context_l(IjkMediaMeta *meta, AVFormatContext *ic) { if (!meta || !ic) return; if (ic->iformat && ic->iformat->name) ijkmeta_set_string_l(meta, IJKM_KEY_FORMAT, ic->iformat->name); if (ic->duration != AV_NOPTS_VALUE) ijkmeta_set_int64_l(meta, IJKM_KEY_DURATION_US, ic->duration); if (ic->start_time != AV_NOPTS_VALUE) ijkmeta_set_int64_l(meta, IJKM_KEY_START_US, ic->start_time); if (ic->bit_rate) ijkmeta_set_int64_l(meta, IJKM_KEY_BITRATE, ic->bit_rate); IjkMediaMeta *stream_meta = NULL; for (int i = 0; i < ic->nb_streams; i++) { if (!stream_meta) ijkmeta_destroy_p(&stream_meta); AVStream *st = ic->streams[i]; if (!st || !st->codecpar) continue; stream_meta = ijkmeta_create(); if (!stream_meta) continue; AVCodecParameters *codecpar = st->codecpar; const char *codec_name = avcodec_get_name(codecpar->codec_id); if (codec_name) ijkmeta_set_string_l(stream_meta, IJKM_KEY_CODEC_NAME, codec_name); if (codecpar->profile != FF_PROFILE_UNKNOWN) { const AVCodec *codec = avcodec_find_decoder(codecpar->codec_id); if (codec) { ijkmeta_set_int64_l(stream_meta, IJKM_KEY_CODEC_PROFILE_ID, codecpar->profile); const char *profile = av_get_profile_name(codec, codecpar->profile); if (profile) ijkmeta_set_string_l(stream_meta, IJKM_KEY_CODEC_PROFILE, profile); if (codec->long_name) ijkmeta_set_string_l(stream_meta, IJKM_KEY_CODEC_LONG_NAME, codec->long_name); ijkmeta_set_int64_l(stream_meta, IJKM_KEY_CODEC_LEVEL, codecpar->level); if (codecpar->format != AV_PIX_FMT_NONE) ijkmeta_set_string_l(stream_meta, IJKM_KEY_CODEC_PIXEL_FORMAT, av_get_pix_fmt_name(codecpar->format)); } } int64_t bitrate = get_bit_rate(codecpar); if (bitrate > 0) { ijkmeta_set_int64_l(stream_meta, IJKM_KEY_BITRATE, bitrate); } switch (codecpar->codec_type) { case AVMEDIA_TYPE_VIDEO: { ijkmeta_set_string_l(stream_meta, IJKM_KEY_TYPE, IJKM_VAL_TYPE__VIDEO); if (codecpar->width > 0) ijkmeta_set_int64_l(stream_meta, IJKM_KEY_WIDTH, codecpar->width); if (codecpar->height > 0) ijkmeta_set_int64_l(stream_meta, IJKM_KEY_HEIGHT, codecpar->height); if (st->sample_aspect_ratio.num > 0 && st->sample_aspect_ratio.den > 0) { ijkmeta_set_int64_l(stream_meta, IJKM_KEY_SAR_NUM, codecpar->sample_aspect_ratio.num); ijkmeta_set_int64_l(stream_meta, IJKM_KEY_SAR_DEN, codecpar->sample_aspect_ratio.den); } if (st->avg_frame_rate.num > 0 && st->avg_frame_rate.den > 0) { ijkmeta_set_int64_l(stream_meta, IJKM_KEY_FPS_NUM, st->avg_frame_rate.num); ijkmeta_set_int64_l(stream_meta, IJKM_KEY_FPS_DEN, st->avg_frame_rate.den); } if (st->r_frame_rate.num > 0 && st->r_frame_rate.den > 0) { ijkmeta_set_int64_l(stream_meta, IJKM_KEY_TBR_NUM, st->avg_frame_rate.num); ijkmeta_set_int64_l(stream_meta, IJKM_KEY_TBR_DEN, st->avg_frame_rate.den); } break; } case AVMEDIA_TYPE_AUDIO: { ijkmeta_set_string_l(stream_meta, IJKM_KEY_TYPE, IJKM_VAL_TYPE__AUDIO); if (codecpar->sample_rate) ijkmeta_set_int64_l(stream_meta, IJKM_KEY_SAMPLE_RATE, codecpar->sample_rate); if (codecpar->channel_layout) ijkmeta_set_int64_l(stream_meta, IJKM_KEY_CHANNEL_LAYOUT, codecpar->channel_layout); break; } case AVMEDIA_TYPE_SUBTITLE: { ijkmeta_set_string_l(stream_meta, IJKM_KEY_TYPE, IJKM_VAL_TYPE__TIMEDTEXT); break; } default: { ijkmeta_set_string_l(stream_meta, IJKM_KEY_TYPE, IJKM_VAL_TYPE__UNKNOWN); break; } } AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0); if (lang && lang->value) ijkmeta_set_string_l(stream_meta, IJKM_KEY_LANGUAGE, lang->value); ijkmeta_append_child_l(meta, stream_meta); stream_meta = NULL; } if (!stream_meta) ijkmeta_destroy_p(&stream_meta); } const char *ijkmeta_get_string_l(IjkMediaMeta *meta, const char *name) { if (!meta || !meta->dict || !name) return NULL; AVDictionaryEntry *entry = av_dict_get(meta->dict, name, NULL, 0); if (!entry) return NULL; return entry->value; } int64_t ijkmeta_get_int64_l(IjkMediaMeta *meta, const char *name, int64_t defaultValue) { if (!meta || !meta->dict) return defaultValue; AVDictionaryEntry *entry = av_dict_get(meta->dict, name, NULL, 0); if (!entry || !entry->value) return defaultValue; return atoll(entry->value); } size_t ijkmeta_get_children_count_l(IjkMediaMeta *meta) { if (!meta || !meta->children) return 0; return meta->children_count; } IjkMediaMeta *ijkmeta_get_child_l(IjkMediaMeta *meta, size_t index) { if (!meta) return NULL; if (index >= meta->children_count) return NULL; return meta->children[index]; } ================================================ FILE: ijkmedia/ijkplayer/ijkmeta.h ================================================ /* * ijkmeta.h * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKPLAYER__IJKMETA_H #define IJKPLAYER__IJKMETA_H #include #include // media meta #define IJKM_KEY_FORMAT "format" #define IJKM_KEY_DURATION_US "duration_us" #define IJKM_KEY_START_US "start_us" #define IJKM_KEY_BITRATE "bitrate" #define IJKM_KEY_VIDEO_STREAM "video" #define IJKM_KEY_AUDIO_STREAM "audio" #define IJKM_KEY_TIMEDTEXT_STREAM "timedtext" // stream meta #define IJKM_KEY_TYPE "type" #define IJKM_VAL_TYPE__VIDEO "video" #define IJKM_VAL_TYPE__AUDIO "audio" #define IJKM_VAL_TYPE__TIMEDTEXT "timedtext" #define IJKM_VAL_TYPE__UNKNOWN "unknown" #define IJKM_KEY_LANGUAGE "language" #define IJKM_KEY_CODEC_NAME "codec_name" #define IJKM_KEY_CODEC_PROFILE "codec_profile" #define IJKM_KEY_CODEC_LEVEL "codec_level" #define IJKM_KEY_CODEC_LONG_NAME "codec_long_name" #define IJKM_KEY_CODEC_PIXEL_FORMAT "codec_pixel_format" #define IJKM_KEY_CODEC_PROFILE_ID "codec_profile_id" // stream: video #define IJKM_KEY_WIDTH "width" #define IJKM_KEY_HEIGHT "height" #define IJKM_KEY_FPS_NUM "fps_num" #define IJKM_KEY_FPS_DEN "fps_den" #define IJKM_KEY_TBR_NUM "tbr_num" #define IJKM_KEY_TBR_DEN "tbr_den" #define IJKM_KEY_SAR_NUM "sar_num" #define IJKM_KEY_SAR_DEN "sar_den" // stream: audio #define IJKM_KEY_SAMPLE_RATE "sample_rate" #define IJKM_KEY_CHANNEL_LAYOUT "channel_layout" // reserved for user #define IJKM_KEY_STREAMS "streams" struct AVFormatContext; typedef struct IjkMediaMeta IjkMediaMeta; IjkMediaMeta *ijkmeta_create(); void ijkmeta_reset(IjkMediaMeta *meta); void ijkmeta_destroy(IjkMediaMeta *meta); void ijkmeta_destroy_p(IjkMediaMeta **meta); void ijkmeta_lock(IjkMediaMeta *meta); void ijkmeta_unlock(IjkMediaMeta *meta); void ijkmeta_append_child_l(IjkMediaMeta *meta, IjkMediaMeta *child); void ijkmeta_set_int64_l(IjkMediaMeta *meta, const char *name, int64_t value); void ijkmeta_set_string_l(IjkMediaMeta *meta, const char *name, const char *value); void ijkmeta_set_avformat_context_l(IjkMediaMeta *meta, struct AVFormatContext *ic); // must be freed with free(); const char *ijkmeta_get_string_l(IjkMediaMeta *meta, const char *name); int64_t ijkmeta_get_int64_l(IjkMediaMeta *meta, const char *name, int64_t defaultValue); size_t ijkmeta_get_children_count_l(IjkMediaMeta *meta); // do not free IjkMediaMeta *ijkmeta_get_child_l(IjkMediaMeta *meta, size_t index); #endif//IJKPLAYER__IJKMETA_H ================================================ FILE: ijkmedia/ijkplayer/ijkplayer.c ================================================ /* * ijkplayer.c * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijkplayer.h" #include "ijkplayer_internal.h" #include "ijkversion.h" #define MP_RET_IF_FAILED(ret) \ do { \ int retval = ret; \ if (retval != 0) return (retval); \ } while(0) #define MPST_RET_IF_EQ_INT(real, expected, errcode) \ do { \ if ((real) == (expected)) return (errcode); \ } while(0) #define MPST_RET_IF_EQ(real, expected) \ MPST_RET_IF_EQ_INT(real, expected, EIJK_INVALID_STATE) inline static void ijkmp_destroy(IjkMediaPlayer *mp) { if (!mp) return; ffp_destroy_p(&mp->ffplayer); if (mp->msg_thread) { SDL_WaitThread(mp->msg_thread, NULL); mp->msg_thread = NULL; } pthread_mutex_destroy(&mp->mutex); freep((void**)&mp->data_source); memset(mp, 0, sizeof(IjkMediaPlayer)); freep((void**)&mp); } inline static void ijkmp_destroy_p(IjkMediaPlayer **pmp) { if (!pmp) return; ijkmp_destroy(*pmp); *pmp = NULL; } void ijkmp_global_init() { ffp_global_init(); } void ijkmp_global_uninit() { ffp_global_uninit(); } void ijkmp_global_set_log_report(int use_report) { ffp_global_set_log_report(use_report); } void ijkmp_global_set_log_level(int log_level) { ffp_global_set_log_level(log_level); } void ijkmp_global_set_inject_callback(ijk_inject_callback cb) { ffp_global_set_inject_callback(cb); } const char *ijkmp_version() { return IJKPLAYER_VERSION; } void ijkmp_io_stat_register(void (*cb)(const char *url, int type, int bytes)) { ffp_io_stat_register(cb); } void ijkmp_io_stat_complete_register(void (*cb)(const char *url, int64_t read_bytes, int64_t total_size, int64_t elpased_time, int64_t total_duration)) { ffp_io_stat_complete_register(cb); } void ijkmp_change_state_l(IjkMediaPlayer *mp, int new_state) { mp->mp_state = new_state; ffp_notify_msg1(mp->ffplayer, FFP_MSG_PLAYBACK_STATE_CHANGED); } IjkMediaPlayer *ijkmp_create(int (*msg_loop)(void*)) { IjkMediaPlayer *mp = (IjkMediaPlayer *) mallocz(sizeof(IjkMediaPlayer)); if (!mp) goto fail; mp->ffplayer = ffp_create(); if (!mp->ffplayer) goto fail; mp->msg_loop = msg_loop; ijkmp_inc_ref(mp); pthread_mutex_init(&mp->mutex, NULL); return mp; fail: ijkmp_destroy_p(&mp); return NULL; } void *ijkmp_set_inject_opaque(IjkMediaPlayer *mp, void *opaque) { assert(mp); MPTRACE("%s(%p)\n", __func__, opaque); void *prev_weak_thiz = ffp_set_inject_opaque(mp->ffplayer, opaque); MPTRACE("%s()=void\n", __func__); return prev_weak_thiz; } void ijkmp_set_frame_at_time(IjkMediaPlayer *mp, const char *path, int64_t start_time, int64_t end_time, int num, int definition) { assert(mp); MPTRACE("%s(%s,%lld,%lld,%d,%d)\n", __func__, path, start_time, end_time, num, definition); ffp_set_frame_at_time(mp->ffplayer, path, start_time, end_time, num, definition); MPTRACE("%s()=void\n", __func__); } void *ijkmp_set_ijkio_inject_opaque(IjkMediaPlayer *mp, void *opaque) { assert(mp); MPTRACE("%s(%p)\n", __func__, opaque); void *prev_weak_thiz = ffp_set_ijkio_inject_opaque(mp->ffplayer, opaque); MPTRACE("%s()=void\n", __func__); return prev_weak_thiz; } void ijkmp_set_option(IjkMediaPlayer *mp, int opt_category, const char *name, const char *value) { assert(mp); // MPTRACE("%s(%s, %s)\n", __func__, name, value); pthread_mutex_lock(&mp->mutex); ffp_set_option(mp->ffplayer, opt_category, name, value); pthread_mutex_unlock(&mp->mutex); // MPTRACE("%s()=void\n", __func__); } void ijkmp_set_option_int(IjkMediaPlayer *mp, int opt_category, const char *name, int64_t value) { assert(mp); // MPTRACE("%s(%s, %"PRId64")\n", __func__, name, value); pthread_mutex_lock(&mp->mutex); ffp_set_option_int(mp->ffplayer, opt_category, name, value); pthread_mutex_unlock(&mp->mutex); // MPTRACE("%s()=void\n", __func__); } int ijkmp_get_video_codec_info(IjkMediaPlayer *mp, char **codec_info) { assert(mp); MPTRACE("%s\n", __func__); pthread_mutex_lock(&mp->mutex); int ret = ffp_get_video_codec_info(mp->ffplayer, codec_info); pthread_mutex_unlock(&mp->mutex); MPTRACE("%s()=void\n", __func__); return ret; } int ijkmp_get_audio_codec_info(IjkMediaPlayer *mp, char **codec_info) { assert(mp); MPTRACE("%s\n", __func__); pthread_mutex_lock(&mp->mutex); int ret = ffp_get_audio_codec_info(mp->ffplayer, codec_info); pthread_mutex_unlock(&mp->mutex); MPTRACE("%s()=void\n", __func__); return ret; } void ijkmp_set_playback_rate(IjkMediaPlayer *mp, float rate) { assert(mp); MPTRACE("%s(%f)\n", __func__, rate); pthread_mutex_lock(&mp->mutex); ffp_set_playback_rate(mp->ffplayer, rate); pthread_mutex_unlock(&mp->mutex); MPTRACE("%s()=void\n", __func__); } void ijkmp_set_playback_volume(IjkMediaPlayer *mp, float volume) { assert(mp); MPTRACE("%s(%f)\n", __func__, volume); pthread_mutex_lock(&mp->mutex); ffp_set_playback_volume(mp->ffplayer, volume); pthread_mutex_unlock(&mp->mutex); MPTRACE("%s()=void\n", __func__); } int ijkmp_set_stream_selected(IjkMediaPlayer *mp, int stream, int selected) { assert(mp); MPTRACE("%s(%d, %d)\n", __func__, stream, selected); pthread_mutex_lock(&mp->mutex); int ret = ffp_set_stream_selected(mp->ffplayer, stream, selected); pthread_mutex_unlock(&mp->mutex); MPTRACE("%s(%d, %d)=%d\n", __func__, stream, selected, ret); return ret; } float ijkmp_get_property_float(IjkMediaPlayer *mp, int id, float default_value) { assert(mp); pthread_mutex_lock(&mp->mutex); float ret = ffp_get_property_float(mp->ffplayer, id, default_value); pthread_mutex_unlock(&mp->mutex); return ret; } void ijkmp_set_property_float(IjkMediaPlayer *mp, int id, float value) { assert(mp); pthread_mutex_lock(&mp->mutex); ffp_set_property_float(mp->ffplayer, id, value); pthread_mutex_unlock(&mp->mutex); } int64_t ijkmp_get_property_int64(IjkMediaPlayer *mp, int id, int64_t default_value) { assert(mp); pthread_mutex_lock(&mp->mutex); int64_t ret = ffp_get_property_int64(mp->ffplayer, id, default_value); pthread_mutex_unlock(&mp->mutex); return ret; } void ijkmp_set_property_int64(IjkMediaPlayer *mp, int id, int64_t value) { assert(mp); pthread_mutex_lock(&mp->mutex); ffp_set_property_int64(mp->ffplayer, id, value); pthread_mutex_unlock(&mp->mutex); } IjkMediaMeta *ijkmp_get_meta_l(IjkMediaPlayer *mp) { assert(mp); MPTRACE("%s\n", __func__); IjkMediaMeta *ret = ffp_get_meta_l(mp->ffplayer); MPTRACE("%s()=void\n", __func__); return ret; } void ijkmp_shutdown_l(IjkMediaPlayer *mp) { assert(mp); MPTRACE("ijkmp_shutdown_l()\n"); if (mp->ffplayer) { ffp_stop_l(mp->ffplayer); ffp_wait_stop_l(mp->ffplayer); } MPTRACE("ijkmp_shutdown_l()=void\n"); } void ijkmp_shutdown(IjkMediaPlayer *mp) { return ijkmp_shutdown_l(mp); } void ijkmp_inc_ref(IjkMediaPlayer *mp) { assert(mp); __sync_fetch_and_add(&mp->ref_count, 1); } void ijkmp_dec_ref(IjkMediaPlayer *mp) { if (!mp) return; int ref_count = __sync_sub_and_fetch(&mp->ref_count, 1); if (ref_count == 0) { MPTRACE("ijkmp_dec_ref(): ref=0\n"); ijkmp_shutdown(mp); ijkmp_destroy_p(&mp); } } void ijkmp_dec_ref_p(IjkMediaPlayer **pmp) { if (!pmp) return; ijkmp_dec_ref(*pmp); *pmp = NULL; } static int ijkmp_set_data_source_l(IjkMediaPlayer *mp, const char *url) { assert(mp); assert(url); // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_IDLE); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_INITIALIZED); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_ASYNC_PREPARING); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_PREPARED); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_STARTED); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_PAUSED); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_COMPLETED); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_STOPPED); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_ERROR); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_END); freep((void**)&mp->data_source); mp->data_source = strdup(url); if (!mp->data_source) return EIJK_OUT_OF_MEMORY; ijkmp_change_state_l(mp, MP_STATE_INITIALIZED); return 0; } int ijkmp_set_data_source(IjkMediaPlayer *mp, const char *url) { assert(mp); assert(url); MPTRACE("ijkmp_set_data_source(url=\"%s\")\n", url); pthread_mutex_lock(&mp->mutex); int retval = ijkmp_set_data_source_l(mp, url); pthread_mutex_unlock(&mp->mutex); MPTRACE("ijkmp_set_data_source(url=\"%s\")=%d\n", url, retval); return retval; } static int ijkmp_msg_loop(void *arg) { IjkMediaPlayer *mp = arg; int ret = mp->msg_loop(arg); return ret; } static int ijkmp_prepare_async_l(IjkMediaPlayer *mp) { assert(mp); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_IDLE); // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_INITIALIZED); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_ASYNC_PREPARING); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_PREPARED); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_STARTED); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_PAUSED); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_COMPLETED); // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_STOPPED); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_ERROR); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_END); assert(mp->data_source); ijkmp_change_state_l(mp, MP_STATE_ASYNC_PREPARING); msg_queue_start(&mp->ffplayer->msg_queue); // released in msg_loop ijkmp_inc_ref(mp); mp->msg_thread = SDL_CreateThreadEx(&mp->_msg_thread, ijkmp_msg_loop, mp, "ff_msg_loop"); // msg_thread is detached inside msg_loop // TODO: 9 release weak_thiz if pthread_create() failed; int retval = ffp_prepare_async_l(mp->ffplayer, mp->data_source); if (retval < 0) { ijkmp_change_state_l(mp, MP_STATE_ERROR); return retval; } return 0; } int ijkmp_prepare_async(IjkMediaPlayer *mp) { assert(mp); MPTRACE("ijkmp_prepare_async()\n"); pthread_mutex_lock(&mp->mutex); int retval = ijkmp_prepare_async_l(mp); pthread_mutex_unlock(&mp->mutex); MPTRACE("ijkmp_prepare_async()=%d\n", retval); return retval; } static int ikjmp_chkst_start_l(int mp_state) { MPST_RET_IF_EQ(mp_state, MP_STATE_IDLE); MPST_RET_IF_EQ(mp_state, MP_STATE_INITIALIZED); MPST_RET_IF_EQ(mp_state, MP_STATE_ASYNC_PREPARING); // MPST_RET_IF_EQ(mp_state, MP_STATE_PREPARED); // MPST_RET_IF_EQ(mp_state, MP_STATE_STARTED); // MPST_RET_IF_EQ(mp_state, MP_STATE_PAUSED); // MPST_RET_IF_EQ(mp_state, MP_STATE_COMPLETED); MPST_RET_IF_EQ(mp_state, MP_STATE_STOPPED); MPST_RET_IF_EQ(mp_state, MP_STATE_ERROR); MPST_RET_IF_EQ(mp_state, MP_STATE_END); return 0; } static int ijkmp_start_l(IjkMediaPlayer *mp) { assert(mp); MP_RET_IF_FAILED(ikjmp_chkst_start_l(mp->mp_state)); ffp_remove_msg(mp->ffplayer, FFP_REQ_START); ffp_remove_msg(mp->ffplayer, FFP_REQ_PAUSE); ffp_notify_msg1(mp->ffplayer, FFP_REQ_START); return 0; } int ijkmp_start(IjkMediaPlayer *mp) { assert(mp); MPTRACE("ijkmp_start()\n"); pthread_mutex_lock(&mp->mutex); int retval = ijkmp_start_l(mp); pthread_mutex_unlock(&mp->mutex); MPTRACE("ijkmp_start()=%d\n", retval); return retval; } static int ikjmp_chkst_pause_l(int mp_state) { MPST_RET_IF_EQ(mp_state, MP_STATE_IDLE); MPST_RET_IF_EQ(mp_state, MP_STATE_INITIALIZED); MPST_RET_IF_EQ(mp_state, MP_STATE_ASYNC_PREPARING); // MPST_RET_IF_EQ(mp_state, MP_STATE_PREPARED); // MPST_RET_IF_EQ(mp_state, MP_STATE_STARTED); // MPST_RET_IF_EQ(mp_state, MP_STATE_PAUSED); // MPST_RET_IF_EQ(mp_state, MP_STATE_COMPLETED); MPST_RET_IF_EQ(mp_state, MP_STATE_STOPPED); MPST_RET_IF_EQ(mp_state, MP_STATE_ERROR); MPST_RET_IF_EQ(mp_state, MP_STATE_END); return 0; } static int ijkmp_pause_l(IjkMediaPlayer *mp) { assert(mp); MP_RET_IF_FAILED(ikjmp_chkst_pause_l(mp->mp_state)); ffp_remove_msg(mp->ffplayer, FFP_REQ_START); ffp_remove_msg(mp->ffplayer, FFP_REQ_PAUSE); ffp_notify_msg1(mp->ffplayer, FFP_REQ_PAUSE); return 0; } int ijkmp_pause(IjkMediaPlayer *mp) { assert(mp); MPTRACE("ijkmp_pause()\n"); pthread_mutex_lock(&mp->mutex); int retval = ijkmp_pause_l(mp); pthread_mutex_unlock(&mp->mutex); MPTRACE("ijkmp_pause()=%d\n", retval); return retval; } static int ijkmp_stop_l(IjkMediaPlayer *mp) { assert(mp); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_IDLE); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_INITIALIZED); // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_ASYNC_PREPARING); // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_PREPARED); // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_STARTED); // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_PAUSED); // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_COMPLETED); // MPST_RET_IF_EQ(mp->mp_state, MP_STATE_STOPPED); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_ERROR); MPST_RET_IF_EQ(mp->mp_state, MP_STATE_END); ffp_remove_msg(mp->ffplayer, FFP_REQ_START); ffp_remove_msg(mp->ffplayer, FFP_REQ_PAUSE); int retval = ffp_stop_l(mp->ffplayer); if (retval < 0) { return retval; } ijkmp_change_state_l(mp, MP_STATE_STOPPED); return 0; } int ijkmp_stop(IjkMediaPlayer *mp) { assert(mp); MPTRACE("ijkmp_stop()\n"); pthread_mutex_lock(&mp->mutex); int retval = ijkmp_stop_l(mp); pthread_mutex_unlock(&mp->mutex); MPTRACE("ijkmp_stop()=%d\n", retval); return retval; } bool ijkmp_is_playing(IjkMediaPlayer *mp) { assert(mp); if (mp->mp_state == MP_STATE_PREPARED || mp->mp_state == MP_STATE_STARTED) { return true; } return false; } static int ikjmp_chkst_seek_l(int mp_state) { MPST_RET_IF_EQ(mp_state, MP_STATE_IDLE); MPST_RET_IF_EQ(mp_state, MP_STATE_INITIALIZED); MPST_RET_IF_EQ(mp_state, MP_STATE_ASYNC_PREPARING); // MPST_RET_IF_EQ(mp_state, MP_STATE_PREPARED); // MPST_RET_IF_EQ(mp_state, MP_STATE_STARTED); // MPST_RET_IF_EQ(mp_state, MP_STATE_PAUSED); // MPST_RET_IF_EQ(mp_state, MP_STATE_COMPLETED); MPST_RET_IF_EQ(mp_state, MP_STATE_STOPPED); MPST_RET_IF_EQ(mp_state, MP_STATE_ERROR); MPST_RET_IF_EQ(mp_state, MP_STATE_END); return 0; } int ijkmp_seek_to_l(IjkMediaPlayer *mp, long msec) { assert(mp); MP_RET_IF_FAILED(ikjmp_chkst_seek_l(mp->mp_state)); mp->seek_req = 1; mp->seek_msec = msec; ffp_remove_msg(mp->ffplayer, FFP_REQ_SEEK); ffp_notify_msg2(mp->ffplayer, FFP_REQ_SEEK, (int)msec); // TODO: 9 64-bit long? return 0; } int ijkmp_seek_to(IjkMediaPlayer *mp, long msec) { assert(mp); MPTRACE("ijkmp_seek_to(%ld)\n", msec); pthread_mutex_lock(&mp->mutex); int retval = ijkmp_seek_to_l(mp, msec); pthread_mutex_unlock(&mp->mutex); MPTRACE("ijkmp_seek_to(%ld)=%d\n", msec, retval); return retval; } int ijkmp_get_state(IjkMediaPlayer *mp) { return mp->mp_state; } static long ijkmp_get_current_position_l(IjkMediaPlayer *mp) { if (mp->seek_req) return mp->seek_msec; return ffp_get_current_position_l(mp->ffplayer); } long ijkmp_get_current_position(IjkMediaPlayer *mp) { assert(mp); pthread_mutex_lock(&mp->mutex); long retval; if (mp->seek_req) retval = mp->seek_msec; else retval = ijkmp_get_current_position_l(mp); pthread_mutex_unlock(&mp->mutex); return retval; } static long ijkmp_get_duration_l(IjkMediaPlayer *mp) { return ffp_get_duration_l(mp->ffplayer); } long ijkmp_get_duration(IjkMediaPlayer *mp) { assert(mp); pthread_mutex_lock(&mp->mutex); long retval = ijkmp_get_duration_l(mp); pthread_mutex_unlock(&mp->mutex); return retval; } static long ijkmp_get_playable_duration_l(IjkMediaPlayer *mp) { return ffp_get_playable_duration_l(mp->ffplayer); } long ijkmp_get_playable_duration(IjkMediaPlayer *mp) { assert(mp); pthread_mutex_lock(&mp->mutex); long retval = ijkmp_get_playable_duration_l(mp); pthread_mutex_unlock(&mp->mutex); return retval; } void ijkmp_set_loop(IjkMediaPlayer *mp, int loop) { assert(mp); pthread_mutex_lock(&mp->mutex); ffp_set_loop(mp->ffplayer, loop); pthread_mutex_unlock(&mp->mutex); } int ijkmp_get_loop(IjkMediaPlayer *mp) { assert(mp); pthread_mutex_lock(&mp->mutex); int loop = ffp_get_loop(mp->ffplayer); pthread_mutex_unlock(&mp->mutex); return loop; } void *ijkmp_get_weak_thiz(IjkMediaPlayer *mp) { return mp->weak_thiz; } void *ijkmp_set_weak_thiz(IjkMediaPlayer *mp, void *weak_thiz) { void *prev_weak_thiz = mp->weak_thiz; mp->weak_thiz = weak_thiz; return prev_weak_thiz; } /* need to call msg_free_res for freeing the resouce obtained in msg */ int ijkmp_get_msg(IjkMediaPlayer *mp, AVMessage *msg, int block) { assert(mp); while (1) { int continue_wait_next_msg = 0; int retval = msg_queue_get(&mp->ffplayer->msg_queue, msg, block); if (retval <= 0) return retval; switch (msg->what) { case FFP_MSG_PREPARED: MPTRACE("ijkmp_get_msg: FFP_MSG_PREPARED\n"); pthread_mutex_lock(&mp->mutex); if (mp->mp_state == MP_STATE_ASYNC_PREPARING) { ijkmp_change_state_l(mp, MP_STATE_PREPARED); } else { // FIXME: 1: onError() ? av_log(mp->ffplayer, AV_LOG_DEBUG, "FFP_MSG_PREPARED: expecting mp_state==MP_STATE_ASYNC_PREPARING\n"); } if (!mp->ffplayer->start_on_prepared) { ijkmp_change_state_l(mp, MP_STATE_PAUSED); } pthread_mutex_unlock(&mp->mutex); break; case FFP_MSG_COMPLETED: MPTRACE("ijkmp_get_msg: FFP_MSG_COMPLETED\n"); pthread_mutex_lock(&mp->mutex); mp->restart = 1; mp->restart_from_beginning = 1; ijkmp_change_state_l(mp, MP_STATE_COMPLETED); pthread_mutex_unlock(&mp->mutex); break; case FFP_MSG_SEEK_COMPLETE: MPTRACE("ijkmp_get_msg: FFP_MSG_SEEK_COMPLETE\n"); pthread_mutex_lock(&mp->mutex); mp->seek_req = 0; mp->seek_msec = 0; pthread_mutex_unlock(&mp->mutex); break; case FFP_REQ_START: MPTRACE("ijkmp_get_msg: FFP_REQ_START\n"); continue_wait_next_msg = 1; pthread_mutex_lock(&mp->mutex); if (0 == ikjmp_chkst_start_l(mp->mp_state)) { // FIXME: 8 check seekable if (mp->restart) { if (mp->restart_from_beginning) { av_log(mp->ffplayer, AV_LOG_DEBUG, "ijkmp_get_msg: FFP_REQ_START: restart from beginning\n"); retval = ffp_start_from_l(mp->ffplayer, 0); if (retval == 0) ijkmp_change_state_l(mp, MP_STATE_STARTED); } else { av_log(mp->ffplayer, AV_LOG_DEBUG, "ijkmp_get_msg: FFP_REQ_START: restart from seek pos\n"); retval = ffp_start_l(mp->ffplayer); if (retval == 0) ijkmp_change_state_l(mp, MP_STATE_STARTED); } mp->restart = 0; mp->restart_from_beginning = 0; } else { av_log(mp->ffplayer, AV_LOG_DEBUG, "ijkmp_get_msg: FFP_REQ_START: start on fly\n"); retval = ffp_start_l(mp->ffplayer); if (retval == 0) ijkmp_change_state_l(mp, MP_STATE_STARTED); } } pthread_mutex_unlock(&mp->mutex); break; case FFP_REQ_PAUSE: MPTRACE("ijkmp_get_msg: FFP_REQ_PAUSE\n"); continue_wait_next_msg = 1; pthread_mutex_lock(&mp->mutex); if (0 == ikjmp_chkst_pause_l(mp->mp_state)) { int pause_ret = ffp_pause_l(mp->ffplayer); if (pause_ret == 0) ijkmp_change_state_l(mp, MP_STATE_PAUSED); } pthread_mutex_unlock(&mp->mutex); break; case FFP_REQ_SEEK: MPTRACE("ijkmp_get_msg: FFP_REQ_SEEK\n"); continue_wait_next_msg = 1; pthread_mutex_lock(&mp->mutex); if (0 == ikjmp_chkst_seek_l(mp->mp_state)) { mp->restart_from_beginning = 0; if (0 == ffp_seek_to_l(mp->ffplayer, msg->arg1)) { av_log(mp->ffplayer, AV_LOG_DEBUG, "ijkmp_get_msg: FFP_REQ_SEEK: seek to %d\n", (int)msg->arg1); } } pthread_mutex_unlock(&mp->mutex); break; } if (continue_wait_next_msg) { msg_free_res(msg); continue; } return retval; } return -1; } ================================================ FILE: ijkmedia/ijkplayer/ijkplayer.h ================================================ /* * ijkplayer.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKPLAYER_ANDROID__IJKPLAYER_H #define IJKPLAYER_ANDROID__IJKPLAYER_H #include #include "ff_ffmsg_queue.h" #include "ijkmeta.h" #ifndef MPTRACE #define MPTRACE ALOGD #endif typedef struct IjkMediaPlayer IjkMediaPlayer; struct FFPlayer; struct SDL_Vout; /*- MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_IDLE); MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_INITIALIZED); MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_ASYNC_PREPARING); MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_PREPARED); MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_STARTED); MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_PAUSED); MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_COMPLETED); MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_STOPPED); MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_ERROR); MPST_CHECK_NOT_RET(mp->mp_state, MP_STATE_END); */ /*- * ijkmp_set_data_source() -> MP_STATE_INITIALIZED * * ijkmp_reset -> self * ijkmp_release -> MP_STATE_END */ #define MP_STATE_IDLE 0 /*- * ijkmp_prepare_async() -> MP_STATE_ASYNC_PREPARING * * ijkmp_reset -> MP_STATE_IDLE * ijkmp_release -> MP_STATE_END */ #define MP_STATE_INITIALIZED 1 /*- * ... -> MP_STATE_PREPARED * ... -> MP_STATE_ERROR * * ijkmp_reset -> MP_STATE_IDLE * ijkmp_release -> MP_STATE_END */ #define MP_STATE_ASYNC_PREPARING 2 /*- * ijkmp_seek_to() -> self * ijkmp_start() -> MP_STATE_STARTED * * ijkmp_reset -> MP_STATE_IDLE * ijkmp_release -> MP_STATE_END */ #define MP_STATE_PREPARED 3 /*- * ijkmp_seek_to() -> self * ijkmp_start() -> self * ijkmp_pause() -> MP_STATE_PAUSED * ijkmp_stop() -> MP_STATE_STOPPED * ... -> MP_STATE_COMPLETED * ... -> MP_STATE_ERROR * * ijkmp_reset -> MP_STATE_IDLE * ijkmp_release -> MP_STATE_END */ #define MP_STATE_STARTED 4 /*- * ijkmp_seek_to() -> self * ijkmp_start() -> MP_STATE_STARTED * ijkmp_pause() -> self * ijkmp_stop() -> MP_STATE_STOPPED * * ijkmp_reset -> MP_STATE_IDLE * ijkmp_release -> MP_STATE_END */ #define MP_STATE_PAUSED 5 /*- * ijkmp_seek_to() -> self * ijkmp_start() -> MP_STATE_STARTED (from beginning) * ijkmp_pause() -> self * ijkmp_stop() -> MP_STATE_STOPPED * * ijkmp_reset -> MP_STATE_IDLE * ijkmp_release -> MP_STATE_END */ #define MP_STATE_COMPLETED 6 /*- * ijkmp_stop() -> self * ijkmp_prepare_async() -> MP_STATE_ASYNC_PREPARING * * ijkmp_reset -> MP_STATE_IDLE * ijkmp_release -> MP_STATE_END */ #define MP_STATE_STOPPED 7 /*- * ijkmp_reset -> MP_STATE_IDLE * ijkmp_release -> MP_STATE_END */ #define MP_STATE_ERROR 8 /*- * ijkmp_release -> self */ #define MP_STATE_END 9 #define IJKMP_IO_STAT_READ 1 #define IJKMP_OPT_CATEGORY_FORMAT FFP_OPT_CATEGORY_FORMAT #define IJKMP_OPT_CATEGORY_CODEC FFP_OPT_CATEGORY_CODEC #define IJKMP_OPT_CATEGORY_SWS FFP_OPT_CATEGORY_SWS #define IJKMP_OPT_CATEGORY_PLAYER FFP_OPT_CATEGORY_PLAYER #define IJKMP_OPT_CATEGORY_SWR FFP_OPT_CATEGORY_SWR void ijkmp_global_init(); void ijkmp_global_uninit(); void ijkmp_global_set_log_report(int use_report); void ijkmp_global_set_log_level(int log_level); // log_level = AV_LOG_xxx void ijkmp_global_set_inject_callback(ijk_inject_callback cb); const char *ijkmp_version(); void ijkmp_io_stat_register(void (*cb)(const char *url, int type, int bytes)); void ijkmp_io_stat_complete_register(void (*cb)(const char *url, int64_t read_bytes, int64_t total_size, int64_t elpased_time, int64_t total_duration)); // ref_count is 1 after open IjkMediaPlayer *ijkmp_create(int (*msg_loop)(void*)); void* ijkmp_set_inject_opaque(IjkMediaPlayer *mp, void *opaque); void* ijkmp_set_ijkio_inject_opaque(IjkMediaPlayer *mp, void *opaque); void ijkmp_set_option(IjkMediaPlayer *mp, int opt_category, const char *name, const char *value); void ijkmp_set_option_int(IjkMediaPlayer *mp, int opt_category, const char *name, int64_t value); int ijkmp_get_video_codec_info(IjkMediaPlayer *mp, char **codec_info); int ijkmp_get_audio_codec_info(IjkMediaPlayer *mp, char **codec_info); void ijkmp_set_playback_rate(IjkMediaPlayer *mp, float rate); void ijkmp_set_playback_volume(IjkMediaPlayer *mp, float rate); int ijkmp_set_stream_selected(IjkMediaPlayer *mp, int stream, int selected); float ijkmp_get_property_float(IjkMediaPlayer *mp, int id, float default_value); void ijkmp_set_property_float(IjkMediaPlayer *mp, int id, float value); int64_t ijkmp_get_property_int64(IjkMediaPlayer *mp, int id, int64_t default_value); void ijkmp_set_property_int64(IjkMediaPlayer *mp, int id, int64_t value); // must be freed with free(); IjkMediaMeta *ijkmp_get_meta_l(IjkMediaPlayer *mp); // preferred to be called explicity, can be called multiple times // NOTE: ijkmp_shutdown may block thread void ijkmp_shutdown(IjkMediaPlayer *mp); void ijkmp_inc_ref(IjkMediaPlayer *mp); // call close at last release, also free memory // NOTE: ijkmp_dec_ref may block thread void ijkmp_dec_ref(IjkMediaPlayer *mp); void ijkmp_dec_ref_p(IjkMediaPlayer **pmp); int ijkmp_set_data_source(IjkMediaPlayer *mp, const char *url); int ijkmp_prepare_async(IjkMediaPlayer *mp); int ijkmp_start(IjkMediaPlayer *mp); int ijkmp_pause(IjkMediaPlayer *mp); int ijkmp_stop(IjkMediaPlayer *mp); int ijkmp_seek_to(IjkMediaPlayer *mp, long msec); int ijkmp_get_state(IjkMediaPlayer *mp); bool ijkmp_is_playing(IjkMediaPlayer *mp); long ijkmp_get_current_position(IjkMediaPlayer *mp); long ijkmp_get_duration(IjkMediaPlayer *mp); long ijkmp_get_playable_duration(IjkMediaPlayer *mp); void ijkmp_set_loop(IjkMediaPlayer *mp, int loop); int ijkmp_get_loop(IjkMediaPlayer *mp); void *ijkmp_get_weak_thiz(IjkMediaPlayer *mp); void *ijkmp_set_weak_thiz(IjkMediaPlayer *mp, void *weak_thiz); /* return < 0 if aborted, 0 if no packet and > 0 if packet. */ /* need to call msg_free_res for freeing the resouce obtained in msg */ int ijkmp_get_msg(IjkMediaPlayer *mp, AVMessage *msg, int block); void ijkmp_set_frame_at_time(IjkMediaPlayer *mp, const char *path, int64_t start_time, int64_t end_time, int num, int definition); #endif ================================================ FILE: ijkmedia/ijkplayer/ijkplayer_internal.h ================================================ /* * ijkplayer_internal.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKPLAYER_ANDROID__IJKPLAYER_INTERNAL_H #define IJKPLAYER_ANDROID__IJKPLAYER_INTERNAL_H #include #include "ijksdl/ijksdl.h" #include "ff_fferror.h" #include "ff_ffplay.h" #include "ijkplayer.h" struct IjkMediaPlayer { volatile int ref_count; pthread_mutex_t mutex; FFPlayer *ffplayer; int (*msg_loop)(void*); SDL_Thread *msg_thread; SDL_Thread _msg_thread; int mp_state; char *data_source; void *weak_thiz; int restart; int restart_from_beginning; int seek_req; long seek_msec; }; #endif ================================================ FILE: ijkmedia/ijkplayer/pipeline/ffpipeline_ffplay.c ================================================ /* * ffpipeline_ffplay.c * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ffpipeline_ffplay.h" #include "ffpipenode_ffplay_vdec.h" #include "../ff_ffplay.h" static SDL_Class g_pipeline_class = { .name = "ffpipeline_ffplay", }; struct IJKFF_Pipeline_Opaque { FFPlayer *ffp; }; static void func_destroy(IJKFF_Pipeline *pipeline) { // do nothing } static IJKFF_Pipenode *func_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp) { return ffpipenode_create_video_decoder_from_ffplay(ffp); } static SDL_Aout *func_open_audio_output(IJKFF_Pipeline *pipeline, FFPlayer *ffp) { return NULL; } IJKFF_Pipeline *ffpipeline_create_from_ffplay(FFPlayer *ffp) { IJKFF_Pipeline *pipeline = ffpipeline_alloc(&g_pipeline_class, sizeof(IJKFF_Pipeline_Opaque)); if (!pipeline) return pipeline; IJKFF_Pipeline_Opaque *opaque = pipeline->opaque; opaque->ffp = ffp; pipeline->func_destroy = func_destroy; pipeline->func_open_video_decoder = func_open_video_decoder; pipeline->func_open_audio_output = func_open_audio_output; return pipeline; } ================================================ FILE: ijkmedia/ijkplayer/pipeline/ffpipeline_ffplay.h ================================================ /* * ffpipeline_ffplay.h * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__FF_FFPIPELINE_FFPLAY_H #define FFPLAY__FF_FFPIPELINE_FFPLAY_H #include "../ff_ffpipeline.h" // There is no default aout for ffplay. // IJKFF_Pipeline *ffpipeline_create_from_ffplay(FFPlayer *ffp); #endif ================================================ FILE: ijkmedia/ijkplayer/pipeline/ffpipenode_ffplay_vdec.c ================================================ /* * ffpipenode_ffplay_vdec.c * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ffpipenode_ffplay_vdec.h" #include "../ff_ffpipenode.h" #include "../ff_ffplay.h" struct IJKFF_Pipenode_Opaque { FFPlayer *ffp; }; static void func_destroy(IJKFF_Pipenode *node) { // do nothing } static int func_run_sync(IJKFF_Pipenode *node) { IJKFF_Pipenode_Opaque *opaque = node->opaque; return ffp_video_thread(opaque->ffp); } IJKFF_Pipenode *ffpipenode_create_video_decoder_from_ffplay(FFPlayer *ffp) { IJKFF_Pipenode *node = ffpipenode_alloc(sizeof(IJKFF_Pipenode_Opaque)); if (!node) return node; IJKFF_Pipenode_Opaque *opaque = node->opaque; opaque->ffp = ffp; node->func_destroy = func_destroy; node->func_run_sync = func_run_sync; ffp_set_video_codec_info(ffp, AVCODEC_MODULE_NAME, avcodec_get_name(ffp->is->viddec.avctx->codec_id)); ffp->stat.vdec_type = FFP_PROPV_DECODER_AVCODEC; return node; } ================================================ FILE: ijkmedia/ijkplayer/pipeline/ffpipenode_ffplay_vdec.h ================================================ /* * ffpipenode_ffplay_vdec.h * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__FF_FFPIPENODE_FFPLAY_VDEC_H #define FFPLAY__FF_FFPIPENODE_FFPLAY_VDEC_H #include "../ff_ffpipenode.h" struct FFPlayer; IJKFF_Pipenode *ffpipenode_create_video_decoder_from_ffplay(struct FFPlayer *ffp); #endif ================================================ FILE: ijkmedia/ijkplayer/version.sh ================================================ #!/bin/sh # Usage: version.sh # check for git short hash if ! test "$revision"; then if (cd "$1" && grep git RELEASE 2> /dev/null >/dev/null) ; then revision=$(cd "$1" && git describe --tags --match N 2> /dev/null) else revision=$(cd "$1" && git describe --tags --always 2> /dev/null) fi fi # Shallow Git clones (--depth) do not have the N tag: # use 'git-YYYY-MM-DD-hhhhhhh'. test "$revision" || revision=$(cd "$1" && git log -1 --pretty=format:"git-%cd-%h" --date=short 2> /dev/null) # Snapshots from gitweb are in a directory called ijkplayer-hhhhhhh or # ijkplayer-HEAD-hhhhhhh. if [ -z "$revision" ]; then srcdir=$(cd "$1" && pwd) case "$srcdir" in */ijkplayer-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]) git_hash="${srcdir##*-}";; */ijkplayer-HEAD-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]) git_hash="${srcdir##*-}";; esac fi # no revision number found test "$revision" || revision=$(cd "$1" && cat RELEASE 2> /dev/null) # Append the Git hash if we have one test "$revision" && test "$git_hash" && revision="$revision-$git_hash" # releases extract the version number from the VERSION file version=$(cd "$1" && cat VERSION 2> /dev/null) test "$version" || version=$revision if [ -z "$2" ]; then echo "$version" exit fi cd $1 NEW_REVISION="#define IJKPLAYER_VERSION \"$version\"" OLD_REVISION=$(cat "$2" 2> /dev/null | head -4 | tail -1) # String used for preprocessor guard GUARD=$(echo "$2" | sed 's/\//_/' | sed 's/\./_/' | tr '[:lower:]' '[:upper:]' | sed 's/LIB//') # Update version header only on revision changes to avoid spurious rebuilds if test "$NEW_REVISION" != "$OLD_REVISION"; then cat << EOF > "$2" /* Automatically generated by version.sh, do not manually edit! */ #ifndef $GUARD #define $GUARD $NEW_REVISION #endif /* $GUARD */ EOF fi ================================================ FILE: ijkmedia/ijksdl/Android.mk ================================================ # Copyright (c) 2013 Bilibili # copyright (c) 2013 Zhang Rui # # This file is part of ijkPlayer. # # ijkPlayer 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. # # ijkPlayer 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 ijkPlayer; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_CFLAGS += -std=c99 LOCAL_LDLIBS += -llog -landroid -lOpenSLES -lEGL -lGLESv2 LOCAL_C_INCLUDES += $(LOCAL_PATH) LOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/..) LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH) LOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/../ijkyuv/include) LOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/../ijkj4a) LOCAL_SRC_FILES += ijksdl_aout.c LOCAL_SRC_FILES += ijksdl_audio.c LOCAL_SRC_FILES += ijksdl_egl.c LOCAL_SRC_FILES += ijksdl_error.c LOCAL_SRC_FILES += ijksdl_mutex.c LOCAL_SRC_FILES += ijksdl_stdinc.c LOCAL_SRC_FILES += ijksdl_thread.c LOCAL_SRC_FILES += ijksdl_timer.c LOCAL_SRC_FILES += ijksdl_vout.c LOCAL_SRC_FILES += ijksdl_extra_log.c LOCAL_SRC_FILES += gles2/color.c LOCAL_SRC_FILES += gles2/common.c LOCAL_SRC_FILES += gles2/renderer.c LOCAL_SRC_FILES += gles2/renderer_rgb.c LOCAL_SRC_FILES += gles2/renderer_yuv420p.c LOCAL_SRC_FILES += gles2/renderer_yuv444p10le.c LOCAL_SRC_FILES += gles2/shader.c LOCAL_SRC_FILES += gles2/fsh/rgb.fsh.c LOCAL_SRC_FILES += gles2/fsh/yuv420p.fsh.c LOCAL_SRC_FILES += gles2/fsh/yuv444p10le.fsh.c LOCAL_SRC_FILES += gles2/vsh/mvp.vsh.c LOCAL_SRC_FILES += dummy/ijksdl_vout_dummy.c LOCAL_SRC_FILES += ffmpeg/ijksdl_vout_overlay_ffmpeg.c LOCAL_SRC_FILES += ffmpeg/abi_all/image_convert.c LOCAL_SRC_FILES += android/android_audiotrack.c LOCAL_SRC_FILES += android/android_nativewindow.c LOCAL_SRC_FILES += android/ijksdl_android_jni.c LOCAL_SRC_FILES += android/ijksdl_aout_android_audiotrack.c LOCAL_SRC_FILES += android/ijksdl_aout_android_opensles.c LOCAL_SRC_FILES += android/ijksdl_codec_android_mediacodec_dummy.c LOCAL_SRC_FILES += android/ijksdl_codec_android_mediacodec_internal.c LOCAL_SRC_FILES += android/ijksdl_codec_android_mediacodec_java.c LOCAL_SRC_FILES += android/ijksdl_codec_android_mediacodec.c LOCAL_SRC_FILES += android/ijksdl_codec_android_mediadef.c LOCAL_SRC_FILES += android/ijksdl_codec_android_mediaformat_java.c LOCAL_SRC_FILES += android/ijksdl_codec_android_mediaformat.c LOCAL_SRC_FILES += android/ijksdl_vout_android_nativewindow.c LOCAL_SRC_FILES += android/ijksdl_vout_android_surface.c LOCAL_SRC_FILES += android/ijksdl_vout_overlay_android_mediacodec.c LOCAL_SHARED_LIBRARIES := ijkffmpeg LOCAL_STATIC_LIBRARIES := cpufeatures yuv_static ijkj4a LOCAL_MODULE := ijksdl include $(BUILD_SHARED_LIBRARY) $(call import-module,android/cpufeatures) ================================================ FILE: ijkmedia/ijksdl/android/android_audiotrack.c ================================================ /***************************************************************************** * android_audiotrack.c ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "android_audiotrack.h" #include #include "j4au/class/android/media/AudioTrack.util.h" #include "ijksdl_android_jni.h" #include "../ijksdl_inc_internal.h" #include "../ijksdl_audio.h" #ifdef SDLTRACE #undef SDLTRACE #define SDLTRACE(...) #endif typedef struct AudioChannelMapEntry { Uint8 sdl_channel; int android_channel; const char *sdl_name; const char *android_name; } AudioChannelMapEntry; static AudioChannelMapEntry g_audio_channel_map[] = { { 2, CHANNEL_OUT_STEREO, "2-chan", "CHANNEL_OUT_STEREO" }, { 1, CHANNEL_OUT_MONO, "1-chan", "CHANNEL_OUT_MONO" }, }; typedef struct AudioFormatMapEntry { SDL_AudioFormat sdl_format; int android_format; const char *sdl_name; const char *android_name; } AudioFormatMapEntry; static AudioFormatMapEntry g_audio_format_map[] = { { AUDIO_S16SYS, ENCODING_PCM_16BIT, "AUDIO_S16SYS", "ENCODING_PCM_16BIT" }, { AUDIO_U8, ENCODING_PCM_8BIT, "AUDIO_U8", "ENCODING_PCM_8BIT" }, { AUDIO_F32, ENCODING_PCM_FLOAT, "AUDIO_F32", "ENCODING_PCM_FLOAT" }, }; static Uint8 find_sdl_channel(int android_channel) { for (int i = 0; i < NELEM(g_audio_channel_map); ++i) { AudioChannelMapEntry *entry = &g_audio_channel_map[i]; if (entry->android_channel == android_channel) return entry->sdl_channel; } return 0; } static int find_android_channel(int sdl_channel) { for (int i = 0; i < NELEM(g_audio_channel_map); ++i) { AudioChannelMapEntry *entry = &g_audio_channel_map[i]; if (entry->sdl_channel == sdl_channel) return entry->android_channel; } return CHANNEL_OUT_INVALID; } static SDL_AudioFormat find_sdl_format(int android_format) { for (int i = 0; i < NELEM(g_audio_format_map); ++i) { AudioFormatMapEntry *entry = &g_audio_format_map[i]; if (entry->android_format == android_format) return entry->sdl_format; } return AUDIO_INVALID; } static int find_android_format(int sdl_format) { for (int i = 0; i < NELEM(g_audio_format_map); ++i) { AudioFormatMapEntry *entry = &g_audio_format_map[i]; if (entry->sdl_format == sdl_format) return entry->android_format; } return ENCODING_INVALID; } typedef struct SDL_Android_AudioTrack { jobject thiz; SDL_Android_AudioTrack_Spec spec; jbyteArray byte_buffer; int byte_buffer_capacity; int min_buffer_size; float max_volume; float min_volume; } SDL_Android_AudioTrack; static void SDL_Android_AudioTrack_get_default_spec(SDL_Android_AudioTrack_Spec *spec) { assert(spec); spec->stream_type = STREAM_MUSIC; spec->sample_rate_in_hz = 0; spec->channel_config = CHANNEL_OUT_STEREO; spec->audio_format = ENCODING_PCM_16BIT; spec->buffer_size_in_bytes = 0; spec->mode = MODE_STREAM; } #define STREAM_MUSIC 3 int audiotrack_get_native_output_sample_rate(JNIEnv *env) { if (!env) { if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SetupThreadEnv failed", __func__); return -1; } } jint retval = J4AC_AudioTrack__getNativeOutputSampleRate(env, STREAM_MUSIC); if (J4A_ExceptionCheck__catchAll(env) || retval <= 0) return -1; return retval; } void SDL_Android_AudioTrack_set_volume(JNIEnv *env, SDL_Android_AudioTrack *atrack, float left_volume, float right_volume) { J4AC_AudioTrack__setStereoVolume__catchAll(env, atrack->thiz, left_volume, right_volume); } SDL_Android_AudioTrack *SDL_Android_AudioTrack_new_from_spec(JNIEnv *env, SDL_Android_AudioTrack_Spec *spec) { assert(spec); switch (spec->channel_config) { case CHANNEL_OUT_MONO: ALOGI("SDL_Android_AudioTrack: %s", "CHANNEL_OUT_MONO"); break; case CHANNEL_OUT_STEREO: ALOGI("SDL_Android_AudioTrack: %s", "CHANNEL_OUT_STEREO"); break; default: ALOGE("%s: invalid channel %d", __func__, spec->channel_config); return NULL; } switch (spec->audio_format) { case ENCODING_PCM_16BIT: ALOGI("SDL_Android_AudioTrack: %s", "ENCODING_PCM_16BIT"); break; case ENCODING_PCM_8BIT: ALOGI("SDL_Android_AudioTrack: %s", "ENCODING_PCM_8BIT"); break; #if 0 case ENCODING_PCM_FLOAT: ALOGI("SDL_Android_AudioTrack: %s", "ENCODING_PCM_FLOAT"); if (sdk_int < IJK_API_21_LOLLIPOP) { ALOGI("SDL_Android_AudioTrack: %s need API 21 or above", "ENCODING_PCM_FLOAT"); return NULL; } break; #endif default: ALOGE("%s: invalid format %d", __func__, spec->audio_format); return NULL; } if (spec->sample_rate_in_hz <= 0) { ALOGE("%s: invalid sample rate %d", __func__, spec->sample_rate_in_hz); return NULL; } SDL_Android_AudioTrack *atrack = (SDL_Android_AudioTrack*) mallocz(sizeof(SDL_Android_AudioTrack)); if (!atrack) { ALOGE("%s: mallocz faild.\n", __func__); return NULL; } atrack->spec = *spec; // libswresample is ugly, depending on native resampler while (atrack->spec.sample_rate_in_hz < 4000) { atrack->spec.sample_rate_in_hz *= 2; } while (atrack->spec.sample_rate_in_hz > 48000) { atrack->spec.sample_rate_in_hz /= 2; } int min_buffer_size = J4AC_AudioTrack__getMinBufferSize(env, atrack->spec.sample_rate_in_hz, atrack->spec.channel_config, atrack->spec.audio_format); if (J4A_ExceptionCheck__catchAll(env) || min_buffer_size <= 0) { ALOGE("%s: J4AC_AudioTrack__getMinBufferSize: return %d:", __func__, min_buffer_size); free(atrack); return NULL; } // for fast playback min_buffer_size *= AUDIOTRACK_PLAYBACK_MAXSPEED; atrack->thiz = J4AC_AudioTrack__AudioTrack__asGlobalRef__catchAll(env, atrack->spec.stream_type, atrack->spec.sample_rate_in_hz, atrack->spec.channel_config, atrack->spec.audio_format, min_buffer_size, atrack->spec.mode); if (!atrack->thiz) { free(atrack); return NULL; } atrack->min_buffer_size = min_buffer_size; atrack->spec.buffer_size_in_bytes = min_buffer_size; // atrack->max_volume = J4AC_AudioTrack__getMaxVolume__catchAll(env); // atrack->min_volume = J4AC_AudioTrack__getMinVolume__catchAll(env); atrack->max_volume = 1.0f; atrack->min_volume = 0.0f; // extra init float init_volume = 1.0f; init_volume = IJKMIN(init_volume, atrack->max_volume); init_volume = IJKMAX(init_volume, atrack->min_volume); ALOGI("%s: init volume as %f/(%f,%f)", __func__, init_volume, atrack->min_volume, atrack->max_volume); J4AC_AudioTrack__setStereoVolume__catchAll(env, atrack->thiz, init_volume, init_volume); return atrack; } SDL_Android_AudioTrack *SDL_Android_AudioTrack_new_from_sdl_spec(JNIEnv *env, const SDL_AudioSpec *sdl_spec) { SDL_Android_AudioTrack_Spec atrack_spec; SDL_Android_AudioTrack_get_default_spec(&atrack_spec); atrack_spec.sample_rate_in_hz = sdl_spec->freq; atrack_spec.channel_config = find_android_channel(sdl_spec->channels); atrack_spec.audio_format = find_android_format(sdl_spec->format); atrack_spec.buffer_size_in_bytes = sdl_spec->size; return SDL_Android_AudioTrack_new_from_spec(env, &atrack_spec); } void SDL_Android_AudioTrack_free(JNIEnv *env, SDL_Android_AudioTrack* atrack) { J4A_DeleteGlobalRef__p(env, &atrack->byte_buffer); atrack->byte_buffer_capacity = 0; if (atrack->thiz) { J4AC_AudioTrack__release(env, atrack->thiz); J4A_DeleteGlobalRef__p(env, &atrack->thiz); } free(atrack); } void SDL_Android_AudioTrack_get_target_spec(SDL_Android_AudioTrack *atrack, SDL_AudioSpec *sdl_spec) { SDL_Android_AudioTrack_Spec *atrack_spec = &atrack->spec; sdl_spec->freq = atrack_spec->sample_rate_in_hz; sdl_spec->channels = find_sdl_channel(atrack_spec->channel_config); sdl_spec->format = find_sdl_format(atrack_spec->audio_format); sdl_spec->size = atrack_spec->buffer_size_in_bytes; sdl_spec->silence = 0; sdl_spec->padding = 0; } int SDL_Android_AudioTrack_get_min_buffer_size(SDL_Android_AudioTrack* atrack) { return atrack->min_buffer_size; } void SDL_Android_AudioTrack_play(JNIEnv *env, SDL_Android_AudioTrack *atrack) { SDLTRACE("%s", __func__); J4AC_AudioTrack__play__catchAll(env, atrack->thiz); } void SDL_Android_AudioTrack_pause(JNIEnv *env, SDL_Android_AudioTrack *atrack) { SDLTRACE("%s", __func__); J4AC_AudioTrack__pause__catchAll(env, atrack->thiz); } void SDL_Android_AudioTrack_flush(JNIEnv *env, SDL_Android_AudioTrack *atrack) { SDLTRACE("%s", __func__); J4AC_AudioTrack__flush__catchAll(env, atrack->thiz); } void SDL_Android_AudioTrack_stop(JNIEnv *env, SDL_Android_AudioTrack *atrack) { SDLTRACE("%s", __func__); J4AC_AudioTrack__stop__catchAll(env, atrack->thiz); } int SDL_Android_AudioTrack_reserve_byte_buffer(JNIEnv *env, SDL_Android_AudioTrack *atrack, int size_in_byte) { if (atrack->byte_buffer && size_in_byte <= atrack->byte_buffer_capacity) return size_in_byte; J4A_DeleteGlobalRef__p(env, &atrack->byte_buffer); atrack->byte_buffer_capacity = 0; int capacity = IJKMAX(size_in_byte, atrack->min_buffer_size); atrack->byte_buffer = J4A_NewByteArray__asGlobalRef__catchAll(env, capacity); if (!atrack->byte_buffer) return -1; atrack->byte_buffer_capacity = capacity; return capacity; } int SDL_Android_AudioTrack_write(JNIEnv *env, SDL_Android_AudioTrack *atrack, uint8_t *data, int size_in_byte) { if (size_in_byte <= 0) return size_in_byte; int reserved = SDL_Android_AudioTrack_reserve_byte_buffer(env, atrack, size_in_byte); if (reserved < size_in_byte) { ALOGE("%s failed %d < %d\n", __func__, reserved, size_in_byte); return -1; } (*env)->SetByteArrayRegion(env, atrack->byte_buffer, 0, (int)size_in_byte, (jbyte*) data); if (J4A_ExceptionCheck__catchAll(env)) return -1; int retval = J4AC_AudioTrack__write(env, atrack->thiz, atrack->byte_buffer, 0, (int)size_in_byte); if (J4A_ExceptionCheck__catchAll(env)) return -1; return retval; } int SDL_Android_AudioTrack_getAudioSessionId(JNIEnv *env, SDL_Android_AudioTrack *atrack) { SDLTRACE("%s", __func__); int audioSessionId = J4AC_AudioTrack__getAudioSessionId(env, atrack->thiz); if (J4A_ExceptionCheck__catchAll(env)) return 0; return audioSessionId; } void SDL_Android_AudioTrack_setSpeed(JNIEnv *env, SDL_Android_AudioTrack *atrack, float speed) { J4AC_AudioTrack__setSpeed(env, atrack->thiz, speed); if (J4A_ExceptionCheck__catchAll(env)) return; return; } ================================================ FILE: ijkmedia/ijksdl/android/android_audiotrack.h ================================================ /***************************************************************************** * android_audiotrack.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_ANDROID__ANDROID_AUDIOTRACK_H #define IJKSDL_ANDROID__ANDROID_AUDIOTRACK_H #include #include #include "../ijksdl_audio.h" #include "../ijksdl_aout.h" #define AUDIOTRACK_PLAYBACK_MAXSPEED (2) typedef struct SDL_Android_AudioTrack_Spec { enum StreamType { STREAM_VOICE_CALL = 0, STREAM_SYSTEM = 1, STREAM_RING = 2, STREAM_MUSIC = 3, STREAM_ALARM = 4, STREAM_NOTIFICATION = 5, } stream_type; int sample_rate_in_hz; enum ChannelConfig { CHANNEL_OUT_INVALID = 0x0, CHANNEL_OUT_DEFAULT = 0x1, /* f-l */ CHANNEL_OUT_MONO = 0x4, /* f-l, f-r */ CHANNEL_OUT_STEREO = 0xc, /* f-l, f-r, b-l, b-r */ CHANNEL_OUT_QUAD = 0xcc, /* f-l, f-r, b-l, b-r */ CHANNEL_OUT_SURROUND = 0x41c, /* f-l, f-r, f-c, b-c */ CHANNEL_OUT_5POINT1 = 0xfc, /* f-l, f-r, b-l, b-r, f-c, low */ CHANNEL_OUT_7POINT1 = 0x3fc, /* f-l, f-r, b-l, b-r, f-c, low, f-lc, f-rc */ CHANNEL_OUT_FRONT_LEFT = 0x4, CHANNEL_OUT_FRONT_RIGHT = 0x8, CHANNEL_OUT_BACK_LEFT = 0x40, CHANNEL_OUT_BACK_RIGHT = 0x80, CHANNEL_OUT_FRONT_CENTER = 0x10, CHANNEL_OUT_LOW_FREQUENCY = 0x20, CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100, CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200, CHANNEL_OUT_BACK_CENTER = 0x400, } channel_config; enum AudioFormat { ENCODING_INVALID = 0, ENCODING_DEFAULT = 1, ENCODING_PCM_16BIT = 2, // signed, guaranteed to be supported by devices. ENCODING_PCM_8BIT = 3, // unsigned, not guaranteed to be supported by devices. ENCODING_PCM_FLOAT = 4, // single-precision floating-point per sample } audio_format; int buffer_size_in_bytes; enum Mode { MODE_STATIC = 0, MODE_STREAM = 1, } mode; enum WriteMode { WRITE_BLOCKING = 0, WRITE_NON_BLOCKING = 1, } write_mode; // not used // extra field int sdl_samples; } SDL_Android_AudioTrack_Spec; typedef struct SDL_Android_AudioTrack SDL_Android_AudioTrack; SDL_Android_AudioTrack *SDL_Android_AudioTrack_new_from_spec(JNIEnv *env, SDL_Android_AudioTrack_Spec *spec); SDL_Android_AudioTrack *SDL_Android_AudioTrack_new_from_sdl_spec(JNIEnv *env, const SDL_AudioSpec *sdl_spec); void SDL_Android_AudioTrack_free(JNIEnv *env, SDL_Android_AudioTrack* atrack); void SDL_Android_AudioTrack_get_target_spec(SDL_Android_AudioTrack* atrack, SDL_AudioSpec *spec); int SDL_Android_AudioTrack_get_min_buffer_size(SDL_Android_AudioTrack* atrack); int audiotrack_get_native_output_sample_rate(JNIEnv *env/* = NULL */); void SDL_Android_AudioTrack_play(JNIEnv *env, SDL_Android_AudioTrack *atrack); void SDL_Android_AudioTrack_pause(JNIEnv *env, SDL_Android_AudioTrack *atrack); void SDL_Android_AudioTrack_flush(JNIEnv *env, SDL_Android_AudioTrack *atrack); void SDL_Android_AudioTrack_set_volume(JNIEnv *env, SDL_Android_AudioTrack *atrack, float left_volume, float right_volume); void SDL_Android_AudioTrack_stop(JNIEnv *env, SDL_Android_AudioTrack *atrack); void SDL_Android_AudioTrack_release(JNIEnv *env, SDL_Android_AudioTrack *atrack); int SDL_Android_AudioTrack_write(JNIEnv *env, SDL_Android_AudioTrack *atrack, uint8_t *data, int size_in_byte); int SDL_Android_AudioTrack_getAudioSessionId(JNIEnv *env, SDL_Android_AudioTrack *atrack); void SDL_Android_AudioTrack_setSpeed(JNIEnv *env, SDL_Android_AudioTrack *atrack, float speed); #endif ================================================ FILE: ijkmedia/ijksdl/android/android_nativewindow.c ================================================ /***************************************************************************** * android_nativewindow.c ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "android_nativewindow.h" #include #include #include "../ijksdl_vout.h" #include "../ijksdl_vout_internal.h" #include "../ffmpeg/ijksdl_inc_ffmpeg.h" #include "ijksdl_inc_internal_android.h" #ifdef SDLTRACE #undef SDLTRACE #define SDLTRACE(...) #endif static int android_render_yv12_on_yv12(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay) { // SDLTRACE("SDL_VoutAndroid: android_render_yv12_on_yv12(%p)", overlay); assert(overlay->format == SDL_FCC_YV12); assert(overlay->planes == 3); int min_height = IJKMIN(out_buffer->height, overlay->h); int dst_y_stride = out_buffer->stride; int dst_c_stride = IJKALIGN(out_buffer->stride / 2, 16); int dst_y_size = dst_y_stride * out_buffer->height; int dst_c_size = dst_c_stride * out_buffer->height / 2; // ALOGE("stride:%d/%d, size:%d/%d", dst_y_stride, dst_c_stride, dst_y_size, dst_c_size); uint8_t *dst_pixels_array[] = { out_buffer->bits, out_buffer->bits + dst_y_size, out_buffer->bits + dst_y_size + dst_c_size, }; int dst_line_height[] = { min_height, min_height / 2, min_height / 2 }; int dst_line_size_array[] = { dst_y_stride, dst_c_stride, dst_c_stride }; for (int i = 0; i < 3; ++i) { int dst_line_size = dst_line_size_array[i]; int src_line_size = overlay->pitches[i]; int line_height = dst_line_height[i]; uint8_t *dst_pixels = dst_pixels_array[i]; const uint8_t *src_pixels = overlay->pixels[i]; if (dst_line_size == src_line_size) { int plane_size = src_line_size * line_height; // ALOGE("sdl_image_copy_plane %p %p %d", dst_pixels, src_pixels, dst_plane_size); memcpy(dst_pixels, src_pixels, plane_size); } else { // TODO: 9 padding int bytewidth = IJKMIN(dst_line_size, src_line_size); // ALOGE("av_image_copy_plane %p %d %p %d %d %d", dst_pixels, dst_line_size, src_pixels, src_line_size, bytewidth, line_height); av_image_copy_plane(dst_pixels, dst_line_size, src_pixels, src_line_size, bytewidth, line_height); } } return 0; } static int android_render_on_yv12(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay) { assert(out_buffer); assert(overlay); switch (overlay->format) { case SDL_FCC_YV12: { return android_render_yv12_on_yv12(out_buffer, overlay); } } return -1; } static int android_render_rgb_on_rgb(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay, int bpp) { // SDLTRACE("SDL_VoutAndroid: android_render_rgb_on_rgb(%p)", overlay); assert(overlay->format == SDL_FCC_RV16); assert(overlay->planes == 1); int min_height = IJKMIN(out_buffer->height, overlay->h); int dst_stride = out_buffer->stride; int src_line_size = overlay->pitches[0]; int dst_line_size = dst_stride * bpp / 8; uint8_t *dst_pixels = out_buffer->bits; const uint8_t *src_pixels = overlay->pixels[0]; if (dst_line_size == src_line_size) { int plane_size = src_line_size * min_height; // ALOGE("android_render_rgb_on_rgb (pix-match) %p %p %d", dst_pixels, src_pixels, plane_size); memcpy(dst_pixels, src_pixels, plane_size); } else { // TODO: 9 padding int bytewidth = IJKMIN(dst_line_size, src_line_size); // ALOGE("android_render_rgb_on_rgb (pix-mismatch) %p %d %p %d %d %d", dst_pixels, dst_line_size, src_pixels, src_line_size, bytewidth, min_height); av_image_copy_plane(dst_pixels, dst_line_size, src_pixels, src_line_size, bytewidth, min_height); } return 0; } static int android_render_rgb565_on_rgb565(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay) { return android_render_rgb_on_rgb(out_buffer, overlay, 16); } static int android_render_on_rgb565(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay) { assert(out_buffer); assert(overlay); switch (overlay->format) { case SDL_FCC_RV16: { return android_render_rgb565_on_rgb565(out_buffer, overlay); } } return -1; } static int android_render_rgb32_on_rgb8888(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay) { return android_render_rgb_on_rgb(out_buffer, overlay, 32); } static int android_render_on_rgb8888(ANativeWindow_Buffer *out_buffer, const SDL_VoutOverlay *overlay) { assert(out_buffer); assert(overlay); switch (overlay->format) { case SDL_FCC_RV32: { return android_render_rgb32_on_rgb8888(out_buffer, overlay); } } return -1; } typedef struct AndroidHalFourccDescriptor { Uint32 fcc_or_hal; const char* name; int hal_format; int (*render)(ANativeWindow_Buffer *native_buffer, const SDL_VoutOverlay *overlay); } AndroidHalFourccDescriptor; static AndroidHalFourccDescriptor g_hal_fcc_map[] = { // YV12 { HAL_PIXEL_FORMAT_YV12, "HAL_YV12", HAL_PIXEL_FORMAT_YV12, android_render_on_yv12 }, { SDL_FCC_YV12, "YV12", HAL_PIXEL_FORMAT_YV12, android_render_on_yv12 }, // RGB565 { HAL_PIXEL_FORMAT_RGB_565, "HAL_RGB_565", HAL_PIXEL_FORMAT_RGB_565, android_render_on_rgb565 }, { SDL_FCC_RV16, "RV16", HAL_PIXEL_FORMAT_RGB_565, android_render_on_rgb565 }, // RGB8888 { HAL_PIXEL_FORMAT_RGBX_8888, "HAL_RGBX_8888", HAL_PIXEL_FORMAT_RGBX_8888, android_render_on_rgb8888 }, { HAL_PIXEL_FORMAT_RGBA_8888, "HAL_RGBA_8888", HAL_PIXEL_FORMAT_RGBA_8888, android_render_on_rgb8888 }, { HAL_PIXEL_FORMAT_BGRA_8888, "HAL_BGRA_8888", HAL_PIXEL_FORMAT_BGRA_8888, android_render_on_rgb8888 }, { SDL_FCC_RV32, "RV32", HAL_PIXEL_FORMAT_RGBX_8888, android_render_on_rgb8888 }, }; AndroidHalFourccDescriptor *native_window_get_desc(int fourcc_or_hal) { for (int i = 0; i < NELEM(g_hal_fcc_map); ++i) { AndroidHalFourccDescriptor *desc = &g_hal_fcc_map[i]; if (desc->fcc_or_hal == fourcc_or_hal) return desc; } return NULL; } int SDL_Android_NativeWindow_display_l(ANativeWindow *native_window, SDL_VoutOverlay *overlay) { int retval; if (!native_window) return -1; if (!overlay) { ALOGE("SDL_Android_NativeWindow_display_l: NULL overlay"); return -1; } if (overlay->w <= 0 || overlay->h <= 0) { ALOGE("SDL_Android_NativeWindow_display_l: invalid overlay dimensions(%d, %d)", overlay->w, overlay->h); return -1; } int curr_w = ANativeWindow_getWidth(native_window); int curr_h = ANativeWindow_getHeight(native_window); int curr_format = ANativeWindow_getFormat(native_window); int buff_w = IJKALIGN(overlay->w, 2); int buff_h = IJKALIGN(overlay->h, 2); AndroidHalFourccDescriptor *overlayDesc = native_window_get_desc(overlay->format); if (!overlayDesc) { ALOGE("SDL_Android_NativeWindow_display_l: unknown overlay format: %d", overlay->format); return -1; } AndroidHalFourccDescriptor *voutDesc = native_window_get_desc(curr_format); if (!voutDesc || voutDesc->hal_format != overlayDesc->hal_format) { ALOGD("ANativeWindow_setBuffersGeometry: w=%d, h=%d, f=%.4s(0x%x) => w=%d, h=%d, f=%.4s(0x%x)", curr_w, curr_h, (char*) &curr_format, curr_format, buff_w, buff_h, (char*) &overlay->format, overlay->format); retval = ANativeWindow_setBuffersGeometry(native_window, buff_w, buff_h, overlayDesc->hal_format); if (retval < 0) { ALOGE("SDL_Android_NativeWindow_display_l: ANativeWindow_setBuffersGeometry: failed %d", retval); return retval; } if (!voutDesc) { ALOGE("SDL_Android_NativeWindow_display_l: unknown hal format %d", curr_format); return -1; } } ANativeWindow_Buffer out_buffer; retval = ANativeWindow_lock(native_window, &out_buffer, NULL); if (retval < 0) { ALOGE("SDL_Android_NativeWindow_display_l: ANativeWindow_lock: failed %d", retval); return retval; } if (out_buffer.width != buff_w || out_buffer.height != buff_h) { ALOGE("unexpected native window buffer (%p)(w:%d, h:%d, fmt:'%.4s'0x%x), expecting (w:%d, h:%d, fmt:'%.4s'0x%x)", native_window, out_buffer.width, out_buffer.height, (char*)&out_buffer.format, out_buffer.format, buff_w, buff_h, (char*)&overlay->format, overlay->format); // TODO: 8 set all black ANativeWindow_unlockAndPost(native_window); ANativeWindow_setBuffersGeometry(native_window, buff_w, buff_h, overlayDesc->hal_format); return -1; } int render_ret = voutDesc->render(&out_buffer, overlay); if (render_ret < 0) { // TODO: 8 set all black // return after unlock image; } retval = ANativeWindow_unlockAndPost(native_window); if (retval < 0) { ALOGE("SDL_Android_NativeWindow_display_l: ANativeWindow_unlockAndPost: failed %d", retval); return retval; } return render_ret; } ================================================ FILE: ijkmedia/ijksdl/android/android_nativewindow.h ================================================ /***************************************************************************** * android_nativewindow.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_ANDROID__ANDROID_NATIVEWINDOW_H #define IJKSDL_ANDROID__ANDROID_NATIVEWINDOW_H typedef struct ANativeWindow ANativeWindow; typedef struct SDL_VoutOverlay SDL_VoutOverlay; int SDL_Android_NativeWindow_display_l(ANativeWindow* native_window, SDL_VoutOverlay *overlay); #endif ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_android.h ================================================ /***************************************************************************** * ijksdl_android.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_ANDROID__IJKSDL_ANDROID_H #define IJKSDL_ANDROID__IJKSDL_ANDROID_H #include "../ijksdl.h" #include "ijksdl_aout_android_audiotrack.h" #include "ijksdl_aout_android_opensles.h" #include "ijksdl_vout_android_nativewindow.h" #include "ijksdl_vout_android_surface.h" #endif ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_android_jni.c ================================================ /***************************************************************************** * ijksdl_android.c ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_android_jni.h" #include #include "j4a/class/android/os/Build.h" #include "ijksdl_inc_internal_android.h" #include "ijksdl_codec_android_mediaformat_java.h" #include "ijksdl_codec_android_mediacodec_java.h" static JavaVM *g_jvm; static pthread_key_t g_thread_key; static pthread_once_t g_key_once = PTHREAD_ONCE_INIT; JavaVM *SDL_JNI_GetJvm() { return g_jvm; } static void SDL_JNI_ThreadDestroyed(void* value) { JNIEnv *env = (JNIEnv*) value; if (env != NULL) { ALOGE("%s: [%d] didn't call SDL_JNI_DetachThreadEnv() explicity\n", __func__, (int)gettid()); (*g_jvm)->DetachCurrentThread(g_jvm); pthread_setspecific(g_thread_key, NULL); } } static void make_thread_key() { pthread_key_create(&g_thread_key, SDL_JNI_ThreadDestroyed); } jint SDL_JNI_SetupThreadEnv(JNIEnv **p_env) { JavaVM *jvm = g_jvm; if (!jvm) { ALOGE("SDL_JNI_GetJvm: AttachCurrentThread: NULL jvm"); return -1; } pthread_once(&g_key_once, make_thread_key); JNIEnv *env = (JNIEnv*) pthread_getspecific(g_thread_key); if (env) { *p_env = env; return 0; } if ((*jvm)->AttachCurrentThread(jvm, &env, NULL) == JNI_OK) { pthread_setspecific(g_thread_key, env); *p_env = env; return 0; } return -1; } void SDL_JNI_DetachThreadEnv() { JavaVM *jvm = g_jvm; ALOGI("%s: [%d]\n", __func__, (int)gettid()); pthread_once(&g_key_once, make_thread_key); JNIEnv *env = pthread_getspecific(g_thread_key); if (!env) return; pthread_setspecific(g_thread_key, NULL); if ((*jvm)->DetachCurrentThread(jvm) == JNI_OK) return; return; } int SDL_JNI_ThrowException(JNIEnv* env, const char* className, const char* msg) { if ((*env)->ExceptionCheck(env)) { jthrowable exception = (*env)->ExceptionOccurred(env); (*env)->ExceptionClear(env); if (exception != NULL) { ALOGW("Discarding pending exception (%s) to throw", className); (*env)->DeleteLocalRef(env, exception); } } jclass exceptionClass = (*env)->FindClass(env, className); if (exceptionClass == NULL) { ALOGE("Unable to find exception class %s", className); /* ClassNotFoundException now pending */ goto fail; } if ((*env)->ThrowNew(env, exceptionClass, msg) != JNI_OK) { ALOGE("Failed throwing '%s' '%s'", className, msg); /* an exception, most likely OOM, will now be pending */ goto fail; } return 0; fail: if (exceptionClass) (*env)->DeleteLocalRef(env, exceptionClass); return -1; } int SDL_JNI_ThrowIllegalStateException(JNIEnv *env, const char* msg) { return SDL_JNI_ThrowException(env, "java/lang/IllegalStateException", msg); } jobject SDL_JNI_NewObjectAsGlobalRef(JNIEnv *env, jclass clazz, jmethodID methodID, ...) { va_list args; va_start(args, methodID); jobject global_object = NULL; jobject local_object = (*env)->NewObjectV(env, clazz, methodID, args); if (!J4A_ExceptionCheck__throwAny(env) && local_object) { global_object = (*env)->NewGlobalRef(env, local_object); SDL_JNI_DeleteLocalRefP(env, &local_object); } va_end(args); return global_object; } void SDL_JNI_DeleteGlobalRefP(JNIEnv *env, jobject *obj_ptr) { if (!obj_ptr || !*obj_ptr) return; (*env)->DeleteGlobalRef(env, *obj_ptr); *obj_ptr = NULL; } void SDL_JNI_DeleteLocalRefP(JNIEnv *env, jobject *obj_ptr) { if (!obj_ptr || !*obj_ptr) return; (*env)->DeleteLocalRef(env, *obj_ptr); *obj_ptr = NULL; } int SDL_Android_GetApiLevel() { static int SDK_INT = 0; if (SDK_INT > 0) return SDK_INT; JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("SDL_Android_GetApiLevel: SetupThreadEnv failed"); return 0; } SDK_INT = J4AC_android_os_Build__VERSION__SDK_INT__get__catchAll(env); ALOGI("API-Level: %d\n", SDK_INT); return SDK_INT; #if 0 char value[PROP_VALUE_MAX]; memset(value, 0, sizeof(value)); __system_property_get("ro.build.version.sdk", value); SDK_INT = atoi(value); return SDK_INT; #endif } JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { int retval; JNIEnv* env = NULL; g_jvm = vm; if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) { return -1; } retval = J4A_LoadAll__catchAll(env); JNI_CHECK_RET(retval == 0, env, NULL, NULL, -1); return JNI_VERSION_1_4; } JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *jvm, void *reserved) { } ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_android_jni.h ================================================ /***************************************************************************** * ijksdl_android_jni.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_ANDROID__IJKSDL_ANDROID_JNI_H #define IJKSDL_ANDROID__IJKSDL_ANDROID_JNI_H #include #include "j4a/j4a_base.h" #include "j4a/j4a_allclasses.h" #define IJK_API_1_BASE 1 // 1.0 #define IJK_API_2_BASE_1_1 2 // 1.1 #define IJK_API_3_CUPCAKE 3 // 1.5 #define IJK_API_4_DONUT 4 // 1.6 #define IJK_API_5_ECLAIR 5 // 2.0 #define IJK_API_6_ECLAIR_0_1 6 // 2.0.1 #define IJK_API_7_ECLAIR_MR1 7 // 2.1 #define IJK_API_8_FROYO 8 // 2.2 #define IJK_API_9_GINGERBREAD 9 // 2.3 #define IJK_API_10_GINGERBREAD_MR1 10 // 2.3.3 #define IJK_API_11_HONEYCOMB 11 // 3.0 #define IJK_API_12_HONEYCOMB_MR1 12 // 3.1 #define IJK_API_13_HONEYCOMB_MR2 13 // 3.2 #define IJK_API_14_ICE_CREAM_SANDWICH 14 // 4.0 #define IJK_API_15_ICE_CREAM_SANDWICH_MR1 15 // 4.0.3 #define IJK_API_16_JELLY_BEAN 16 // 4.1 #define IJK_API_17_JELLY_BEAN_MR1 17 // 4.2 #define IJK_API_18_JELLY_BEAN_MR2 18 // 4.3 #define IJK_API_19_KITKAT 19 // 4.4 #define IJK_API_20_KITKAT_WATCH 20 // 4.4W #define IJK_API_21_LOLLIPOP 21 // 5.0 #define IJK_API_22_LOLLIPOP_MR1 22 // 5.1 #define IJK_API_23_M 23 // 6.0 JavaVM *SDL_JNI_GetJvm(); jint SDL_JNI_SetupThreadEnv(JNIEnv **p_env); void SDL_JNI_DetachThreadEnv(); int SDL_JNI_ThrowException(JNIEnv *env, const char *exception, const char* msg); int SDL_JNI_ThrowIllegalStateException(JNIEnv *env, const char* msg); jobject SDL_JNI_NewObjectAsGlobalRef(JNIEnv *env, jclass clazz, jmethodID methodID, ...); void SDL_JNI_DeleteGlobalRefP(JNIEnv *env, jobject *obj_ptr); void SDL_JNI_DeleteLocalRefP(JNIEnv *env, jobject *obj_ptr); int SDL_Android_GetApiLevel(); #define IJK_FIND_JAVA_CLASS(env__, var__, classsign__) \ do { \ jclass clazz = (*env__)->FindClass(env__, classsign__); \ if (J4A_ExceptionCheck__catchAll(env) || !(clazz)) { \ ALOGE("FindClass failed: %s", classsign__); \ return -1; \ } \ var__ = (*env__)->NewGlobalRef(env__, clazz); \ if (J4A_ExceptionCheck__catchAll(env) || !(var__)) { \ ALOGE("FindClass::NewGlobalRef failed: %s", classsign__); \ (*env__)->DeleteLocalRef(env__, clazz); \ return -1; \ } \ (*env__)->DeleteLocalRef(env__, clazz); \ } while(0); #define JNI_CHECK_GOTO(condition__, env__, exception__, msg__, label__) \ do { \ if (!(condition__)) { \ if (exception__) { \ SDL_JNI_ThrowException(env__, exception__, msg__); \ } \ goto label__; \ } \ }while(0) #define JNI_CHECK_RET_VOID(condition__, env__, exception__, msg__) \ do { \ if (!(condition__)) { \ if (exception__) { \ SDL_JNI_ThrowException(env__, exception__, msg__); \ } \ return; \ } \ }while(0) #define JNI_CHECK_RET(condition__, env__, exception__, msg__, ret__) \ do { \ if (!(condition__)) { \ if (exception__) { \ SDL_JNI_ThrowException(env__, exception__, msg__); \ } \ return ret__; \ } \ }while(0) #endif ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_aout_android_audiotrack.c ================================================ /***************************************************************************** * ijksdl_aout_android_audiotrack.c ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_aout_android_audiotrack.h" #include #include #include #include "../ijksdl_inc_internal.h" #include "../ijksdl_thread.h" #include "../ijksdl_aout_internal.h" #include "ijksdl_android_jni.h" #include "android_audiotrack.h" #ifdef SDLTRACE #undef SDLTRACE #define SDLTRACE(...) //#define SDLTRACE ALOGE #endif static SDL_Class g_audiotrack_class = { .name = "AudioTrack", }; typedef struct SDL_Aout_Opaque { SDL_cond *wakeup_cond; SDL_mutex *wakeup_mutex; SDL_AudioSpec spec; SDL_Android_AudioTrack* atrack; uint8_t *buffer; int buffer_size; volatile bool need_flush; volatile bool pause_on; volatile bool abort_request; volatile bool need_set_volume; volatile float left_volume; volatile float right_volume; SDL_Thread *audio_tid; SDL_Thread _audio_tid; int audio_session_id; volatile float speed; volatile bool speed_changed; } SDL_Aout_Opaque; static int aout_thread_n(JNIEnv *env, SDL_Aout *aout) { SDL_Aout_Opaque *opaque = aout->opaque; SDL_Android_AudioTrack *atrack = opaque->atrack; SDL_AudioCallback audio_cblk = opaque->spec.callback; void *userdata = opaque->spec.userdata; uint8_t *buffer = opaque->buffer; int copy_size = 256; assert(atrack); assert(buffer); SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH); if (!opaque->abort_request && !opaque->pause_on) SDL_Android_AudioTrack_play(env, atrack); while (!opaque->abort_request) { SDL_LockMutex(opaque->wakeup_mutex); if (!opaque->abort_request && opaque->pause_on) { SDL_Android_AudioTrack_pause(env, atrack); while (!opaque->abort_request && opaque->pause_on) { SDL_CondWaitTimeout(opaque->wakeup_cond, opaque->wakeup_mutex, 1000); } if (!opaque->abort_request && !opaque->pause_on) { if (opaque->need_flush) { opaque->need_flush = 0; SDL_Android_AudioTrack_flush(env, atrack); } SDL_Android_AudioTrack_play(env, atrack); } } if (opaque->need_flush) { opaque->need_flush = 0; SDL_Android_AudioTrack_flush(env, atrack); } if (opaque->need_set_volume) { opaque->need_set_volume = 0; SDL_Android_AudioTrack_set_volume(env, atrack, opaque->left_volume, opaque->right_volume); } if (opaque->speed_changed) { opaque->speed_changed = 0; SDL_Android_AudioTrack_setSpeed(env, atrack, opaque->speed); } SDL_UnlockMutex(opaque->wakeup_mutex); audio_cblk(userdata, buffer, copy_size); if (opaque->need_flush) { SDL_Android_AudioTrack_flush(env, atrack); opaque->need_flush = false; } if (opaque->need_flush) { opaque->need_flush = 0; SDL_Android_AudioTrack_flush(env, atrack); } else { int written = SDL_Android_AudioTrack_write(env, atrack, buffer, copy_size); if (written != copy_size) { ALOGW("AudioTrack: not all data copied %d/%d", (int)written, (int)copy_size); } } // TODO: 1 if callback return -1 or 0 } SDL_Android_AudioTrack_free(env, atrack); return 0; } static int aout_thread(void *arg) { SDL_Aout *aout = arg; // SDL_Aout_Opaque *opaque = aout->opaque; JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("aout_thread: SDL_AndroidJni_SetupEnv: failed"); return -1; } return aout_thread_n(env, aout); } static int aout_open_audio_n(JNIEnv *env, SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained) { assert(desired); SDL_Aout_Opaque *opaque = aout->opaque; opaque->spec = *desired; opaque->atrack = SDL_Android_AudioTrack_new_from_sdl_spec(env, desired); if (!opaque->atrack) { ALOGE("aout_open_audio_n: failed to new AudioTrcak()"); return -1; } opaque->buffer_size = SDL_Android_AudioTrack_get_min_buffer_size(opaque->atrack); if (opaque->buffer_size <= 0) { ALOGE("aout_open_audio_n: failed to getMinBufferSize()"); SDL_Android_AudioTrack_free(env, opaque->atrack); opaque->atrack = NULL; return -1; } opaque->buffer = malloc(opaque->buffer_size); if (!opaque->buffer) { ALOGE("aout_open_audio_n: failed to allocate buffer"); SDL_Android_AudioTrack_free(env, opaque->atrack); opaque->atrack = NULL; return -1; } if (obtained) { SDL_Android_AudioTrack_get_target_spec(opaque->atrack, obtained); SDLTRACE("audio target format fmt:0x%x, channel:0x%x", (int)obtained->format, (int)obtained->channels); } opaque->audio_session_id = SDL_Android_AudioTrack_getAudioSessionId(env, opaque->atrack); ALOGI("audio_session_id = %d\n", opaque->audio_session_id); opaque->pause_on = 1; opaque->abort_request = 0; opaque->audio_tid = SDL_CreateThreadEx(&opaque->_audio_tid, aout_thread, aout, "ff_aout_android"); if (!opaque->audio_tid) { ALOGE("aout_open_audio_n: failed to create audio thread"); SDL_Android_AudioTrack_free(env, opaque->atrack); opaque->atrack = NULL; return -1; } return 0; } static int aout_open_audio(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained) { // SDL_Aout_Opaque *opaque = aout->opaque; JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("aout_open_audio: AttachCurrentThread: failed"); return -1; } return aout_open_audio_n(env, aout, desired, obtained); } static void aout_pause_audio(SDL_Aout *aout, int pause_on) { SDL_Aout_Opaque *opaque = aout->opaque; SDL_LockMutex(opaque->wakeup_mutex); SDLTRACE("aout_pause_audio(%d)", pause_on); opaque->pause_on = pause_on; if (!pause_on) SDL_CondSignal(opaque->wakeup_cond); SDL_UnlockMutex(opaque->wakeup_mutex); } static void aout_flush_audio(SDL_Aout *aout) { SDL_Aout_Opaque *opaque = aout->opaque; SDL_LockMutex(opaque->wakeup_mutex); SDLTRACE("aout_flush_audio()"); opaque->need_flush = 1; SDL_CondSignal(opaque->wakeup_cond); SDL_UnlockMutex(opaque->wakeup_mutex); } static void aout_set_volume(SDL_Aout *aout, float left_volume, float right_volume) { SDL_Aout_Opaque *opaque = aout->opaque; SDL_LockMutex(opaque->wakeup_mutex); SDLTRACE("aout_flush_audio()"); opaque->left_volume = left_volume; opaque->right_volume = right_volume; opaque->need_set_volume = 1; SDL_CondSignal(opaque->wakeup_cond); SDL_UnlockMutex(opaque->wakeup_mutex); } static void aout_close_audio(SDL_Aout *aout) { SDL_Aout_Opaque *opaque = aout->opaque; SDL_LockMutex(opaque->wakeup_mutex); opaque->abort_request = true; SDL_CondSignal(opaque->wakeup_cond); SDL_UnlockMutex(opaque->wakeup_mutex); SDL_WaitThread(opaque->audio_tid, NULL); opaque->audio_tid = NULL; } static int aout_get_audio_session_id(SDL_Aout *aout) { SDL_Aout_Opaque *opaque = aout->opaque; return opaque->audio_session_id; } static void aout_free_l(SDL_Aout *aout) { if (!aout) return; aout_close_audio(aout); SDL_Aout_Opaque *opaque = aout->opaque; if (opaque) { free(opaque->buffer); opaque->buffer = NULL; opaque->buffer_size = 0; SDL_DestroyCond(opaque->wakeup_cond); SDL_DestroyMutex(opaque->wakeup_mutex); } SDL_Aout_FreeInternal(aout); } static void func_set_playback_rate(SDL_Aout *aout, float speed) { if (!aout) return; SDL_Aout_Opaque *opaque = aout->opaque; SDL_LockMutex(opaque->wakeup_mutex); SDLTRACE("%s %f", __func__, (double)speed); opaque->speed = speed; opaque->speed_changed = 1; SDL_CondSignal(opaque->wakeup_cond); SDL_UnlockMutex(opaque->wakeup_mutex); } SDL_Aout *SDL_AoutAndroid_CreateForAudioTrack() { SDL_Aout *aout = SDL_Aout_CreateInternal(sizeof(SDL_Aout_Opaque)); if (!aout) return NULL; SDL_Aout_Opaque *opaque = aout->opaque; opaque->wakeup_cond = SDL_CreateCond(); opaque->wakeup_mutex = SDL_CreateMutex(); opaque->speed = 1.0f; aout->opaque_class = &g_audiotrack_class; aout->free_l = aout_free_l; aout->open_audio = aout_open_audio; aout->pause_audio = aout_pause_audio; aout->flush_audio = aout_flush_audio; aout->set_volume = aout_set_volume; aout->close_audio = aout_close_audio; aout->func_get_audio_session_id = aout_get_audio_session_id; aout->func_set_playback_rate = func_set_playback_rate; return aout; } bool SDL_AoutAndroid_IsObjectOfAudioTrack(SDL_Aout *aout) { if (aout) return false; return aout->opaque_class == &g_audiotrack_class; } void SDL_Init_AoutAndroid(JNIEnv *env) { } ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_aout_android_audiotrack.h ================================================ /***************************************************************************** * ijksdl_aout_android_audiotrack.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_ANDROID__IJKSDL_AOUT_ANDROID_AUDIOTRACK_H #define IJKSDL_ANDROID__IJKSDL_AOUT_ANDROID_AUDIOTRACK_H #include "../ijksdl_aout.h" SDL_Aout *SDL_AoutAndroid_CreateForAudioTrack(); bool SDL_AoutAndroid_IsObjectOfAudioTrack(SDL_Aout *aout); #endif ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_aout_android_opensles.c ================================================ /***************************************************************************** * ijksdl_aout_android_opensles.c ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; 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 "../ijksdl_inc_internal.h" #include "../ijksdl_thread.h" #include "../ijksdl_aout_internal.h" #include "ijksdl_android_jni.h" #include "android_audiotrack.h" #ifdef SDLTRACE #undef SDLTRACE #define SDLTRACE(...) //#define SDLTRACE ALOGW #endif #define OPENSLES_BUFFERS 255 /* maximum number of buffers */ #define OPENSLES_BUFLEN 10 /* ms */ static SDL_Class g_opensles_class = { .name = "OpenSLES", }; typedef struct SDL_Aout_Opaque { SDL_cond *wakeup_cond; SDL_mutex *wakeup_mutex; SDL_Thread *audio_tid; SDL_Thread _audio_tid; SDL_AudioSpec spec; SLDataFormat_PCM format_pcm; int bytes_per_frame; int milli_per_buffer; int frames_per_buffer; int bytes_per_buffer; SLObjectItf slObject; SLEngineItf slEngine; SLObjectItf slOutputMixObject; SLObjectItf slPlayerObject; SLAndroidSimpleBufferQueueItf slBufferQueueItf; SLVolumeItf slVolumeItf; SLPlayItf slPlayItf; volatile bool need_set_volume; volatile float left_volume; volatile float right_volume; volatile bool abort_request; volatile bool pause_on; volatile bool need_flush; volatile bool is_running; uint8_t *buffer; size_t buffer_capacity; } SDL_Aout_Opaque; #define CHECK_OPENSL_ERROR(ret__, ...) \ do { \ if ((ret__) != SL_RESULT_SUCCESS) \ { \ ALOGE(__VA_ARGS__); \ goto fail; \ } \ } while (0) #define CHECK_COND_ERROR(cond__, ...) \ do { \ if (!(cond__)) \ { \ ALOGE(__VA_ARGS__); \ goto fail; \ } \ } while (0) static inline SLmillibel android_amplification_to_sles(float volumeLevel) { // FIXME use the FX Framework conversions if (volumeLevel < 0.00000001) return SL_MILLIBEL_MIN; SLmillibel mb = lroundf(2000.f * log10f(volumeLevel)); if (mb < SL_MILLIBEL_MIN) mb = SL_MILLIBEL_MIN; else if (mb > 0) mb = 0; /* maximum supported level could be higher: GetMaxVolumeLevel */ return mb; } static int aout_thread_n(SDL_Aout *aout) { SDL_Aout_Opaque *opaque = aout->opaque; SLPlayItf slPlayItf = opaque->slPlayItf; SLAndroidSimpleBufferQueueItf slBufferQueueItf = opaque->slBufferQueueItf; SLVolumeItf slVolumeItf = opaque->slVolumeItf; SDL_AudioCallback audio_cblk = opaque->spec.callback; void *userdata = opaque->spec.userdata; uint8_t *next_buffer = NULL; int next_buffer_index = 0; size_t bytes_per_buffer = opaque->bytes_per_buffer; SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH); if (!opaque->abort_request && !opaque->pause_on) (*slPlayItf)->SetPlayState(slPlayItf, SL_PLAYSTATE_PLAYING); while (!opaque->abort_request) { SLAndroidSimpleBufferQueueState slState = {0}; SLresult slRet = (*slBufferQueueItf)->GetState(slBufferQueueItf, &slState); if (slRet != SL_RESULT_SUCCESS) { ALOGE("%s: slBufferQueueItf->GetState() failed\n", __func__); SDL_UnlockMutex(opaque->wakeup_mutex); } SDL_LockMutex(opaque->wakeup_mutex); if (!opaque->abort_request && (opaque->pause_on || slState.count >= OPENSLES_BUFFERS)) { while (!opaque->abort_request && (opaque->pause_on || slState.count >= OPENSLES_BUFFERS)) { if (!opaque->pause_on) { (*slPlayItf)->SetPlayState(slPlayItf, SL_PLAYSTATE_PLAYING); } SDL_CondWaitTimeout(opaque->wakeup_cond, opaque->wakeup_mutex, 1000); SLresult slRet = (*slBufferQueueItf)->GetState(slBufferQueueItf, &slState); if (slRet != SL_RESULT_SUCCESS) { ALOGE("%s: slBufferQueueItf->GetState() failed\n", __func__); SDL_UnlockMutex(opaque->wakeup_mutex); } if (opaque->pause_on) (*slPlayItf)->SetPlayState(slPlayItf, SL_PLAYSTATE_PAUSED); } if (!opaque->abort_request && !opaque->pause_on) { (*slPlayItf)->SetPlayState(slPlayItf, SL_PLAYSTATE_PLAYING); } } if (opaque->need_flush) { opaque->need_flush = 0; (*slBufferQueueItf)->Clear(slBufferQueueItf); } #if 0 if (opaque->need_set_volume) { opaque->need_set_volume = 0; // FIXME: set volume here } #endif if (opaque->need_set_volume) { opaque->need_set_volume = 0; SLmillibel level = android_amplification_to_sles((opaque->left_volume + opaque->right_volume) / 2); ALOGI("slVolumeItf->SetVolumeLevel((%f, %f) -> %d)\n", opaque->left_volume, opaque->right_volume, (int)level); slRet = (*slVolumeItf)->SetVolumeLevel(slVolumeItf, level); if (slRet != SL_RESULT_SUCCESS) { ALOGE("slVolumeItf->SetVolumeLevel failed %d\n", (int)slRet); // just ignore error } } SDL_UnlockMutex(opaque->wakeup_mutex); next_buffer = opaque->buffer + next_buffer_index * bytes_per_buffer; next_buffer_index = (next_buffer_index + 1) % OPENSLES_BUFFERS; audio_cblk(userdata, next_buffer, bytes_per_buffer); if (opaque->need_flush) { (*slBufferQueueItf)->Clear(slBufferQueueItf); opaque->need_flush = false; } if (opaque->need_flush) { ALOGE("flush"); opaque->need_flush = 0; (*slBufferQueueItf)->Clear(slBufferQueueItf); } else { slRet = (*slBufferQueueItf)->Enqueue(slBufferQueueItf, next_buffer, bytes_per_buffer); if (slRet == SL_RESULT_SUCCESS) { // do nothing } else if (slRet == SL_RESULT_BUFFER_INSUFFICIENT) { // don't retry, just pass through ALOGE("SL_RESULT_BUFFER_INSUFFICIENT\n"); } else { ALOGE("slBufferQueueItf->Enqueue() = %d\n", (int)slRet); break; } } // TODO: 1 if callback return -1 or 0 } return 0; } static int aout_thread(void *arg) { return aout_thread_n(arg); } static void aout_opensles_callback(SLAndroidSimpleBufferQueueItf caller, void *pContext) { SDLTRACE("%s\n", __func__); SDL_Aout *aout = pContext; SDL_Aout_Opaque *opaque = aout->opaque; if (opaque) { SDL_LockMutex(opaque->wakeup_mutex); opaque->is_running = true; SDL_CondSignal(opaque->wakeup_cond); SDL_UnlockMutex(opaque->wakeup_mutex); } } static void aout_close_audio(SDL_Aout *aout) { SDLTRACE("aout_close_audio()\n"); SDL_Aout_Opaque *opaque = aout->opaque; if (!opaque) return; SDL_LockMutex(opaque->wakeup_mutex); opaque->abort_request = true; SDL_CondSignal(opaque->wakeup_cond); SDL_UnlockMutex(opaque->wakeup_mutex); SDL_WaitThread(opaque->audio_tid, NULL); opaque->audio_tid = NULL; if (opaque->slPlayItf) (*opaque->slPlayItf)->SetPlayState(opaque->slPlayItf, SL_PLAYSTATE_STOPPED); if (opaque->slBufferQueueItf) (*opaque->slBufferQueueItf)->Clear(opaque->slBufferQueueItf); if (opaque->slBufferQueueItf) opaque->slBufferQueueItf = NULL; if (opaque->slVolumeItf) opaque->slVolumeItf = NULL; if (opaque->slPlayItf) opaque->slPlayItf = NULL; if (opaque->slPlayerObject) { (*opaque->slPlayerObject)->Destroy(opaque->slPlayerObject); opaque->slPlayerObject = NULL; } freep((void **)&opaque->buffer); } static void aout_free_l(SDL_Aout *aout) { SDLTRACE("%s\n", __func__); if (!aout) return; aout_close_audio(aout); SDL_Aout_Opaque *opaque = aout->opaque; if (opaque->slOutputMixObject) { (*opaque->slOutputMixObject)->Destroy(opaque->slOutputMixObject); opaque->slOutputMixObject = NULL; } opaque->slEngine = NULL; if (opaque->slObject) { (*opaque->slObject)->Destroy(opaque->slObject); opaque->slObject = NULL; } SDL_DestroyCondP(&opaque->wakeup_cond); SDL_DestroyMutexP(&opaque->wakeup_mutex); SDL_Aout_FreeInternal(aout); } static int aout_open_audio(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained) { SDLTRACE("%s\n", __func__); assert(desired); SDLTRACE("aout_open_audio()\n"); SDL_Aout_Opaque *opaque = aout->opaque; SLEngineItf slEngine = opaque->slEngine; SLDataFormat_PCM *format_pcm = &opaque->format_pcm; int ret = 0; opaque->spec = *desired; // config audio src SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, OPENSLES_BUFFERS }; int native_sample_rate = audiotrack_get_native_output_sample_rate(NULL); ALOGI("OpenSL-ES: native sample rate %d Hz\n", native_sample_rate); CHECK_COND_ERROR((desired->format == AUDIO_S16SYS), "%s: not AUDIO_S16SYS", __func__); CHECK_COND_ERROR((desired->channels == 2 || desired->channels == 1), "%s: not 1,2 channel", __func__); CHECK_COND_ERROR((desired->freq >= 8000 && desired->freq <= 48000), "%s: unsupport freq %d Hz", __func__, desired->freq); if (SDL_Android_GetApiLevel() < IJK_API_21_LOLLIPOP && native_sample_rate > 0 && desired->freq < native_sample_rate) { // Don't try to play back a sample rate higher than the native one, // since OpenSL ES will try to use the fast path, which AudioFlinger // will reject (fast path can't do resampling), and will end up with // too small buffers for the resampling. See http://b.android.com/59453 // for details. This bug is still present in 4.4. If it is fixed later // this workaround could be made conditional. // // by VLC/android_opensles.c ALOGW("OpenSL-ES: force resample %lu to native sample rate %d\n", (unsigned long) format_pcm->samplesPerSec / 1000, (int) native_sample_rate); format_pcm->samplesPerSec = native_sample_rate * 1000; } format_pcm->formatType = SL_DATAFORMAT_PCM; format_pcm->numChannels = desired->channels; format_pcm->samplesPerSec = desired->freq * 1000; // milli Hz // format_pcm->numChannels = 2; // format_pcm->samplesPerSec = SL_SAMPLINGRATE_44_1; format_pcm->bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; format_pcm->containerSize = SL_PCMSAMPLEFORMAT_FIXED_16; switch (desired->channels) { case 2: format_pcm->channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; break; case 1: format_pcm->channelMask = SL_SPEAKER_FRONT_CENTER; break; default: ALOGE("%s, invalid channel %d", __func__, desired->channels); goto fail; } format_pcm->endianness = SL_BYTEORDER_LITTLEENDIAN; SLDataSource audio_source = {&loc_bufq, format_pcm}; // config audio sink SLDataLocator_OutputMix loc_outmix = { SL_DATALOCATOR_OUTPUTMIX, opaque->slOutputMixObject }; SLDataSink audio_sink = {&loc_outmix, NULL}; SLObjectItf slPlayerObject = NULL; const SLInterfaceID ids2[] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_VOLUME, SL_IID_PLAY }; static const SLboolean req2[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE }; ret = (*slEngine)->CreateAudioPlayer(slEngine, &slPlayerObject, &audio_source, &audio_sink, sizeof(ids2) / sizeof(*ids2), ids2, req2); CHECK_OPENSL_ERROR(ret, "%s: slEngine->CreateAudioPlayer() failed", __func__); opaque->slPlayerObject = slPlayerObject; ret = (*slPlayerObject)->Realize(slPlayerObject, SL_BOOLEAN_FALSE); CHECK_OPENSL_ERROR(ret, "%s: slPlayerObject->Realize() failed", __func__); ret = (*slPlayerObject)->GetInterface(slPlayerObject, SL_IID_PLAY, &opaque->slPlayItf); CHECK_OPENSL_ERROR(ret, "%s: slPlayerObject->GetInterface(SL_IID_PLAY) failed", __func__); ret = (*slPlayerObject)->GetInterface(slPlayerObject, SL_IID_VOLUME, &opaque->slVolumeItf); CHECK_OPENSL_ERROR(ret, "%s: slPlayerObject->GetInterface(SL_IID_VOLUME) failed", __func__); ret = (*slPlayerObject)->GetInterface(slPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &opaque->slBufferQueueItf); CHECK_OPENSL_ERROR(ret, "%s: slPlayerObject->GetInterface(SL_IID_ANDROIDSIMPLEBUFFERQUEUE) failed", __func__); ret = (*opaque->slBufferQueueItf)->RegisterCallback(opaque->slBufferQueueItf, aout_opensles_callback, (void*)aout); CHECK_OPENSL_ERROR(ret, "%s: slBufferQueueItf->RegisterCallback() failed", __func__); // set the player's state to playing // ret = (*opaque->slPlayItf)->SetPlayState(opaque->slPlayItf, SL_PLAYSTATE_PLAYING); // CHECK_OPENSL_ERROR(ret, "%s: slBufferQueueItf->slPlayItf() failed", __func__); opaque->bytes_per_frame = format_pcm->numChannels * format_pcm->bitsPerSample / 8; opaque->milli_per_buffer = OPENSLES_BUFLEN; opaque->frames_per_buffer = opaque->milli_per_buffer * format_pcm->samplesPerSec / 1000000; // samplesPerSec is in milli opaque->bytes_per_buffer = opaque->bytes_per_frame * opaque->frames_per_buffer; opaque->buffer_capacity = OPENSLES_BUFFERS * opaque->bytes_per_buffer; ALOGI("OpenSL-ES: bytes_per_frame = %d bytes\n", (int)opaque->bytes_per_frame); ALOGI("OpenSL-ES: milli_per_buffer = %d ms\n", (int)opaque->milli_per_buffer); ALOGI("OpenSL-ES: frame_per_buffer = %d frames\n", (int)opaque->frames_per_buffer); ALOGI("OpenSL-ES: bytes_per_buffer = %d bytes\n", (int)opaque->bytes_per_buffer); ALOGI("OpenSL-ES: buffer_capacity = %d bytes\n", (int)opaque->buffer_capacity); opaque->buffer = malloc(opaque->buffer_capacity); CHECK_COND_ERROR(opaque->buffer, "%s: failed to alloc buffer %d\n", __func__, (int)opaque->buffer_capacity); // (*opaque->slPlayItf)->SetPositionUpdatePeriod(opaque->slPlayItf, 1000); // enqueue empty buffer to start play memset(opaque->buffer, 0, opaque->buffer_capacity); for(int i = 0; i < OPENSLES_BUFFERS; ++i) { ret = (*opaque->slBufferQueueItf)->Enqueue(opaque->slBufferQueueItf, opaque->buffer + i * opaque->bytes_per_buffer, opaque->bytes_per_buffer); CHECK_OPENSL_ERROR(ret, "%s: slBufferQueueItf->Enqueue(000...) failed", __func__); } opaque->pause_on = 1; opaque->abort_request = 0; opaque->audio_tid = SDL_CreateThreadEx(&opaque->_audio_tid, aout_thread, aout, "ff_aout_opensles"); CHECK_COND_ERROR(opaque->audio_tid, "%s: failed to SDL_CreateThreadEx", __func__); if (obtained) { *obtained = *desired; obtained->size = opaque->buffer_capacity; obtained->freq = format_pcm->samplesPerSec / 1000; } return opaque->buffer_capacity; fail: aout_close_audio(aout); return -1; } static void aout_pause_audio(SDL_Aout *aout, int pause_on) { SDL_Aout_Opaque *opaque = aout->opaque; SDL_LockMutex(opaque->wakeup_mutex); SDLTRACE("aout_pause_audio(%d)", pause_on); opaque->pause_on = pause_on; if (!pause_on) SDL_CondSignal(opaque->wakeup_cond); SDL_UnlockMutex(opaque->wakeup_mutex); } static void aout_flush_audio(SDL_Aout *aout) { SDL_Aout_Opaque *opaque = aout->opaque; SDL_LockMutex(opaque->wakeup_mutex); SDLTRACE("aout_flush_audio()"); opaque->need_flush = 1; SDL_CondSignal(opaque->wakeup_cond); SDL_UnlockMutex(opaque->wakeup_mutex); } static void aout_set_volume(SDL_Aout *aout, float left_volume, float right_volume) { SDL_Aout_Opaque *opaque = aout->opaque; SDL_LockMutex(opaque->wakeup_mutex); ALOGI("aout_set_volume(%f, %f)", left_volume, right_volume); opaque->left_volume = left_volume; opaque->right_volume = right_volume; opaque->need_set_volume = 1; SDL_CondSignal(opaque->wakeup_cond); SDL_UnlockMutex(opaque->wakeup_mutex); } static double aout_get_latency_seconds(SDL_Aout *aout) { SDL_Aout_Opaque *opaque = aout->opaque; SLAndroidSimpleBufferQueueState state = {0}; SLresult slRet = (*opaque->slBufferQueueItf)->GetState(opaque->slBufferQueueItf, &state); if (slRet != SL_RESULT_SUCCESS) { ALOGE("%s failed\n", __func__); return ((double)opaque->milli_per_buffer) * OPENSLES_BUFFERS / 1000; } // assume there is always a buffer in coping double latency = ((double)opaque->milli_per_buffer) * state.count / 1000; return latency; } SDL_Aout *SDL_AoutAndroid_CreateForOpenSLES() { SDLTRACE("%s\n", __func__); SDL_Aout *aout = SDL_Aout_CreateInternal(sizeof(SDL_Aout_Opaque)); if (!aout) return NULL; SDL_Aout_Opaque *opaque = aout->opaque; opaque->wakeup_cond = SDL_CreateCond(); opaque->wakeup_mutex = SDL_CreateMutex(); int ret = 0; SLObjectItf slObject = NULL; ret = slCreateEngine(&slObject, 0, NULL, 0, NULL, NULL); CHECK_OPENSL_ERROR(ret, "%s: slCreateEngine() failed", __func__); opaque->slObject = slObject; ret = (*slObject)->Realize(slObject, SL_BOOLEAN_FALSE); CHECK_OPENSL_ERROR(ret, "%s: slObject->Realize() failed", __func__); SLEngineItf slEngine = NULL; ret = (*slObject)->GetInterface(slObject, SL_IID_ENGINE, &slEngine); CHECK_OPENSL_ERROR(ret, "%s: slObject->GetInterface() failed", __func__); opaque->slEngine = slEngine; SLObjectItf slOutputMixObject = NULL; const SLInterfaceID ids1[] = {SL_IID_VOLUME}; const SLboolean req1[] = {SL_BOOLEAN_FALSE}; ret = (*slEngine)->CreateOutputMix(slEngine, &slOutputMixObject, 1, ids1, req1); CHECK_OPENSL_ERROR(ret, "%s: slEngine->CreateOutputMix() failed", __func__); opaque->slOutputMixObject = slOutputMixObject; ret = (*slOutputMixObject)->Realize(slOutputMixObject, SL_BOOLEAN_FALSE); CHECK_OPENSL_ERROR(ret, "%s: slOutputMixObject->Realize() failed", __func__); aout->free_l = aout_free_l; aout->opaque_class = &g_opensles_class; aout->open_audio = aout_open_audio; aout->pause_audio = aout_pause_audio; aout->flush_audio = aout_flush_audio; aout->close_audio = aout_close_audio; aout->set_volume = aout_set_volume; aout->func_get_latency_seconds = aout_get_latency_seconds; return aout; fail: aout_free_l(aout); return NULL; } bool SDL_AoutAndroid_IsObjectOfOpenSLES(SDL_Aout *aout) { if (aout) return false; return aout->opaque_class == &g_opensles_class; } ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_aout_android_opensles.h ================================================ /***************************************************************************** * ijksdl_aout_android_opensles.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_ANDROID__IJKSDL_AOUT_ANDROID_OPENSLES_H #define IJKSDL_ANDROID__IJKSDL_AOUT_ANDROID_OPENSLES_H #include "../ijksdl_aout.h" SDL_Aout *SDL_AoutAndroid_CreateForOpenSLES(); bool SDL_AoutAndroid_IsObjectOfOpenSLES(SDL_Aout *aout); #endif ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_codec_android_mediacodec.c ================================================ /***************************************************************************** * ijksdl_codec_android_mediacodec.c ***************************************************************************** * * Copyright (c) 2014 Bilibili * copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_codec_android_mediacodec.h" #include #include "ijksdl/ijksdl_log.h" #include "ijksdl_codec_android_mediacodec_internal.h" static volatile int g_amediacodec_object_serial; typedef struct SDL_AMediaCodec_Common { SDL_AMediaCodec_FakeFifo fake_fifo; } SDL_AMediaCodec_Common; int SDL_AMediaCodec_create_object_serial() { int object_serial = __sync_add_and_fetch(&g_amediacodec_object_serial, 1); if (object_serial == 0) object_serial = __sync_add_and_fetch(&g_amediacodec_object_serial, 1); return object_serial; } // FIXME: release SDL_AMediaCodec sdl_amedia_status_t SDL_AMediaCodec_delete(SDL_AMediaCodec* acodec) { if (!acodec) return SDL_AMEDIA_OK; assert(acodec->func_delete); return acodec->func_delete(acodec); } sdl_amedia_status_t SDL_AMediaCodec_deleteP(SDL_AMediaCodec** acodec) { if (!acodec) return SDL_AMEDIA_OK; sdl_amedia_status_t ret = SDL_AMediaCodec_delete(*acodec); *acodec = NULL; return ret; } sdl_amedia_status_t SDL_AMediaCodec_configure( SDL_AMediaCodec* acodec, const SDL_AMediaFormat* aformat, ANativeWindow* surface, SDL_AMediaCrypto *crypto, uint32_t flags) { assert(acodec->func_configure); sdl_amedia_status_t ret = acodec->func_configure(acodec, aformat, surface, crypto, flags); acodec->is_configured = true; acodec->is_started = false; return ret; } sdl_amedia_status_t SDL_AMediaCodec_configure_surface( JNIEnv*env, SDL_AMediaCodec* acodec, const SDL_AMediaFormat* aformat, jobject android_surface, SDL_AMediaCrypto *crypto, uint32_t flags) { assert(acodec->func_configure_surface); sdl_amedia_status_t ret = acodec->func_configure_surface(env, acodec, aformat, android_surface, crypto, flags); acodec->is_configured = true; acodec->is_started = false; return ret; } void SDL_AMediaCodec_increaseReference(SDL_AMediaCodec *acodec) { assert(acodec); int ref_count = __sync_add_and_fetch(&acodec->ref_count, 1); ALOGD("%s(): ref=%d\n", __func__, ref_count); } void SDL_AMediaCodec_decreaseReference(SDL_AMediaCodec *acodec) { if (!acodec) return; int ref_count = __sync_sub_and_fetch(&acodec->ref_count, 1); ALOGD("%s(): ref=%d\n", __func__, ref_count); if (ref_count == 0) { if (SDL_AMediaCodec_isStarted(acodec)) { SDL_AMediaCodec_stop(acodec); } SDL_AMediaCodec_delete(acodec); } } void SDL_AMediaCodec_decreaseReferenceP(SDL_AMediaCodec **acodec) { if (!acodec) return; SDL_AMediaCodec_decreaseReference(*acodec); *acodec = NULL; } bool SDL_AMediaCodec_isConfigured(SDL_AMediaCodec *acodec) { return acodec->is_configured; } bool SDL_AMediaCodec_isStarted(SDL_AMediaCodec *acodec) { return acodec->is_started; } sdl_amedia_status_t SDL_AMediaCodec_start(SDL_AMediaCodec* acodec) { assert(acodec->func_start); sdl_amedia_status_t amc_ret = acodec->func_start(acodec); if (amc_ret == SDL_AMEDIA_OK) { acodec->is_started = true; } return amc_ret; } sdl_amedia_status_t SDL_AMediaCodec_stop(SDL_AMediaCodec* acodec) { assert(acodec->func_stop); acodec->is_started = false; SDL_AMediaCodec_FakeFifo_abort(&acodec->common->fake_fifo); return acodec->func_stop(acodec); } sdl_amedia_status_t SDL_AMediaCodec_flush(SDL_AMediaCodec* acodec) { assert(acodec->func_flush); SDL_AMediaCodec_FakeFifo_flush(&acodec->common->fake_fifo); return acodec->func_flush(acodec); } ssize_t SDL_AMediaCodec_writeInputData(SDL_AMediaCodec* acodec, size_t idx, const uint8_t *data, size_t size) { assert(acodec->func_writeInputData); return acodec->func_writeInputData(acodec, idx, data, size); } ssize_t SDL_AMediaCodec_dequeueInputBuffer(SDL_AMediaCodec* acodec, int64_t timeoutUs) { assert(acodec->func_dequeueInputBuffer); return acodec->func_dequeueInputBuffer(acodec, timeoutUs); } sdl_amedia_status_t SDL_AMediaCodec_queueInputBuffer(SDL_AMediaCodec* acodec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) { assert(acodec->func_queueInputBuffer); if (flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME) { return SDL_AMediaCodec_FakeFifo_queueInputBuffer(&acodec->common->fake_fifo, idx, offset, size, time, flags); } return acodec->func_queueInputBuffer(acodec, idx, offset, size, time, flags); } ssize_t SDL_AMediaCodec_dequeueOutputBuffer(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs) { assert(acodec->func_dequeueOutputBuffer); return acodec->func_dequeueOutputBuffer(acodec, info, timeoutUs); } SDL_AMediaFormat* SDL_AMediaCodec_getOutputFormat(SDL_AMediaCodec* acodec) { assert(acodec->func_getOutputFormat); return acodec->func_getOutputFormat(acodec); } sdl_amedia_status_t SDL_AMediaCodec_releaseOutputBuffer(SDL_AMediaCodec* acodec, size_t idx, bool render) { assert(acodec->func_releaseOutputBuffer); return acodec->func_releaseOutputBuffer(acodec, idx, render); } bool SDL_AMediaCodec_isInputBuffersValid(SDL_AMediaCodec* acodec) { assert(acodec->func_isInputBuffersValid); return acodec->func_isInputBuffersValid(acodec); } int SDL_AMediaCodec_getSerial(SDL_AMediaCodec* acodec) { if (!acodec) return 0; return acodec->object_serial; } bool SDL_AMediaCodec_isSameSerial(SDL_AMediaCodec* acodec, int acodec_serial) { if (acodec == NULL) return false; return acodec->object_serial == acodec_serial; } SDL_AMediaCodec *SDL_AMediaCodec_CreateInternal(size_t opaque_size) { SDL_AMediaCodec *acodec = (SDL_AMediaCodec*) mallocz(sizeof(SDL_AMediaCodec)); if (!acodec) return NULL; acodec->mutex = SDL_CreateMutex(); if (acodec->mutex == NULL) goto fail; acodec->opaque = mallocz(opaque_size); if (!acodec->opaque) goto fail; acodec->common = mallocz(sizeof(SDL_AMediaCodec_Common)); if (!acodec->common) goto fail; SDL_AMediaCodec_FakeFifo_init(&acodec->common->fake_fifo); return acodec; fail: SDL_AMediaCodec_FreeInternal(acodec); return NULL; } void SDL_AMediaCodec_FreeInternal(SDL_AMediaCodec *acodec) { if (!acodec) return; if (acodec->common) { SDL_AMediaCodec_FakeFifo_destroy(&acodec->common->fake_fifo); free(acodec->common); } free(acodec->opaque); if (acodec->mutex) SDL_DestroyMutexP(&acodec->mutex); memset(acodec, 0, sizeof(SDL_AMediaCodec)); free(acodec); } void SDL_AMediaCodecFake_abort(SDL_AMediaCodec* acodec) { SDL_AMediaCodec_FakeFifo_abort(&acodec->common->fake_fifo); } void SDL_AMediaCodecFake_flushFakeFrames(SDL_AMediaCodec* acodec) { SDL_AMediaCodec_FakeFifo_flush(&acodec->common->fake_fifo); } sdl_amedia_status_t SDL_AMediaCodecFake_queueFakeFrame(SDL_AMediaCodec* acodec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) { return SDL_AMediaCodec_FakeFifo_queueInputBuffer(&acodec->common->fake_fifo, idx, offset, size, time, flags); } ssize_t SDL_AMediaCodecFake_dequeueOutputBuffer(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs) { if (SDL_AMediaCodec_FakeFifo_size(&acodec->common->fake_fifo) > 0) { ssize_t ret = SDL_AMediaCodec_FakeFifo_dequeueOutputBuffer(&acodec->common->fake_fifo, info, 0); if (ret >= 0) return ret; } assert(acodec->func_dequeueOutputBuffer); return acodec->func_dequeueOutputBuffer(acodec, info, timeoutUs); } ssize_t SDL_AMediaCodecFake_dequeueFakeFrameOnly(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs) { return SDL_AMediaCodec_FakeFifo_dequeueOutputBuffer(&acodec->common->fake_fifo, info, 0); } ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_codec_android_mediacodec.h ================================================ /***************************************************************************** * ijksdl_codec_android_mediacodec.h ***************************************************************************** * * Copyright (c) 2014 Bilibili * copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIACODEC_H #define IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIACODEC_H #include "../ijksdl_stdinc.h" #include #include #include #include "../ijksdl_class.h" #include "../ijksdl_mutex.h" #include "ijksdl_codec_android_mediadef.h" #include "android_nativewindow.h" typedef struct SDL_AMediaCodecBufferInfo { int32_t offset; int32_t size; int64_t presentationTimeUs; uint32_t flags; } SDL_AMediaCodecBufferInfo; typedef struct SDL_AMediaFormat SDL_AMediaFormat; typedef struct SDL_AMediaCrypto SDL_AMediaCrypto; typedef struct SDL_AMediaCodec_Common SDL_AMediaCodec_Common; typedef struct SDL_AMediaCodec_Opaque SDL_AMediaCodec_Opaque; typedef struct SDL_AMediaCodec SDL_AMediaCodec; typedef struct SDL_AMediaCodec { SDL_mutex *mutex; volatile int ref_count; SDL_Class *opaque_class; SDL_AMediaCodec_Common *common; SDL_AMediaCodec_Opaque *opaque; bool is_configured; bool is_started; int object_serial; sdl_amedia_status_t (*func_delete)(SDL_AMediaCodec *acodec); sdl_amedia_status_t (*func_configure)( SDL_AMediaCodec* acodec, const SDL_AMediaFormat* aformat, ANativeWindow* surface, SDL_AMediaCrypto *crypto, uint32_t flags); sdl_amedia_status_t (*func_configure_surface)( JNIEnv*env, SDL_AMediaCodec* acodec, const SDL_AMediaFormat* aformat, jobject android_surface, SDL_AMediaCrypto *crypto, uint32_t flags); sdl_amedia_status_t (*func_start)(SDL_AMediaCodec* acodec); sdl_amedia_status_t (*func_stop)(SDL_AMediaCodec* acodec); sdl_amedia_status_t (*func_flush)(SDL_AMediaCodec* acodec); ssize_t (*func_writeInputData)(SDL_AMediaCodec* acodec, size_t idx, const uint8_t *data, size_t size); ssize_t (*func_dequeueInputBuffer)(SDL_AMediaCodec* acodec, int64_t timeoutUs); sdl_amedia_status_t (*func_queueInputBuffer)(SDL_AMediaCodec* acodec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags); ssize_t (*func_dequeueOutputBuffer)(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs); SDL_AMediaFormat* (*func_getOutputFormat)(SDL_AMediaCodec* acodec); sdl_amedia_status_t (*func_releaseOutputBuffer)(SDL_AMediaCodec* acodec, size_t idx, bool render); bool (*func_isInputBuffersValid)(SDL_AMediaCodec* acodec); } SDL_AMediaCodec; int SDL_AMediaCodec_create_object_serial(); sdl_amedia_status_t SDL_AMediaCodec_configure( SDL_AMediaCodec* acodec, const SDL_AMediaFormat* aformat, ANativeWindow* surface, SDL_AMediaCrypto *crypto, uint32_t flags); sdl_amedia_status_t SDL_AMediaCodec_configure_surface( JNIEnv*env, SDL_AMediaCodec* acodec, const SDL_AMediaFormat* aformat, jobject android_surface, SDL_AMediaCrypto *crypto, uint32_t flags); void SDL_AMediaCodec_increaseReference(SDL_AMediaCodec *acodec); void SDL_AMediaCodec_decreaseReference(SDL_AMediaCodec *acodec); void SDL_AMediaCodec_decreaseReferenceP(SDL_AMediaCodec **acodec); bool SDL_AMediaCodec_isConfigured(SDL_AMediaCodec *acodec); bool SDL_AMediaCodec_isStarted(SDL_AMediaCodec *acodec); sdl_amedia_status_t SDL_AMediaCodec_start(SDL_AMediaCodec* acodec); sdl_amedia_status_t SDL_AMediaCodec_stop(SDL_AMediaCodec* acodec); sdl_amedia_status_t SDL_AMediaCodec_flush(SDL_AMediaCodec* acodec); ssize_t SDL_AMediaCodec_writeInputData(SDL_AMediaCodec* acodec, size_t idx, const uint8_t *data, size_t size); ssize_t SDL_AMediaCodec_dequeueInputBuffer(SDL_AMediaCodec* acodec, int64_t timeoutUs); sdl_amedia_status_t SDL_AMediaCodec_queueInputBuffer(SDL_AMediaCodec* acodec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags); ssize_t SDL_AMediaCodec_dequeueOutputBuffer(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs); SDL_AMediaFormat* SDL_AMediaCodec_getOutputFormat(SDL_AMediaCodec* acodec); sdl_amedia_status_t SDL_AMediaCodec_releaseOutputBuffer(SDL_AMediaCodec* acodec, size_t idx, bool render); bool SDL_AMediaCodec_isInputBuffersValid(SDL_AMediaCodec* acodec); int SDL_AMediaCodec_getSerial(SDL_AMediaCodec* acodec); bool SDL_AMediaCodec_isSameSerial(SDL_AMediaCodec* acodec, int acodec_serial); // extended void SDL_AMediaCodecFake_abort(SDL_AMediaCodec* acodec); void SDL_AMediaCodecFake_flushFakeFrames(SDL_AMediaCodec* acodec); sdl_amedia_status_t SDL_AMediaCodecFake_queueFakeFrame(SDL_AMediaCodec* acodec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags); ssize_t SDL_AMediaCodecFake_dequeueOutputBuffer(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs); ssize_t SDL_AMediaCodecFake_dequeueFakeFrameOnly(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs); #endif ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_codec_android_mediacodec_dummy.c ================================================ /* * Copyright (c) 2014 Bilibili * copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_codec_android_mediacodec_dummy.h" #include #include "ijksdl/ijksdl_log.h" #include "ijksdl_codec_android_mediadef.h" #include "ijksdl_codec_android_mediacodec.h" #include "ijksdl_codec_android_mediacodec_internal.h" #define DMY_TRACE(...) //#define DMY_TRACE ALOGE static SDL_Class g_amediacodec_class = { .name = "AMediaCodecDummy", }; typedef struct SDL_AMediaCodec_Opaque { bool request_stop; SDL_AMediaCodec_FakeFifo dummy_fifo; } SDL_AMediaCodec_Opaque; static SDL_AMediaFormat *SDL_AMediaCodecDummy_getOutputFormat(SDL_AMediaCodec *thiz) { return NULL; } static sdl_amedia_status_t SDL_AMediaCodecDummy_delete(SDL_AMediaCodec* acodec) { SDL_AMediaCodec_FakeFifo_destroy(&acodec->opaque->dummy_fifo); SDL_AMediaCodec_FreeInternal(acodec); return SDL_AMEDIA_OK; } static sdl_amedia_status_t SDL_AMediaCodecDummy_configure_surface( JNIEnv*env, SDL_AMediaCodec* acodec, const SDL_AMediaFormat* aformat, jobject android_surface, SDL_AMediaCrypto *crypto, uint32_t flags) { return SDL_AMEDIA_OK; } static sdl_amedia_status_t SDL_AMediaCodecDummy_start(SDL_AMediaCodec* acodec) { acodec->opaque->request_stop = false; return SDL_AMEDIA_OK; } static sdl_amedia_status_t SDL_AMediaCodecDummy_stop(SDL_AMediaCodec* acodec) { acodec->opaque->request_stop = true; SDL_AMediaCodec_FakeFifo_abort(&acodec->opaque->dummy_fifo); return SDL_AMEDIA_OK; } static sdl_amedia_status_t SDL_AMediaCodecDummy_flush(SDL_AMediaCodec* acodec) { SDL_AMediaCodec_FakeFifo_flush(&acodec->opaque->dummy_fifo); return SDL_AMEDIA_OK; } static ssize_t SDL_AMediaCodecDummy_writeInputData(SDL_AMediaCodec* acodec, size_t idx, const uint8_t *data, size_t size) { return size; } static ssize_t SDL_AMediaCodecDummy_dequeueInputBuffer(SDL_AMediaCodec* acodec, int64_t timeoutUs) { DMY_TRACE("%s", __func__); return SDL_AMediaCodec_FakeFifo_dequeueInputBuffer(&acodec->opaque->dummy_fifo, timeoutUs); } static sdl_amedia_status_t SDL_AMediaCodecDummy_queueInputBuffer(SDL_AMediaCodec* acodec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) { DMY_TRACE("%s", __func__); return SDL_AMediaCodec_FakeFifo_queueInputBuffer(&acodec->opaque->dummy_fifo, idx, offset, size, time, flags | AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME); } static ssize_t SDL_AMediaCodecDummy_dequeueOutputBuffer(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs) { DMY_TRACE("%s", __func__); return SDL_AMediaCodec_FakeFifo_dequeueOutputBuffer(&acodec->opaque->dummy_fifo, info, timeoutUs); } static sdl_amedia_status_t SDL_AMediaCodecDummy_releaseOutputBuffer(SDL_AMediaCodec* acodec, size_t idx, bool render) { DMY_TRACE("%s", __func__); return SDL_AMEDIA_OK; } static bool SDL_AMediaCodecDummy_isInputBuffersValid(SDL_AMediaCodec* acodec) { return !acodec->opaque->request_stop; } SDL_AMediaCodec* SDL_AMediaCodecDummy_create() { ALOGI("%s\n", __func__); SDL_AMediaCodec *acodec = SDL_AMediaCodec_CreateInternal(sizeof(SDL_AMediaCodec_Opaque)); if (!acodec) return NULL; SDL_AMediaCodec_Opaque *opaque = acodec->opaque; SDL_AMediaCodec_FakeFifo_init(&opaque->dummy_fifo); acodec->opaque_class = &g_amediacodec_class; acodec->func_delete = SDL_AMediaCodecDummy_delete; acodec->func_configure = NULL; acodec->func_configure_surface = SDL_AMediaCodecDummy_configure_surface; acodec->func_start = SDL_AMediaCodecDummy_start; acodec->func_stop = SDL_AMediaCodecDummy_stop; acodec->func_flush = SDL_AMediaCodecDummy_flush; acodec->func_writeInputData = SDL_AMediaCodecDummy_writeInputData; acodec->func_dequeueInputBuffer = SDL_AMediaCodecDummy_dequeueInputBuffer; acodec->func_queueInputBuffer = SDL_AMediaCodecDummy_queueInputBuffer; acodec->func_dequeueOutputBuffer = SDL_AMediaCodecDummy_dequeueOutputBuffer; acodec->func_getOutputFormat = SDL_AMediaCodecDummy_getOutputFormat; acodec->func_releaseOutputBuffer = SDL_AMediaCodecDummy_releaseOutputBuffer; acodec->func_isInputBuffersValid = SDL_AMediaCodecDummy_isInputBuffersValid; SDL_AMediaCodec_increaseReference(acodec); return acodec; } ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_codec_android_mediacodec_dummy.h ================================================ /* * Copyright (c) 2014 Bilibili * copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIACODEC_DUMMY_H #define IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIACODEC_DUMMY_H #include "ijksdl_codec_android_mediacodec.h" SDL_AMediaCodec *SDL_AMediaCodecDummy_create(); #endif ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_codec_android_mediacodec_internal.c ================================================ /* * Copyright (c) 2015 Bilibili * copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_codec_android_mediacodec_internal.h" #include "ijksdl/ijksdl_log.h" #include "ijksdl/ijksdl_mutex.h" #include "ijksdl/ijksdl_timer.h" #include "ijksdl_codec_android_mediadef.h" #define FAK_TRACE(...) //#define FAK_TRACE ALOGE sdl_amedia_status_t SDL_AMediaCodec_FakeFifo_init(SDL_AMediaCodec_FakeFifo *fifo) { memset(fifo, 0, sizeof(SDL_AMediaCodec_FakeFifo)); fifo->mutex = SDL_CreateMutex(); fifo->wakeup_enqueue_cond = SDL_CreateCond(); fifo->wakeup_dequeue_cond = SDL_CreateCond(); return SDL_AMEDIA_OK; } void SDL_AMediaCodec_FakeFifo_abort(SDL_AMediaCodec_FakeFifo *fifo) { SDL_LockMutex(fifo->mutex); fifo->should_abort = 1; SDL_CondSignal(fifo->wakeup_enqueue_cond); SDL_CondSignal(fifo->wakeup_dequeue_cond); SDL_UnlockMutex(fifo->mutex); } void SDL_AMediaCodec_FakeFifo_destroy(SDL_AMediaCodec_FakeFifo *fifo) { if (!fifo) return; if (fifo->mutex) SDL_AMediaCodec_FakeFifo_abort(fifo); SDL_DestroyMutexP(&fifo->mutex); SDL_DestroyCondP(&fifo->wakeup_enqueue_cond); SDL_DestroyCondP(&fifo->wakeup_dequeue_cond); memset(fifo, 0, sizeof(SDL_AMediaCodec_FakeFifo)); } ssize_t SDL_AMediaCodec_FakeFifo_dequeueInputBuffer(SDL_AMediaCodec_FakeFifo* fifo, int64_t timeoutUs) { int ret_index = -1; if (fifo->should_abort) return SDL_AMEDIA_ERROR_UNKNOWN; SDL_LockMutex(fifo->mutex); if (!fifo->should_abort) { if (fifo->size >= FAKE_BUFFER_QUEUE_SIZE) { SDL_CondWaitTimeout(fifo->wakeup_enqueue_cond, fifo->mutex, timeoutUs / 1000); } if (fifo->size < FAKE_BUFFER_QUEUE_SIZE) { ret_index = fifo->end; } } SDL_UnlockMutex(fifo->mutex); if (fifo->should_abort) return -1; return ret_index; } sdl_amedia_status_t SDL_AMediaCodec_FakeFifo_queueInputBuffer(SDL_AMediaCodec_FakeFifo *fifo, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) { if (fifo->should_abort) return SDL_AMEDIA_ERROR_UNKNOWN; SDL_LockMutex(fifo->mutex); if (fifo->size >= FAKE_BUFFER_QUEUE_SIZE) { SDL_UnlockMutex(fifo->mutex); return SDL_AMEDIA_ERROR_UNKNOWN; } SDL_AMediaCodec_FakeFrame *fake = &fifo->fakes[fifo->end]; fake->info.offset = offset; fake->info.size = size; fake->info.presentationTimeUs = time; fake->info.flags = flags; fake->index = fifo->end; FAK_TRACE("%s, %d, %lld", __func__, fifo->end, time); fifo->end = (fifo->end + 1) % FAKE_BUFFER_QUEUE_SIZE; fifo->size++; SDL_CondSignal(fifo->wakeup_dequeue_cond); SDL_UnlockMutex(fifo->mutex); return SDL_AMEDIA_OK; } ssize_t SDL_AMediaCodec_FakeFifo_dequeueOutputBuffer(SDL_AMediaCodec_FakeFifo *fifo, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs) { if (fifo->should_abort) return -1; int64_t timeoutMs = (timeoutUs + 999) / 1000; ssize_t dequeue_ret = -1; uint64_t wait_start = SDL_GetTickHR(); int64_t to_wait = timeoutMs; SDL_LockMutex(fifo->mutex); while (!fifo->should_abort) { if (fifo->size > 0) { SDL_AMediaCodec_FakeFrame *fake = &fifo->fakes[fifo->begin]; *info = fake->info; info->flags |= AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME; dequeue_ret = fake->index; FAK_TRACE("%s, [%d]%lld", __func__, fifo->begin, info->presentationTimeUs); fifo->begin = (fifo->begin + 1) % FAKE_BUFFER_QUEUE_SIZE; fifo->size--; SDL_CondSignal(fifo->wakeup_enqueue_cond); break; } SDL_CondWaitTimeout(fifo->wakeup_dequeue_cond, fifo->mutex, to_wait); if (to_wait >= 0) { uint64_t now = SDL_GetTickHR(); if (now < wait_start) { // tick overflow dequeue_ret = -1; break; } else { uint64_t elapsed = now - wait_start; if (elapsed >= timeoutMs) { // timeout dequeue_ret = -1; break; } else { to_wait = timeoutMs - elapsed; } } } } SDL_UnlockMutex(fifo->mutex); if (fifo->should_abort) return -1; return dequeue_ret; } void SDL_AMediaCodec_FakeFifo_flush(SDL_AMediaCodec_FakeFifo *fifo) { if (fifo->should_abort) return; SDL_LockMutex(fifo->mutex); fifo->begin = 0; fifo->end = 0; fifo->size = 0; SDL_UnlockMutex(fifo->mutex); } int SDL_AMediaCodec_FakeFifo_size(SDL_AMediaCodec_FakeFifo *fifo) { return fifo->size; } ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_codec_android_mediacodec_internal.h ================================================ /***************************************************************************** * ijksdl_codec_android_mediacodec_internal.h ***************************************************************************** * * Copyright (c) 2014 Bilibili * copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIACODEC_INTERNAL_H #define IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIACODEC_INTERNAL_H #include "ijksdl_codec_android_mediacodec.h" SDL_AMediaCodec *SDL_AMediaCodec_CreateInternal(size_t opaque_size); void SDL_AMediaCodec_FreeInternal(SDL_AMediaCodec *acodec); #define FAKE_BUFFER_QUEUE_SIZE 5 typedef struct SDL_AMediaCodec_FakeFrame { size_t index; SDL_AMediaCodecBufferInfo info; } SDL_AMediaCodec_FakeFrame; typedef struct SDL_AMediaCodec_FakeFifo { SDL_AMediaCodec_FakeFrame fakes[FAKE_BUFFER_QUEUE_SIZE]; int begin; int end; int size; int should_abort; SDL_mutex *mutex; SDL_cond *wakeup_enqueue_cond; SDL_cond *wakeup_dequeue_cond; } SDL_AMediaCodec_FakeFifo; sdl_amedia_status_t SDL_AMediaCodec_FakeFifo_init(SDL_AMediaCodec_FakeFifo *fifo); void SDL_AMediaCodec_FakeFifo_abort(SDL_AMediaCodec_FakeFifo *fifo); void SDL_AMediaCodec_FakeFifo_destroy(SDL_AMediaCodec_FakeFifo *fifo); ssize_t SDL_AMediaCodec_FakeFifo_dequeueInputBuffer(SDL_AMediaCodec_FakeFifo* fifo, int64_t timeoutUs); sdl_amedia_status_t SDL_AMediaCodec_FakeFifo_queueInputBuffer(SDL_AMediaCodec_FakeFifo *fifo, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags); ssize_t SDL_AMediaCodec_FakeFifo_dequeueOutputBuffer(SDL_AMediaCodec_FakeFifo *fifo, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs); void SDL_AMediaCodec_FakeFifo_flush(SDL_AMediaCodec_FakeFifo *fifo); int SDL_AMediaCodec_FakeFifo_size(SDL_AMediaCodec_FakeFifo *fifo); #endif ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_codec_android_mediacodec_java.c ================================================ /***************************************************************************** * ijksdl_codec_android_mediacodec_java.c ***************************************************************************** * * Copyright (c) 2014 Bilibili * copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_codec_android_mediacodec_java.h" #include #include "j4a/class/android/media/MediaCodec.h" #include "ijksdl_android_jni.h" #include "ijksdl_codec_android_mediacodec_internal.h" #include "ijksdl_codec_android_mediaformat_java.h" #include "ijksdl_inc_internal_android.h" static SDL_Class g_amediacodec_class = { .name = "AMediaCodecJava", }; typedef struct SDL_AMediaCodec_Opaque { jobject android_media_codec; jobject output_buffer_info; bool is_input_buffer_valid; } SDL_AMediaCodec_Opaque; jobject SDL_AMediaCodecJava_getObject(JNIEnv *env, const SDL_AMediaCodec *thiz) { if (!thiz || !thiz->opaque) return NULL; SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)thiz->opaque; return opaque->android_media_codec; } SDL_AMediaFormat *SDL_AMediaCodecJava_getOutputFormat(SDL_AMediaCodec *thiz) { if (!thiz || !thiz->opaque) return NULL; JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SetupThreadEnv failed", __func__); return NULL; } SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)thiz->opaque; jobject local_android_format = J4AC_MediaCodec__getOutputFormat__catchAll(env, opaque->android_media_codec); if (!local_android_format) { return NULL; } SDL_AMediaFormat *aformat = SDL_AMediaFormatJava_init(env, local_android_format); SDL_JNI_DeleteLocalRefP(env, &local_android_format); return aformat; } static sdl_amedia_status_t SDL_AMediaCodecJava_delete(SDL_AMediaCodec* acodec) { ALOGI("%s\n", __func__); if (!acodec) return SDL_AMEDIA_OK; JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("SDL_AMediaCodecJava_delete: SetupThreadEnv failed"); return SDL_AMEDIA_ERROR_UNKNOWN; } SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque; if (opaque) { if (opaque->android_media_codec) { J4AC_MediaCodec__release__catchAll(env, opaque->android_media_codec); } SDL_JNI_DeleteGlobalRefP(env, &opaque->output_buffer_info); SDL_JNI_DeleteGlobalRefP(env, &opaque->android_media_codec); } SDL_AMediaCodec_FreeInternal(acodec); return SDL_AMEDIA_OK; } static sdl_amedia_status_t SDL_AMediaCodecJava_configure_surface( JNIEnv*env, SDL_AMediaCodec* acodec, const SDL_AMediaFormat* aformat, jobject android_surface, SDL_AMediaCrypto *crypto, uint32_t flags) { SDLTRACE("%s", __func__); SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque; jobject android_media_format = SDL_AMediaFormatJava_getObject(env, aformat); jobject android_media_codec = SDL_AMediaCodecJava_getObject(env, acodec); ALOGE("configure acodec:%p format:%p: surface:%p", android_media_codec, android_media_format, android_surface); J4AC_MediaCodec__configure(env, android_media_codec, android_media_format, android_surface, crypto, flags); if (J4A_ExceptionCheck__catchAll(env)) { return SDL_AMEDIA_ERROR_UNKNOWN; } opaque->is_input_buffer_valid = true; return SDL_AMEDIA_OK; } static sdl_amedia_status_t SDL_AMediaCodecJava_start(SDL_AMediaCodec* acodec) { SDLTRACE("%s", __func__); JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SetupThreadEnv failed", __func__); return SDL_AMEDIA_ERROR_UNKNOWN; } SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque; jobject android_media_codec = opaque->android_media_codec; J4AC_MediaCodec__start(env, android_media_codec); if (J4A_ExceptionCheck__catchAll(env)) { ALOGE("%s: start failed", __func__); return SDL_AMEDIA_ERROR_UNKNOWN; } return SDL_AMEDIA_OK; } static sdl_amedia_status_t SDL_AMediaCodecJava_stop(SDL_AMediaCodec* acodec) { SDLTRACE("%s", __func__); JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SetupThreadEnv failed", __func__); return SDL_AMEDIA_ERROR_UNKNOWN; } jobject android_media_codec = SDL_AMediaCodecJava_getObject(env, acodec); J4AC_MediaCodec__stop(env, android_media_codec); if (J4A_ExceptionCheck__catchAll(env)) { ALOGE("%s: stop", __func__); return SDL_AMEDIA_ERROR_UNKNOWN; } acodec->object_serial = SDL_AMediaCodec_create_object_serial(); return SDL_AMEDIA_OK; } static sdl_amedia_status_t SDL_AMediaCodecJava_flush(SDL_AMediaCodec* acodec) { SDLTRACE("%s", __func__); JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SetupThreadEnv failed", __func__); return SDL_AMEDIA_ERROR_UNKNOWN; } jobject android_media_codec = SDL_AMediaCodecJava_getObject(env, acodec); J4AC_MediaCodec__flush(env, android_media_codec); if (J4A_ExceptionCheck__catchAll(env)) { ALOGE("%s: flush", __func__); return SDL_AMEDIA_ERROR_UNKNOWN; } acodec->object_serial = SDL_AMediaCodec_create_object_serial(); return SDL_AMEDIA_OK; } static ssize_t SDL_AMediaCodecJava_writeInputData(SDL_AMediaCodec* acodec, size_t idx, const uint8_t *data, size_t size) { AMCTRACE("%s", __func__); ssize_t write_ret = -1; jobject input_buffer_array = NULL; jobject input_buffer = NULL; JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SetupThreadEnv failed", __func__); return -1; } SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque; input_buffer_array = J4AC_MediaCodec__getInputBuffers__catchAll(env, opaque->android_media_codec); if (!input_buffer_array) return -1; int buffer_count = (*env)->GetArrayLength(env, input_buffer_array); if (J4A_ExceptionCheck__catchAll(env) || idx < 0 || idx >= buffer_count) { ALOGE("%s: idx(%d) < count(%d)\n", __func__, (int)idx, (int)buffer_count); goto fail; } input_buffer = (*env)->GetObjectArrayElement(env, input_buffer_array, idx); if (J4A_ExceptionCheck__catchAll(env) || !input_buffer) { ALOGE("%s: GetObjectArrayElement failed\n", __func__); goto fail; } { jlong buf_size = (*env)->GetDirectBufferCapacity(env, input_buffer); void *buf_ptr = (*env)->GetDirectBufferAddress(env, input_buffer); write_ret = size < buf_size ? size : buf_size; memcpy(buf_ptr, data, write_ret); } fail: SDL_JNI_DeleteLocalRefP(env, &input_buffer); SDL_JNI_DeleteLocalRefP(env, &input_buffer_array); return write_ret; } ssize_t SDL_AMediaCodecJava_dequeueInputBuffer(SDL_AMediaCodec* acodec, int64_t timeoutUs) { AMCTRACE("%s(%d)", __func__, (int)timeoutUs); JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SetupThreadEnv failed", __func__); return -1; } SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque; // docs lie, getInputBuffers should be good after // m_codec->start() but the internal refs are not // setup until much later on some devices. //if (-1 == getInputBuffers(env, acodec)) { // ALOGE("%s: getInputBuffers failed", __func__); // return -1; //} jobject android_media_codec = opaque->android_media_codec; jint idx = J4AC_MediaCodec__dequeueInputBuffer(env, android_media_codec, (jlong)timeoutUs); if (J4A_ExceptionCheck__catchAll(env)) { ALOGE("%s: dequeueInputBuffer failed", __func__); opaque->is_input_buffer_valid = false; return -1; } return idx; } sdl_amedia_status_t SDL_AMediaCodecJava_queueInputBuffer(SDL_AMediaCodec* acodec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) { AMCTRACE("%s: %d", __func__, (int)idx); JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("SDL_AMediaCodecJava_queueInputBuffer: SetupThreadEnv failed"); return SDL_AMEDIA_ERROR_UNKNOWN; } SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque; jobject android_media_codec = opaque->android_media_codec; J4AC_MediaCodec__queueInputBuffer(env, android_media_codec, (jint)idx, (jint)offset, (jint)size, (jlong)time, (jint)flags); if (J4A_ExceptionCheck__catchAll(env)) { return SDL_AMEDIA_ERROR_UNKNOWN; } return SDL_AMEDIA_OK; } ssize_t SDL_AMediaCodecJava_dequeueOutputBuffer(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs) { AMCTRACE("%s(%d)", __func__, (int)timeoutUs); JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SetupThreadEnv failed", __func__); return AMEDIACODEC__UNKNOWN_ERROR; } SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque; jobject android_media_codec = opaque->android_media_codec; if (!opaque->output_buffer_info) { opaque->output_buffer_info = J4AC_MediaCodec__BufferInfo__BufferInfo__asGlobalRef__catchAll(env); if (!opaque->output_buffer_info) return AMEDIACODEC__UNKNOWN_ERROR; } jint idx = AMEDIACODEC__UNKNOWN_ERROR; while (1) { idx = J4AC_MediaCodec__dequeueOutputBuffer(env, android_media_codec, opaque->output_buffer_info, (jlong)timeoutUs); if (J4A_ExceptionCheck__catchAll(env)) { ALOGI("%s: Exception\n", __func__); return AMEDIACODEC__UNKNOWN_ERROR; } if (idx == AMEDIACODEC__INFO_OUTPUT_BUFFERS_CHANGED) { ALOGI("%s: INFO_OUTPUT_BUFFERS_CHANGED\n", __func__); continue; } else if (idx == AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED) { ALOGI("%s: INFO_OUTPUT_FORMAT_CHANGED\n", __func__); } else if (idx >= 0) { AMCTRACE("%s: buffer ready (%d) ====================\n", __func__, idx); if (info) { info->offset = J4AC_MediaCodec__BufferInfo__offset__get__catchAll(env, opaque->output_buffer_info); info->size = J4AC_MediaCodec__BufferInfo__size__get__catchAll(env, opaque->output_buffer_info); info->presentationTimeUs = J4AC_MediaCodec__BufferInfo__presentationTimeUs__get__catchAll(env, opaque->output_buffer_info); info->flags = J4AC_MediaCodec__BufferInfo__flags__get__catchAll(env, opaque->output_buffer_info); } } break; } return idx; } sdl_amedia_status_t SDL_AMediaCodecJava_releaseOutputBuffer(SDL_AMediaCodec* acodec, size_t idx, bool render) { AMCTRACE("%s", __func__); JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s(%d, %s): SetupThreadEnv failed", __func__, (int)idx, render ? "true" : "false"); return SDL_AMEDIA_ERROR_UNKNOWN; } SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque; jobject android_media_codec = opaque->android_media_codec; J4AC_MediaCodec__releaseOutputBuffer(env, android_media_codec, (jint)idx, (jboolean)render); if (J4A_ExceptionCheck__catchAll(env)) { ALOGE("%s: releaseOutputBuffer\n", __func__); return SDL_AMEDIA_ERROR_UNKNOWN; } return SDL_AMEDIA_OK; } bool SDL_AMediaCodecJava_isInputBuffersValid(SDL_AMediaCodec* acodec) { SDL_AMediaCodec_Opaque *opaque = acodec->opaque; return opaque->is_input_buffer_valid; } static SDL_AMediaCodec* SDL_AMediaCodecJava_init(JNIEnv *env, jobject android_media_codec) { SDLTRACE("%s", __func__); jobject global_android_media_codec = (*env)->NewGlobalRef(env, android_media_codec); if (J4A_ExceptionCheck__catchAll(env) || !global_android_media_codec) { return NULL; } SDL_AMediaCodec *acodec = SDL_AMediaCodec_CreateInternal(sizeof(SDL_AMediaCodec_Opaque)); if (!acodec) { SDL_JNI_DeleteGlobalRefP(env, &global_android_media_codec); return NULL; } SDL_AMediaCodec_Opaque *opaque = acodec->opaque; opaque->android_media_codec = global_android_media_codec; acodec->opaque_class = &g_amediacodec_class; acodec->func_delete = SDL_AMediaCodecJava_delete; acodec->func_configure = NULL; acodec->func_configure_surface = SDL_AMediaCodecJava_configure_surface; acodec->func_start = SDL_AMediaCodecJava_start; acodec->func_stop = SDL_AMediaCodecJava_stop; acodec->func_flush = SDL_AMediaCodecJava_flush; acodec->func_writeInputData = SDL_AMediaCodecJava_writeInputData; acodec->func_dequeueInputBuffer = SDL_AMediaCodecJava_dequeueInputBuffer; acodec->func_queueInputBuffer = SDL_AMediaCodecJava_queueInputBuffer; acodec->func_dequeueOutputBuffer = SDL_AMediaCodecJava_dequeueOutputBuffer; acodec->func_getOutputFormat = SDL_AMediaCodecJava_getOutputFormat; acodec->func_releaseOutputBuffer = SDL_AMediaCodecJava_releaseOutputBuffer; acodec->func_isInputBuffersValid = SDL_AMediaCodecJava_isInputBuffersValid; SDL_AMediaCodec_increaseReference(acodec); return acodec; } SDL_AMediaCodec* SDL_AMediaCodecJava_createByCodecName(JNIEnv *env, const char *codec_name) { SDLTRACE("%s", __func__); jobject android_media_codec = J4AC_MediaCodec__createByCodecName__withCString__catchAll(env, codec_name); if (J4A_ExceptionCheck__catchAll(env) || !android_media_codec) { return NULL; } SDL_AMediaCodec* acodec = SDL_AMediaCodecJava_init(env, android_media_codec); acodec->object_serial = SDL_AMediaCodec_create_object_serial(); SDL_JNI_DeleteLocalRefP(env, &android_media_codec); return acodec; } ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_codec_android_mediacodec_java.h ================================================ /***************************************************************************** * ijksdl_codec_android_mediacodec_java.h ***************************************************************************** * * Copyright (c) 2014 Bilibili * copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIACODEC_JAVA_H #define IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIACODEC_JAVA_H #include "ijksdl_codec_android_mediacodec.h" typedef struct ASDK_MediaCodec ASDK_MediaCodec; SDL_AMediaCodec *SDL_AMediaCodecJava_createByCodecName(JNIEnv *env, const char *codec_name); jobject SDL_AMediaCodecJava_getObject(JNIEnv *env, const SDL_AMediaCodec *thiz); #endif ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_codec_android_mediadef.c ================================================ /***************************************************************************** * ijksdl_codec_android_mediadef.h ***************************************************************************** * * Copyright (c) 2014 Bilibili * copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_codec_android_mediadef.h" const char *SDL_AMediaCodec_getColorFormatName(int colorFormat) { switch (colorFormat) { case AMEDIACODEC__OMX_COLOR_FormatMonochrome: return "Format8bitRGB332"; case AMEDIACODEC__OMX_COLOR_Format8bitRGB332: return "Format8bitRGB332"; case AMEDIACODEC__OMX_COLOR_Format12bitRGB444: return "Format12bitRGB444"; case AMEDIACODEC__OMX_COLOR_Format16bitARGB4444: return "Format16bitARGB4444"; case AMEDIACODEC__OMX_COLOR_Format16bitARGB1555: return "Format16bitARGB1555"; case AMEDIACODEC__OMX_COLOR_Format16bitRGB565: return "Format16bitRGB565"; case AMEDIACODEC__OMX_COLOR_Format16bitBGR565: return "Format16bitBGR565"; case AMEDIACODEC__OMX_COLOR_Format18bitRGB666: return "Format18bitRGB666"; case AMEDIACODEC__OMX_COLOR_Format18bitARGB1665: return "Format18bitARGB1665"; case AMEDIACODEC__OMX_COLOR_Format19bitARGB1666: return "Format19bitARGB1666"; case AMEDIACODEC__OMX_COLOR_Format24bitRGB888: return "Format24bitRGB888"; case AMEDIACODEC__OMX_COLOR_Format24bitBGR888: return "Format24bitBGR888"; case AMEDIACODEC__OMX_COLOR_Format24bitARGB1887: return "Format24bitARGB1887"; case AMEDIACODEC__OMX_COLOR_Format25bitARGB1888: return "Format25bitARGB1888"; case AMEDIACODEC__OMX_COLOR_Format32bitBGRA8888: return "Format32bitBGRA8888"; case AMEDIACODEC__OMX_COLOR_Format32bitARGB8888: return "Format32bitARGB8888"; case AMEDIACODEC__OMX_COLOR_FormatYUV411Planar: return "FormatYUV411Planar"; case AMEDIACODEC__OMX_COLOR_FormatYUV411PackedPlanar: return "FormatYUV411PackedPlanar"; case AMEDIACODEC__OMX_COLOR_FormatYUV420Planar: return "FormatYUV420Planar"; case AMEDIACODEC__OMX_COLOR_FormatYUV420PackedPlanar: return "FormatYUV420PackedPlanar"; case AMEDIACODEC__OMX_COLOR_FormatYUV420SemiPlanar: return "FormatYUV420SemiPlanar"; case AMEDIACODEC__OMX_COLOR_FormatYUV422Planar: return "FormatYUV422Planar"; case AMEDIACODEC__OMX_COLOR_FormatYUV422PackedPlanar: return "FormatYUV422PackedPlanar"; case AMEDIACODEC__OMX_COLOR_FormatYUV422SemiPlanar: return "FormatYUV422SemiPlanar"; case AMEDIACODEC__OMX_COLOR_FormatYCbYCr: return "FormatYCbYCr"; case AMEDIACODEC__OMX_COLOR_FormatYCrYCb: return "FormatYCrYCb"; case AMEDIACODEC__OMX_COLOR_FormatCbYCrY: return "FormatCbYCrY"; case AMEDIACODEC__OMX_COLOR_FormatCrYCbY: return "FormatCrYCbY"; case AMEDIACODEC__OMX_COLOR_FormatYUV444Interleaved: return "FormatYUV444Interleaved"; case AMEDIACODEC__OMX_COLOR_FormatRawBayer8bit: return "FormatRawBayer8bit"; case AMEDIACODEC__OMX_COLOR_FormatRawBayer10bit: return "FormatRawBayer10bit"; case AMEDIACODEC__OMX_COLOR_FormatRawBayer8bitcompressed: return "FormatRawBayer8bitcompressed"; case AMEDIACODEC__OMX_COLOR_FormatL2: return "FormatL2"; case AMEDIACODEC__OMX_COLOR_FormatL4: return "FormatL4"; case AMEDIACODEC__OMX_COLOR_FormatL8: return "FormatL8"; case AMEDIACODEC__OMX_COLOR_FormatL16: return "FormatL16"; case AMEDIACODEC__OMX_COLOR_FormatL24: return "FormatL24"; case AMEDIACODEC__OMX_COLOR_FormatL32: return "FormatL32"; case AMEDIACODEC__OMX_COLOR_FormatYUV420PackedSemiPlanar: return "FormatYUV420PackedSemiPlanar"; case AMEDIACODEC__OMX_COLOR_FormatYUV422PackedSemiPlanar: return "FormatYUV422PackedSemiPlanar"; case AMEDIACODEC__OMX_COLOR_Format18BitBGR666: return "Format18BitBGR666"; case AMEDIACODEC__OMX_COLOR_Format24BitARGB6666: return "Format24BitARGB6666"; case AMEDIACODEC__OMX_COLOR_Format24BitABGR6666: return "Format24BitABGR6666"; #if 0 // duplicated case AMEDIACODEC__OMX_COLOR_TI_FormatYUV420PackedSemiPlanar: return "TI_FormatYUV420PackedSemiPlanar"; #endif case AMEDIACODEC__OMX_COLOR_FormatSurface: return "FormatSurface"; case AMEDIACODEC__OMX_COLOR_FormatYUV420Flexible: return "FormatYUV420Flexible"; #if 0 // duplicated case AMEDIACODEC__OMX_COLOR_QCOM_FormatYUV420SemiPlanar: return "QCOM_FormatYUV420SemiPlanar"; #endif // from hardware intel case _AMEDIACODEC__OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar: return "INTEL_FormatYUV420PackedSemiPlanar"; case _AMEDIACODEC__OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled: return "INTEL_FormatYUV420PackedSemiPlanar_Tiled"; // from hardware qcom case _AMEDIACODEC__OMX_QCOM_COLOR_FormatYVU420SemiPlanar: return "QCOM_FormatYVU420SemiPlanar"; case _AMEDIACODEC__OMX_QCOM_COLOR_FormatYVU420PackedSemiPlanar32m4ka: return "QCOM_FormatYVU420PackedSemiPlanar32m4ka"; case _AMEDIACODEC__OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar16m2ka: return "QCOM_FormatYUV420PackedSemiPlanar16m2ka"; case _AMEDIACODEC__OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka: return "QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka"; case _AMEDIACODEC__OMX_QCOM_COLOR_FORMATYUV420PackedSemiPlanar32m: return "QCOM_FORMATYUV420PackedSemiPlanar32m"; case _AMEDIACODEC__OMX_QCOM_COLOR_FORMATYUV420PackedSemiPlanar32mMultiView: return "QCOM_FORMATYUV420PackedSemiPlanar32mMultiView"; // from hardware samsung_slsi case _AMEDIACODEC__OMX_SEC_COLOR_FormatNV12TPhysicalAddress: return "SEC_FormatNV12TPhysicalAddress"; case _AMEDIACODEC__OMX_SEC_COLOR_FormatNV12LPhysicalAddress: return "SEC_FormatNV12LPhysicalAddress"; case _AMEDIACODEC__OMX_SEC_COLOR_FormatNV12LVirtualAddress: return "SEC_FormatNV12LVirtualAddress"; case _AMEDIACODEC__OMX_SEC_COLOR_FormatNV12Tiled: return "SEC_FormatNV12Tiled"; case _AMEDIACODEC__OMX_SEC_COLOR_FormatNV21LPhysicalAddress: return "SEC_FormatNV21LPhysicalAddress"; case _AMEDIACODEC__OMX_SEC_COLOR_FormatNV21Linear: return "SEC_FormatNV21Linear"; // from hardware ti case _AMEDIACODEC__OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: return "TI_FormatYUV420PackedSemiPlanar"; default: return "FormatUnknown"; } } ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_codec_android_mediadef.h ================================================ /***************************************************************************** * ijksdl_codec_android_mediadef.h ***************************************************************************** * * Copyright (c) 2014 Bilibili * copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIADEF_H #define IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIADEF_H #include "../ijksdl_misc.h" typedef enum sdl_amedia_status_t { SDL_AMEDIA_OK = 0, SDL_AMEDIA_ERROR_BASE = -10000, SDL_AMEDIA_ERROR_UNKNOWN = SDL_AMEDIA_ERROR_BASE, SDL_AMEDIA_ERROR_MALFORMED = SDL_AMEDIA_ERROR_BASE - 1, SDL_AMEDIA_ERROR_UNSUPPORTED = SDL_AMEDIA_ERROR_BASE - 2, SDL_AMEDIA_ERROR_INVALID_OBJECT = SDL_AMEDIA_ERROR_BASE - 3, SDL_AMEDIA_ERROR_INVALID_PARAMETER = SDL_AMEDIA_ERROR_BASE - 4, SDL_AMEDIA_DRM_ERROR_BASE = -20000, SDL_AMEDIA_DRM_NOT_PROVISIONED = SDL_AMEDIA_DRM_ERROR_BASE - 1, SDL_AMEDIA_DRM_RESOURCE_BUSY = SDL_AMEDIA_DRM_ERROR_BASE - 2, SDL_AMEDIA_DRM_DEVICE_REVOKED = SDL_AMEDIA_DRM_ERROR_BASE - 3, SDL_AMEDIA_DRM_SHORT_BUFFER = SDL_AMEDIA_DRM_ERROR_BASE - 4, SDL_AMEDIA_DRM_SESSION_NOT_OPENED = SDL_AMEDIA_DRM_ERROR_BASE - 5, SDL_AMEDIA_DRM_TAMPER_DETECTED = SDL_AMEDIA_DRM_ERROR_BASE - 6, SDL_AMEDIA_DRM_VERIFY_FAILED = SDL_AMEDIA_DRM_ERROR_BASE - 7, SDL_AMEDIA_DRM_NEED_KEY = SDL_AMEDIA_DRM_ERROR_BASE - 8, SDL_AMEDIA_DRM_LICENSE_EXPIRED = SDL_AMEDIA_DRM_ERROR_BASE - 9, } sdl_amedia_status_t; #define SDL_AMIME_VIDEO_VP8 "video/x-vnd.on2.vp8" //- VP8 video (i.e. video in .webm) #define SDL_AMIME_VIDEO_VP9 "video/x-vnd.on2.vp9" //- VP9 video (i.e. video in .webm) #define SDL_AMIME_VIDEO_AVC "video/avc" //- H.264/AVC video #define SDL_AMIME_VIDEO_HEVC "video/hevc" //- H.265/HEVC video #define SDL_AMIME_VIDEO_MPEG2VIDEO "video/mpeg2" //- MPEG2 video #define SDL_AMIME_VIDEO_MPEG4 "video/mp4v-es" //- MPEG4 video #define SDL_AMIME_VIDEO_H263 "video/3gpp" //- H.263 video #define SDL_AMIME_AUDIO_AMR_NB "audio/3gpp" //- AMR narrowband audio #define SDL_AMIME_AUDIO_AMR_WB "audio/amr-wb" //- AMR wideband audio #define SDL_AMIME_AUDIO_MP3 "audio/mpeg" //- MPEG1/2 audio layer III #define SDL_AMIME_AUDIO_RAW_AAC "audio/mp4a-latm" //- AAC audio (note, this is raw AAC packets, not packaged in LATM!) #define SDL_AMIME_AUDIO_VORBIS "audio/vorbis" //- vorbis audio #define SDL_AMIME_AUDIO_G711_ALAW "audio/g711-alaw" //- G.711 alaw audio #define SDL_AMIME_AUDIO_G711_MLAW "audio/g711-mlaw" //- G.711 ulaw audio #if 0 typedef enum sdl_amedia_format_key_t { AMEDIAFORMAT_KEY_AAC_PROFILE, AMEDIAFORMAT_KEY_BIT_RATE, AMEDIAFORMAT_KEY_CHANNEL_COUNT, AMEDIAFORMAT_KEY_CHANNEL_MASK, AMEDIAFORMAT_KEY_COLOR_FORMAT, AMEDIAFORMAT_KEY_DURATION, AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL, AMEDIAFORMAT_KEY_FRAME_RATE, AMEDIAFORMAT_KEY_HEIGHT, AMEDIAFORMAT_KEY_IS_ADTS, AMEDIAFORMAT_KEY_IS_AUTOSELECT, AMEDIAFORMAT_KEY_IS_DEFAULT, AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, AMEDIAFORMAT_KEY_LANGUAGE, AMEDIAFORMAT_KEY_MAX_HEIGHT, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, AMEDIAFORMAT_KEY_MAX_WIDTH, AMEDIAFORMAT_KEY_MIME, AMEDIAFORMAT_KEY_PUSH_BLANK_BUFFERS_ON_STOP, AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER, AMEDIAFORMAT_KEY_SAMPLE_RATE, AMEDIAFORMAT_KEY_WIDTH, AMEDIAFORMAT_KEY_STRIDE, } sdl_amedia_format_key_t; #else #define AMEDIAFORMAT_KEY_AAC_PROFILE "aac-profile" #define AMEDIAFORMAT_KEY_BIT_RATE "bitrate" #define AMEDIAFORMAT_KEY_CHANNEL_COUNT "channel-count" #define AMEDIAFORMAT_KEY_CHANNEL_MASK "channel-mask" #define AMEDIAFORMAT_KEY_COLOR_FORMAT "color-format" #define AMEDIAFORMAT_KEY_DURATION "durationUs" #define AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL "flac-compression-level" #define AMEDIAFORMAT_KEY_FRAME_RATE "frame-rate" #define AMEDIAFORMAT_KEY_HEIGHT "height" #define AMEDIAFORMAT_KEY_IS_ADTS "is-adts" //#define AMEDIAFORMAT_KEY_IS_AUTOSELECT //#define AMEDIAFORMAT_KEY_IS_DEFAULT //#define AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE #define AMEDIAFORMAT_KEY_I_FRAME_INTERVAL "i-frame-interval" //#define AMEDIAFORMAT_KEY_LANGUAGE //#define AMEDIAFORMAT_KEY_MAX_HEIGHT #define AMEDIAFORMAT_KEY_MAX_INPUT_SIZE "max-input-size" //#define AMEDIAFORMAT_KEY_MAX_WIDTH #define AMEDIAFORMAT_KEY_MIME "mime" //#define AMEDIAFORMAT_KEY_PUSH_BLANK_BUFFERS_ON_STOP, //#define AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER, #define AMEDIAFORMAT_KEY_SAMPLE_RATE "sample-rate" #define AMEDIAFORMAT_KEY_WIDTH "width" //#define AMEDIAFORMAT_KEY_STRIDE #endif enum { AMEDIACODEC__INFO_OUTPUT_BUFFERS_CHANGED = -3, AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED = -2, AMEDIACODEC__INFO_TRY_AGAIN_LATER = -1, AMEDIACODEC__UNKNOWN_ERROR = -1000, }; enum { AMEDIACODEC__BUFFER_FLAG_KEY_FRAME = 0x01, AMEDIACODEC__BUFFER_FLAG_CODEC_CONFIG = 0x02, AMEDIACODEC__BUFFER_FLAG_END_OF_STREAM = 0x04, // extended AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME = 0x1000, }; enum { AMEDIACODEC__OMX_COLOR_FormatMonochrome = 1, AMEDIACODEC__OMX_COLOR_Format8bitRGB332 = 2, AMEDIACODEC__OMX_COLOR_Format12bitRGB444 = 3, AMEDIACODEC__OMX_COLOR_Format16bitARGB4444 = 4, AMEDIACODEC__OMX_COLOR_Format16bitARGB1555 = 5, AMEDIACODEC__OMX_COLOR_Format16bitRGB565 = 6, AMEDIACODEC__OMX_COLOR_Format16bitBGR565 = 7, AMEDIACODEC__OMX_COLOR_Format18bitRGB666 = 8, AMEDIACODEC__OMX_COLOR_Format18bitARGB1665 = 9, AMEDIACODEC__OMX_COLOR_Format19bitARGB1666 = 10, AMEDIACODEC__OMX_COLOR_Format24bitRGB888 = 11, AMEDIACODEC__OMX_COLOR_Format24bitBGR888 = 12, AMEDIACODEC__OMX_COLOR_Format24bitARGB1887 = 13, AMEDIACODEC__OMX_COLOR_Format25bitARGB1888 = 14, AMEDIACODEC__OMX_COLOR_Format32bitBGRA8888 = 15, AMEDIACODEC__OMX_COLOR_Format32bitARGB8888 = 16, AMEDIACODEC__OMX_COLOR_FormatYUV411Planar = 17, AMEDIACODEC__OMX_COLOR_FormatYUV411PackedPlanar = 18, AMEDIACODEC__OMX_COLOR_FormatYUV420Planar = 19, AMEDIACODEC__OMX_COLOR_FormatYUV420PackedPlanar = 20, AMEDIACODEC__OMX_COLOR_FormatYUV420SemiPlanar = 21, AMEDIACODEC__OMX_COLOR_FormatYUV422Planar = 22, AMEDIACODEC__OMX_COLOR_FormatYUV422PackedPlanar = 23, AMEDIACODEC__OMX_COLOR_FormatYUV422SemiPlanar = 24, AMEDIACODEC__OMX_COLOR_FormatYCbYCr = 25, AMEDIACODEC__OMX_COLOR_FormatYCrYCb = 26, AMEDIACODEC__OMX_COLOR_FormatCbYCrY = 27, AMEDIACODEC__OMX_COLOR_FormatCrYCbY = 28, AMEDIACODEC__OMX_COLOR_FormatYUV444Interleaved = 29, AMEDIACODEC__OMX_COLOR_FormatRawBayer8bit = 30, AMEDIACODEC__OMX_COLOR_FormatRawBayer10bit = 31, AMEDIACODEC__OMX_COLOR_FormatRawBayer8bitcompressed = 32, AMEDIACODEC__OMX_COLOR_FormatL2 = 33, AMEDIACODEC__OMX_COLOR_FormatL4 = 34, AMEDIACODEC__OMX_COLOR_FormatL8 = 35, AMEDIACODEC__OMX_COLOR_FormatL16 = 36, AMEDIACODEC__OMX_COLOR_FormatL24 = 37, AMEDIACODEC__OMX_COLOR_FormatL32 = 38, AMEDIACODEC__OMX_COLOR_FormatYUV420PackedSemiPlanar = 39, AMEDIACODEC__OMX_COLOR_FormatYUV422PackedSemiPlanar = 40, AMEDIACODEC__OMX_COLOR_Format18BitBGR666 = 41, AMEDIACODEC__OMX_COLOR_Format24BitARGB6666 = 42, AMEDIACODEC__OMX_COLOR_Format24BitABGR6666 = 43, // AMEDIACODEC__OMX_COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100, AMEDIACODEC__OMX_COLOR_FormatSurface = 0x7f000789, AMEDIACODEC__OMX_COLOR_FormatYUV420Flexible = 0x7f420888, // AMEDIACODEC__OMX_COLOR_QCOM_FormatYUV420SemiPlanar = 0x7fa30c00, // from hardware intel _AMEDIACODEC__OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar = 0x7FA00E00, _AMEDIACODEC__OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled = 0x7FA00F00, // from hardware qcom _AMEDIACODEC__OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00, _AMEDIACODEC__OMX_QCOM_COLOR_FormatYVU420PackedSemiPlanar32m4ka = 0x7FA30C01, _AMEDIACODEC__OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar16m2ka = 0x7FA30C02, _AMEDIACODEC__OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka = 0x7FA30C03, _AMEDIACODEC__OMX_QCOM_COLOR_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04, _AMEDIACODEC__OMX_QCOM_COLOR_FORMATYUV420PackedSemiPlanar32mMultiView = 0x7FA30C05, // from hardware samsung_slsi _AMEDIACODEC__OMX_SEC_COLOR_FormatNV12TPhysicalAddress = 0x7F000001, _AMEDIACODEC__OMX_SEC_COLOR_FormatNV12LPhysicalAddress = 0x7F000002, _AMEDIACODEC__OMX_SEC_COLOR_FormatNV12LVirtualAddress = 0x7F000003, _AMEDIACODEC__OMX_SEC_COLOR_FormatNV12Tiled = 0x7FC00002, _AMEDIACODEC__OMX_SEC_COLOR_FormatNV21LPhysicalAddress = 0x7F000010, _AMEDIACODEC__OMX_SEC_COLOR_FormatNV21Linear = 0x7F000011, // from hardware ti // _AMEDIACODEC__OMX_TI_COLOR_FormatRawBayer10bitStereo = 0x7F000002, _AMEDIACODEC__OMX_TI_COLOR_FormatYUV420PackedSemiPlanar = 0x7F000100, }; const char *SDL_AMediaCodec_getColorFormatName(int colorFormat); //#define AMCTRACE ALOGI #define AMCTRACE(...) #endif ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_codec_android_mediaformat.c ================================================ /***************************************************************************** * ijksdl_codec_android_mediaformat.c ***************************************************************************** * * Copyright (c) 2014 Bilibili * copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_codec_android_mediaformat.h" #include // FIXME: release SDL_AMediaFormat sdl_amedia_status_t SDL_AMediaFormat_delete(SDL_AMediaFormat* aformat) { if (!aformat) return SDL_AMEDIA_OK; assert(aformat->func_delete); return aformat->func_delete(aformat); } sdl_amedia_status_t SDL_AMediaFormat_deleteP(SDL_AMediaFormat** aformat) { if (!aformat) return SDL_AMEDIA_OK; sdl_amedia_status_t amc_ret = SDL_AMediaFormat_delete(*aformat); *aformat = NULL; return amc_ret; } bool SDL_AMediaFormat_getInt32(SDL_AMediaFormat* aformat, const char* name, int32_t *out) { assert(aformat->func_getInt32); return aformat->func_getInt32(aformat, name, out); } void SDL_AMediaFormat_setInt32(SDL_AMediaFormat* aformat, const char* name, int32_t value) { assert(aformat->func_setInt32); aformat->func_setInt32(aformat, name, value); } void SDL_AMediaFormat_setBuffer(SDL_AMediaFormat* aformat, const char* name, void* data, size_t size) { assert(aformat->func_setInt32); aformat->func_setBuffer(aformat, name, data, size); } ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_codec_android_mediaformat.h ================================================ /***************************************************************************** * ijksdl_codec_android_mediaformat.h ***************************************************************************** * * Copyright (c) 2014 Bilibili * copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIAFORMAT_H #define IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIAFORMAT_H #include "../ijksdl_stdinc.h" #include #include #include #include "../ijksdl_mutex.h" #include "ijksdl_codec_android_mediadef.h" typedef struct SDL_AMediaFormat_Opaque SDL_AMediaFormat_Opaque; typedef struct SDL_AMediaFormat SDL_AMediaFormat; typedef struct SDL_AMediaFormat { SDL_mutex *mutex; SDL_AMediaFormat_Opaque *opaque; sdl_amedia_status_t (*func_delete)(SDL_AMediaFormat *aformat); bool (*func_getInt32)(SDL_AMediaFormat* aformat, const char* name, int32_t *out); void (*func_setInt32)(SDL_AMediaFormat* aformat, const char* name, int32_t value); void (*func_setBuffer)(SDL_AMediaFormat* aformat, const char* name, void* data, size_t size); } SDL_AMediaFormat; sdl_amedia_status_t SDL_AMediaFormat_delete(SDL_AMediaFormat* aformat); sdl_amedia_status_t SDL_AMediaFormat_deleteP(SDL_AMediaFormat** aformat); bool SDL_AMediaFormat_getInt32(SDL_AMediaFormat* aformat, const char* name, int32_t *out); void SDL_AMediaFormat_setInt32(SDL_AMediaFormat* aformat, const char* name, int32_t value); void SDL_AMediaFormat_setBuffer(SDL_AMediaFormat* aformat, const char* name, void* data, size_t size); #endif ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_codec_android_mediaformat_internal.h ================================================ /***************************************************************************** * ijksdl_codec_android_mediaformat_internal.h ***************************************************************************** * * Copyright (c) 2014 Bilibili * copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIAFORMAT_INTERNAL_H #define IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIAFORMAT_INTERNAL_H #include "ijksdl_codec_android_mediaformat.h" inline static SDL_AMediaFormat *SDL_AMediaFormat_CreateInternal(size_t opaque_size) { SDL_AMediaFormat *aformat = (SDL_AMediaFormat*) mallocz(sizeof(SDL_AMediaFormat)); if (!aformat) return NULL; aformat->opaque = mallocz(opaque_size); if (!aformat->opaque) { free(aformat); return NULL; } aformat->mutex = SDL_CreateMutex(); if (aformat->mutex == NULL) { free(aformat->opaque); free(aformat); return NULL; } return aformat; } inline static void SDL_AMediaFormat_FreeInternal(SDL_AMediaFormat *aformat) { if (!aformat) return; if (aformat->mutex) { SDL_DestroyMutexP(&aformat->mutex); } free(aformat->opaque); memset(aformat, 0, sizeof(SDL_AMediaFormat)); free(aformat); } #endif ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_codec_android_mediaformat_java.c ================================================ /***************************************************************************** * ijksdl_codec_android_mediaformat_java.c ***************************************************************************** * * Copyright (c) 2014 Bilibili * copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_codec_android_mediaformat_java.h" #include "j4a/class/android/media/MediaFormat.h" #include "j4au/class/java/nio/ByteBuffer.util.h" #include "ijksdl_android_jni.h" #include "ijksdl_codec_android_mediaformat_internal.h" #include "ijksdl_inc_internal_android.h" typedef struct SDL_AMediaFormat_Opaque { jobject android_media_format; jobject android_byte_buffer; } SDL_AMediaFormat_Opaque; jobject SDL_AMediaFormatJava_getObject(JNIEnv *env, const SDL_AMediaFormat *thiz) { if (!thiz || !thiz->opaque) return NULL; SDL_AMediaFormat_Opaque *opaque = (SDL_AMediaFormat_Opaque *)thiz->opaque; return opaque->android_media_format; } static jobject getAndroidMediaFormat(JNIEnv *env, const SDL_AMediaFormat* thiz) { if (!thiz) return NULL; SDL_AMediaFormat_Opaque *opaque = (SDL_AMediaFormat_Opaque *)thiz->opaque; if (!opaque) return NULL; return opaque->android_media_format; } static sdl_amedia_status_t SDL_AMediaFormatJava_delete(SDL_AMediaFormat* aformat) { if (!aformat) return SDL_AMEDIA_OK; JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SetupThreadEnv failed", __func__); return SDL_AMEDIA_ERROR_UNKNOWN; } SDL_AMediaFormat_Opaque *opaque = (SDL_AMediaFormat_Opaque *)aformat->opaque; if (opaque) { SDL_JNI_DeleteGlobalRefP(env, &opaque->android_byte_buffer); SDL_JNI_DeleteGlobalRefP(env, &opaque->android_media_format); } SDL_AMediaFormat_FreeInternal(aformat); return SDL_AMEDIA_OK; } static bool SDL_AMediaFormatJava_getInt32(SDL_AMediaFormat* aformat, const char* name, int32_t *out) { JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SDL_JNI_SetupThreadEnv: failed", __func__); return false; } jobject android_media_format = getAndroidMediaFormat(env, aformat); if (!android_media_format) { ALOGE("%s: getAndroidMediaFormat: failed", __func__); return false; } jint ret = J4AC_MediaFormat__getInteger__withCString(env, android_media_format, name); if (J4A_ExceptionCheck__catchAll(env)) { ALOGE("%s: CallIntMethod: failed", __func__); return false; } if (out) *out = ret; return true; } static void SDL_AMediaFormatJava_setInt32(SDL_AMediaFormat* aformat, const char* name, int32_t value) { JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SDL_JNI_SetupThreadEnv: failed", __func__); return; } jobject android_media_format = getAndroidMediaFormat(env, aformat); if (!android_media_format) { ALOGE("%s: getAndroidMediaFormat: failed", __func__); return; } J4AC_MediaFormat__setInteger__withCString(env, android_media_format, name, value); if (J4A_ExceptionCheck__catchAll(env)) { ALOGE("%s: CallVoidMethod: failed", __func__); return; } } static void SDL_AMediaFormatJava_setBuffer(SDL_AMediaFormat* aformat, const char* name, void* data, size_t size) { int ret = -1; JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s: SDL_JNI_SetupThreadEnv: failed", __func__); return; } SDL_AMediaFormat_Opaque *opaque = (SDL_AMediaFormat_Opaque *)aformat->opaque; jobject android_media_format = opaque->android_media_format; if (!opaque->android_byte_buffer) { opaque->android_byte_buffer = J4AC_ByteBuffer__allocateDirect__asGlobalRef__catchAll(env, size); if (!opaque->android_byte_buffer) { J4A_FUNC_FAIL_TRACE(); return; } } ret = J4AC_ByteBuffer__assignData__catchAll(env, opaque->android_byte_buffer, data, size); if (ret < 0) { J4A_FUNC_FAIL_TRACE(); return; } J4AC_MediaFormat__setByteBuffer__withCString(env, android_media_format, name, opaque->android_byte_buffer); if (J4A_ExceptionCheck__catchAll(env)) { ALOGE("%s: call jmid_setByteBuffer: failed", __func__); return; } } static void setup_aformat(SDL_AMediaFormat *aformat, jobject android_media_format) { SDL_AMediaFormat_Opaque *opaque = aformat->opaque; opaque->android_media_format = android_media_format; aformat->func_delete = SDL_AMediaFormatJava_delete; aformat->func_getInt32 = SDL_AMediaFormatJava_getInt32; aformat->func_setInt32 = SDL_AMediaFormatJava_setInt32; aformat->func_setBuffer = SDL_AMediaFormatJava_setBuffer; } SDL_AMediaFormat *SDL_AMediaFormatJava_init(JNIEnv *env, jobject android_format) { SDLTRACE("%s", __func__); jobject global_android_media_format = (*env)->NewGlobalRef(env, android_format); if (J4A_ExceptionCheck__catchAll(env) || !global_android_media_format) { return NULL; } SDL_AMediaFormat *aformat = SDL_AMediaFormat_CreateInternal(sizeof(SDL_AMediaFormat_Opaque)); if (!aformat) { SDL_JNI_DeleteGlobalRefP(env, &global_android_media_format); return NULL; } setup_aformat(aformat, global_android_media_format); return aformat; } SDL_AMediaFormat *SDL_AMediaFormatJava_createVideoFormat(JNIEnv *env, const char *mime, int width, int height) { SDLTRACE("%s", __func__); jobject android_media_format = J4AC_MediaFormat__createVideoFormat__withCString__asGlobalRef__catchAll(env, mime, width, height); if (J4A_ExceptionCheck__catchAll(env) || !android_media_format) { return NULL; } SDL_AMediaFormat *aformat = SDL_AMediaFormat_CreateInternal(sizeof(SDL_AMediaFormat_Opaque)); if (!aformat) { SDL_JNI_DeleteGlobalRefP(env, &android_media_format); return NULL; } setup_aformat(aformat, android_media_format); SDL_AMediaFormat_setInt32(aformat, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, 0); return aformat; } ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_codec_android_mediaformat_java.h ================================================ /***************************************************************************** * ijksdl_codec_android_mediaformat_java.h ***************************************************************************** * * Copyright (c) 2014 Bilibili * copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIAFORMAT_JAVA_H #define IJKSDL_ANDROID__ANDROID_CODEC_ANDROID_MEDIAFORMAT_JAVA_H #include "ijksdl_codec_android_mediaformat.h" SDL_AMediaFormat *SDL_AMediaFormatJava_init(JNIEnv *env, jobject android_format); SDL_AMediaFormat *SDL_AMediaFormatJava_createVideoFormat(JNIEnv *env, const char *mime, int width, int height); jobject SDL_AMediaFormatJava_getObject(JNIEnv *env, const SDL_AMediaFormat *thiz); #endif ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_inc_internal_android.h ================================================ /* * ijksdl_inc_internal_android.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKPLAYER__IJKSDL_INC_INTERNAL_ANDROID_H #define IJKPLAYER__IJKSDL_INC_INTERNAL_ANDROID_H #include #include #include "../ijksdl_inc_internal.h" #include "../ijksdl_misc.h" #include "../ijksdl_log.h" enum { HAL_PIXEL_FORMAT_RGBA_8888 = 1, HAL_PIXEL_FORMAT_RGBX_8888 = 2, HAL_PIXEL_FORMAT_RGB_888 = 3, HAL_PIXEL_FORMAT_RGB_565 = 4, HAL_PIXEL_FORMAT_BGRA_8888 = 5, HAL_PIXEL_FORMAT_RGBA_5551 = 6, HAL_PIXEL_FORMAT_RGBA_4444 = 7, /* 0x8 - 0xFF range unavailable */ /* 0x100 - 0x1FF HAL implement */ HAL_PIXEL_FORMAT_YV12 = 0x32315659, // YCrCb 4:2:0 Planar HAL_PIXEL_FORMAT_RAW_SENSOR = 0x20, HAL_PIXEL_FORMAT_BLOB = 0x21, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22, /* Legacy formats (deprecated), used by ImageFormat.java */ HAL_PIXEL_FORMAT_YCbCr_422_SP = 0x10, // NV16 HAL_PIXEL_FORMAT_YCrCb_420_SP = 0x11, // NV21 HAL_PIXEL_FORMAT_YCbCr_422_I = 0x14, // YUY2 }; #endif ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_vout_android_nativewindow.c ================================================ /***************************************************************************** * ijksdl_vout_android_nativewindow.c ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_vout_android_nativewindow.h" #include #include #include "ijksdl/ijksdl_vout.h" #include "ijksdl/ijksdl_vout_internal.h" #include "ijksdl/ijksdl_container.h" #include "ijksdl/ijksdl_egl.h" #include "ijksdl/ffmpeg/ijksdl_vout_overlay_ffmpeg.h" #include "ijksdl_codec_android_mediacodec.h" #include "ijksdl_inc_internal_android.h" #include "ijksdl_vout_overlay_android_mediacodec.h" #include "android_nativewindow.h" #ifndef AMCTRACE #define AMCTRACE(...) #endif struct SDL_AMediaCodecBufferProxy { int buffer_id; int buffer_index; int acodec_serial; SDL_AMediaCodecBufferInfo buffer_info; }; static void SDL_AMediaCodecBufferProxy_reset(SDL_AMediaCodecBufferProxy *proxy) { memset(proxy, 0, sizeof(SDL_AMediaCodecBufferProxy)); proxy->buffer_index = -1; proxy->acodec_serial = 0; } static void SDL_AMediaCodecBufferProxy_init(SDL_AMediaCodecBufferProxy *proxy) { assert(proxy); SDL_AMediaCodecBufferProxy_reset(proxy); } static void SDL_AMediaCodecBufferProxy_destroy(SDL_AMediaCodecBufferProxy *proxy) { if (!proxy) return; SDL_AMediaCodecBufferProxy_reset(proxy); } static void SDL_AMediaCodecBufferProxy_destroyP(SDL_AMediaCodecBufferProxy **proxy) { if (!proxy) return; SDL_AMediaCodecBufferProxy_destroy(*proxy); *proxy = NULL; } static void SDL_AMediaCodecBufferProxy_invalidate(SDL_AMediaCodecBufferProxy *proxy) { SDL_AMediaCodecBufferProxy_reset(proxy); } typedef struct SDL_Vout_Opaque { ANativeWindow *native_window; SDL_AMediaCodec *acodec; int null_native_window_warned; // reduce log for null window int next_buffer_id; ISDL_Array overlay_manager; ISDL_Array overlay_pool; IJK_EGL *egl; } SDL_Vout_Opaque; static SDL_VoutOverlay *func_create_overlay_l(int width, int height, int frame_format, SDL_Vout *vout) { switch (frame_format) { case IJK_AV_PIX_FMT__ANDROID_MEDIACODEC: return SDL_VoutAMediaCodec_CreateOverlay(width, height, vout); default: return SDL_VoutFFmpeg_CreateOverlay(width, height, frame_format, vout); } } static SDL_VoutOverlay *func_create_overlay(int width, int height, int frame_format, SDL_Vout *vout) { SDL_LockMutex(vout->mutex); SDL_VoutOverlay *overlay = func_create_overlay_l(width, height, frame_format, vout); SDL_UnlockMutex(vout->mutex); return overlay; } static void func_free_l(SDL_Vout *vout) { if (!vout) return; SDL_Vout_Opaque *opaque = vout->opaque; if (opaque) { SDL_AMediaCodecBufferProxy **begin = (SDL_AMediaCodecBufferProxy **)ISDL_Array__begin(&opaque->overlay_manager); SDL_AMediaCodecBufferProxy **end = (SDL_AMediaCodecBufferProxy **)ISDL_Array__end(&opaque->overlay_manager); for (; begin < end; ++begin) { SDL_AMediaCodecBufferProxy_destroyP(begin); } 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; } IJK_EGL_freep(&opaque->egl); SDL_AMediaCodec_decreaseReferenceP(&opaque->acodec); } SDL_Vout_FreeInternal(vout); } static int func_display_overlay_l(SDL_Vout *vout, SDL_VoutOverlay *overlay) { SDL_Vout_Opaque *opaque = vout->opaque; ANativeWindow *native_window = opaque->native_window; if (!native_window) { if (!opaque->null_native_window_warned) { opaque->null_native_window_warned = 1; ALOGW("func_display_overlay_l: NULL native_window"); } return -1; } else { opaque->null_native_window_warned = 1; } if (!overlay) { ALOGE("func_display_overlay_l: NULL overlay"); return -1; } if (overlay->w <= 0 || overlay->h <= 0) { ALOGE("func_display_overlay_l: invalid overlay dimensions(%d, %d)", overlay->w, overlay->h); return -1; } switch(overlay->format) { case SDL_FCC__AMC: { // only ANativeWindow support IJK_EGL_terminate(opaque->egl); 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); 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); break; } } // fallback to ANativeWindow IJK_EGL_terminate(opaque->egl); 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); SDL_UnlockMutex(vout->mutex); return retval; } static SDL_Class g_nativewindow_class = { .name = "ANativeWindow_Vout", }; SDL_Vout *SDL_VoutAndroid_CreateForANativeWindow() { SDL_Vout *vout = SDL_Vout_CreateInternal(sizeof(SDL_Vout_Opaque)); if (!vout) return NULL; SDL_Vout_Opaque *opaque = vout->opaque; opaque->native_window = 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) goto fail; vout->opaque_class = &g_nativewindow_class; vout->create_overlay = func_create_overlay; vout->free_l = func_free_l; vout->display_overlay = func_display_overlay; return vout; fail: func_free_l(vout); return NULL; } static void SDL_VoutAndroid_invalidateAllBuffers_l(SDL_Vout *vout) { AMCTRACE("%s\n", __func__); SDL_Vout_Opaque *opaque = vout->opaque; SDL_AMediaCodecBufferProxy **begin = (SDL_AMediaCodecBufferProxy **)ISDL_Array__begin(&opaque->overlay_manager); SDL_AMediaCodecBufferProxy **end = (SDL_AMediaCodecBufferProxy **)ISDL_Array__end(&opaque->overlay_manager); for (; begin < end; ++begin) { SDL_AMediaCodecBufferProxy_invalidate(*begin); } } void SDL_VoutAndroid_invalidateAllBuffers(SDL_Vout *vout) { SDL_LockMutex(vout->mutex); SDL_VoutAndroid_invalidateAllBuffers_l(vout); SDL_UnlockMutex(vout->mutex); } static void SDL_VoutAndroid_SetNativeWindow_l(SDL_Vout *vout, ANativeWindow *native_window) { AMCTRACE("%s(%p, %p)\n", __func__, vout, native_window); SDL_Vout_Opaque *opaque = vout->opaque; if (opaque->native_window == native_window) { if (native_window == NULL) { // always invalidate buffers, if native_window is changed SDL_VoutAndroid_invalidateAllBuffers_l(vout); } return; } IJK_EGL_terminate(opaque->egl); SDL_VoutAndroid_invalidateAllBuffers_l(vout); if (opaque->native_window) ANativeWindow_release(opaque->native_window); if (native_window) ANativeWindow_acquire(native_window); opaque->native_window = native_window; opaque->null_native_window_warned = 0; } void SDL_VoutAndroid_SetNativeWindow(SDL_Vout *vout, ANativeWindow *native_window) { SDL_LockMutex(vout->mutex); SDL_VoutAndroid_SetNativeWindow_l(vout, native_window); SDL_UnlockMutex(vout->mutex); } static void SDL_VoutAndroid_setAMediaCodec_l(SDL_Vout *vout, SDL_AMediaCodec *acodec) { AMCTRACE("%s(%p)\n", __func__, acodec); SDL_Vout_Opaque *opaque = vout->opaque; if (opaque->acodec == acodec) return; SDL_VoutAndroid_invalidateAllBuffers_l(vout); SDL_AMediaCodec_decreaseReferenceP(&opaque->acodec); opaque->acodec = acodec; if (opaque->acodec) SDL_AMediaCodec_increaseReference(opaque->acodec); } void SDL_VoutAndroid_setAMediaCodec(SDL_Vout *vout, SDL_AMediaCodec *acodec) { SDL_LockMutex(vout->mutex); SDL_VoutAndroid_setAMediaCodec_l(vout, acodec); SDL_UnlockMutex(vout->mutex); } SDL_AMediaCodec *SDL_VoutAndroid_peekAMediaCodec(SDL_Vout *vout) { SDL_Vout_Opaque *opaque = vout->opaque; SDL_AMediaCodec *acodec = NULL; SDL_LockMutex(vout->mutex); acodec = opaque->acodec; SDL_UnlockMutex(vout->mutex); return acodec; } static SDL_AMediaCodecBufferProxy *SDL_VoutAndroid_obtainBufferProxy_l(SDL_Vout *vout, int acodec_serial, int buffer_index, SDL_AMediaCodecBufferInfo *buffer_info) { SDL_Vout_Opaque *opaque = vout->opaque; SDL_AMediaCodecBufferProxy *proxy = NULL; if (ISDL_Array__size(&opaque->overlay_pool) > 0) { proxy = ISDL_Array__pop_back(&opaque->overlay_pool); SDL_AMediaCodecBufferProxy_reset(proxy); } else { proxy = (SDL_AMediaCodecBufferProxy *)mallocz(sizeof(SDL_AMediaCodecBufferProxy)); if (!proxy) return NULL; SDL_AMediaCodecBufferProxy_init(proxy); ISDL_Array__push_back(&opaque->overlay_manager, proxy); } proxy->buffer_id = opaque->next_buffer_id++; proxy->acodec_serial = acodec_serial; proxy->buffer_index = buffer_index; proxy->buffer_info = *buffer_info; AMCTRACE("%s: [%d] ++++++++ proxy %d: vout: %d idx: %d fake: %s", __func__, proxy->buffer_id, proxy->acodec_serial, SDL_AMediaCodec_getSerial(opaque->acodec), proxy->buffer_index, (proxy->buffer_info.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME) ? "YES" : "NO"); return proxy; } SDL_AMediaCodecBufferProxy *SDL_VoutAndroid_obtainBufferProxy(SDL_Vout *vout, int acodec_serial, int buffer_index, SDL_AMediaCodecBufferInfo *buffer_info) { SDL_AMediaCodecBufferProxy *proxy = NULL; SDL_LockMutex(vout->mutex); proxy = SDL_VoutAndroid_obtainBufferProxy_l(vout, acodec_serial, buffer_index, buffer_info); SDL_UnlockMutex(vout->mutex); return proxy; } static int SDL_VoutAndroid_releaseBufferProxy_l(SDL_Vout *vout, SDL_AMediaCodecBufferProxy *proxy, bool render) { SDL_Vout_Opaque *opaque = vout->opaque; if (!proxy) return 0; AMCTRACE("%s: [%d] -------- proxy %d: vout: %d idx: %d render: %s fake: %s", __func__, proxy->buffer_id, proxy->acodec_serial, SDL_AMediaCodec_getSerial(opaque->acodec), proxy->buffer_index, render ? "true" : "false", (proxy->buffer_info.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME) ? "YES" : "NO"); ISDL_Array__push_back(&opaque->overlay_pool, proxy); if (!SDL_AMediaCodec_isSameSerial(opaque->acodec, proxy->acodec_serial)) { ALOGW("%s: [%d] ???????? proxy %d: vout: %d idx: %d render: %s fake: %s", __func__, proxy->buffer_id, proxy->acodec_serial, SDL_AMediaCodec_getSerial(opaque->acodec), proxy->buffer_index, render ? "true" : "false", (proxy->buffer_info.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME) ? "YES" : "NO"); return 0; } if (proxy->buffer_index < 0) { ALOGE("%s: [%d] invalid AMediaCodec buffer index %d\n", __func__, proxy->buffer_id, proxy->buffer_index); return 0; } else if (proxy->buffer_info.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME) { proxy->buffer_index = -1; return 0; } sdl_amedia_status_t amc_ret = SDL_AMediaCodec_releaseOutputBuffer(opaque->acodec, proxy->buffer_index, render); if (amc_ret != SDL_AMEDIA_OK) { ALOGW("%s: [%d] !!!!!!!! proxy %d: vout: %d idx: %d render: %s, fake: %s", __func__, proxy->buffer_id, proxy->acodec_serial, SDL_AMediaCodec_getSerial(opaque->acodec), proxy->buffer_index, render ? "true" : "false", (proxy->buffer_info.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME) ? "YES" : "NO"); proxy->buffer_index = -1; return -1; } proxy->buffer_index = -1; return 0; } static int SDL_VoutAndroid_releaseBufferProxy(SDL_Vout *vout, SDL_AMediaCodecBufferProxy *proxy, bool render) { int ret = 0; if (!proxy) return 0; SDL_LockMutex(vout->mutex); ret = SDL_VoutAndroid_releaseBufferProxy_l(vout, proxy, render); SDL_UnlockMutex(vout->mutex); return ret; } int SDL_VoutAndroid_releaseBufferProxyP(SDL_Vout *vout, SDL_AMediaCodecBufferProxy **proxy, bool render) { int ret = 0; if (!proxy) return 0; ret = SDL_VoutAndroid_releaseBufferProxy(vout, *proxy, render); *proxy = NULL; return ret; } int SDL_VoutAndroid_releaseBufferProxyP_l(SDL_Vout *vout, SDL_AMediaCodecBufferProxy **proxy, bool render) { int ret = 0; if (!proxy) return 0; ret = SDL_VoutAndroid_releaseBufferProxy_l(vout, *proxy, render); *proxy = NULL; return ret; } ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_vout_android_nativewindow.h ================================================ /***************************************************************************** * ijksdl_vout_android_nativewindow.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_ANDROID__IJKSDL_VOUT_ANDROID_NATIVEWINDOW_H #define IJKSDL_ANDROID__IJKSDL_VOUT_ANDROID_NATIVEWINDOW_H #include "../ijksdl_stdinc.h" #include "../ijksdl_vout.h" 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_setAMediaCodec(SDL_Vout *vout, SDL_AMediaCodec *acodec); SDL_AMediaCodec *SDL_VoutAndroid_peekAMediaCodec(SDL_Vout *vout); void SDL_VoutAndroid_invalidateAllBuffers(SDL_Vout *vout); /* * MediaCodec buffer proxy */ typedef struct SDL_AMediaCodecBufferInfo SDL_AMediaCodecBufferInfo; typedef struct SDL_AMediaCodecBufferProxy SDL_AMediaCodecBufferProxy; void SDL_AMediaCodecBufferProxy_lock(SDL_AMediaCodecBufferProxy *proxy); void SDL_AMediaCodecBufferProxy_unlock(SDL_AMediaCodecBufferProxy *proxy); SDL_AMediaCodecBufferProxy *SDL_VoutAndroid_obtainBufferProxy(SDL_Vout *vout, int acodec_serial, int buffer_index, SDL_AMediaCodecBufferInfo *buffer_info); int SDL_VoutAndroid_releaseBufferProxyP(SDL_Vout *vout, SDL_AMediaCodecBufferProxy **proxy, bool render); int SDL_VoutAndroid_releaseBufferProxyP_l(SDL_Vout *vout, SDL_AMediaCodecBufferProxy **proxy, bool render); #endif ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_vout_android_surface.c ================================================ /***************************************************************************** * ijksdl_vout_android_surface.c ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_vout_android_surface.h" #include #include "../ijksdl_inc_internal.h" #include "ijksdl_android_jni.h" #include "ijksdl_vout_android_nativewindow.h" SDL_Vout *SDL_VoutAndroid_CreateForAndroidSurface() { return SDL_VoutAndroid_CreateForANativeWindow(); } void SDL_VoutAndroid_SetAndroidSurface(JNIEnv *env, SDL_Vout *vout, jobject android_surface) { ANativeWindow *native_window = NULL; if (android_surface) { native_window = ANativeWindow_fromSurface(env, android_surface); if (!native_window) { ALOGE("%s: ANativeWindow_fromSurface: failed\n", __func__); // do not return fail here; } } SDL_VoutAndroid_SetNativeWindow(vout, native_window); if (native_window) ANativeWindow_release(native_window); } ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_vout_android_surface.h ================================================ /***************************************************************************** * ijksdl_vout_android_surface.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_ANDROID__IJKSDL_VOUT_ANDROID_SURFACE_H #define IJKSDL_ANDROID__IJKSDL_VOUT_ANDROID_SURFACE_H #include #include "../ijksdl_stdinc.h" #include "../ijksdl_vout.h" SDL_Vout *SDL_VoutAndroid_CreateForAndroidSurface(); void SDL_VoutAndroid_SetAndroidSurface(JNIEnv*env, SDL_Vout *vout, jobject android_surface); #endif ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_vout_overlay_android_mediacodec.c ================================================ /***************************************************************************** * ijksdl_vout_overlay_android_mediacodec.c ***************************************************************************** * * Copyright (c) 2014 Bilibili * copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_vout_overlay_android_mediacodec.h" #include #include "ijksdl/ijksdl_stdinc.h" #include "ijksdl/ijksdl_mutex.h" #include "ijksdl/ijksdl_vout_internal.h" #include "ijksdl/ijksdl_video.h" #include "ijksdl_vout_android_nativewindow.h" #include "ijksdl_codec_android_mediacodec.h" #include "ijksdl_inc_internal_android.h" #ifndef AMCTRACE #define AMCTRACE(...) #endif typedef struct SDL_VoutOverlay_Opaque { SDL_mutex *mutex; SDL_Vout *vout; SDL_AMediaCodec *acodec; SDL_AMediaCodecBufferProxy *buffer_proxy; Uint16 pitches[AV_NUM_DATA_POINTERS]; Uint8 *pixels[AV_NUM_DATA_POINTERS]; } SDL_VoutOverlay_Opaque; static int overlay_lock(SDL_VoutOverlay *overlay) { SDL_VoutOverlay_Opaque *opaque = overlay->opaque; return SDL_LockMutex(opaque->mutex); } static int overlay_unlock(SDL_VoutOverlay *overlay) { SDL_VoutOverlay_Opaque *opaque = overlay->opaque; return SDL_UnlockMutex(opaque->mutex); } static void overlay_unref(SDL_VoutOverlay *overlay) { SDL_VoutOverlay_Opaque *opaque = overlay->opaque; SDL_VoutAndroid_releaseBufferProxyP(opaque->vout, &opaque->buffer_proxy, false); } static void overlay_free_l(SDL_VoutOverlay *overlay) { AMCTRACE("SDL_Overlay(mediacodec): overlay_free_l(%p)\n", overlay); if (!overlay) return; SDL_VoutOverlay_Opaque *opaque = overlay->opaque; if (!opaque) return; overlay_unref(overlay); if (opaque->mutex) SDL_DestroyMutex(opaque->mutex); SDL_VoutOverlay_FreeInternal(overlay); } static SDL_Class g_vout_overlay_amediacodec_class = { .name = "AndroidMediaCodecVoutOverlay", }; inline static bool check_object(SDL_VoutOverlay* object, const char *func_name) { if (!object || !object->opaque || !object->opaque_class) { ALOGE("%s.%s: invalid pipeline\n", object->opaque_class->name, func_name); return false; } if (object->opaque_class != &g_vout_overlay_amediacodec_class) { ALOGE("%s.%s: unsupported method\n", object->opaque_class->name, func_name); return false; } return true; } static int func_fill_frame(SDL_VoutOverlay *overlay, const AVFrame *frame) { assert(frame->format == IJK_AV_PIX_FMT__ANDROID_MEDIACODEC); SDL_VoutOverlay_Opaque *opaque = overlay->opaque; if (!check_object(overlay, __func__)) return -1; if (opaque->buffer_proxy) SDL_VoutAndroid_releaseBufferProxyP(opaque->vout, (SDL_AMediaCodecBufferProxy **)&opaque->buffer_proxy, false); opaque->acodec = SDL_VoutAndroid_peekAMediaCodec(opaque->vout); // TODO: ref-count buffer_proxy? opaque->buffer_proxy = (SDL_AMediaCodecBufferProxy *)frame->opaque; overlay->opaque_class = &g_vout_overlay_amediacodec_class; overlay->format = SDL_FCC__AMC; overlay->planes = 1; overlay->pixels[0] = NULL; overlay->pixels[1] = NULL; overlay->pitches[0] = 0; overlay->pitches[1] = 0; overlay->is_private = 1; overlay->w = (int)frame->width; overlay->h = (int)frame->height; return 0; } SDL_VoutOverlay *SDL_VoutAMediaCodec_CreateOverlay(int width, int height, SDL_Vout *vout) { SDLTRACE("SDL_VoutAMediaCodec_CreateOverlay(w=%d, h=%d, fmt=_AMC vout=%p)\n", width, height, vout); SDL_VoutOverlay *overlay = SDL_VoutOverlay_CreateInternal(sizeof(SDL_VoutOverlay_Opaque)); if (!overlay) { ALOGE("overlay allocation failed"); return NULL; } SDL_VoutOverlay_Opaque *opaque = overlay->opaque; opaque->mutex = SDL_CreateMutex(); opaque->vout = vout; opaque->acodec = NULL; opaque->buffer_proxy = NULL; overlay->opaque_class = &g_vout_overlay_amediacodec_class; overlay->format = SDL_FCC__AMC; overlay->pitches = opaque->pitches; overlay->pixels = opaque->pixels; overlay->w = width; overlay->h = height; overlay->is_private = 1; overlay->free_l = overlay_free_l; overlay->lock = overlay_lock; overlay->unlock = overlay_unlock; overlay->unref = overlay_unref; overlay->func_fill_frame = func_fill_frame; if (!opaque->mutex) { ALOGE("SDL_CreateMutex failed"); goto fail; } return overlay; fail: overlay_free_l(overlay); return NULL; } bool SDL_VoutOverlayAMediaCodec_isKindOf(SDL_VoutOverlay *overlay) { return check_object(overlay, __func__); } int SDL_VoutOverlayAMediaCodec_releaseFrame_l(SDL_VoutOverlay *overlay, SDL_AMediaCodec *acodec, bool render) { if (!check_object(overlay, __func__)) return -1; SDL_VoutOverlay_Opaque *opaque = overlay->opaque; return SDL_VoutAndroid_releaseBufferProxyP_l(opaque->vout, &opaque->buffer_proxy, render); } ================================================ FILE: ijkmedia/ijksdl/android/ijksdl_vout_overlay_android_mediacodec.h ================================================ /***************************************************************************** * ijksdl_vout_overlay_android_mediacodec.h ***************************************************************************** * * Copyright (c) 2014 Bilibili * copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_ANDROID__IJKSDL_VOUT_OVERLAY_ANDROID_MEDIACODEC_H #define IJKSDL_ANDROID__IJKSDL_VOUT_OVERLAY_ANDROID_MEDIACODEC_H #include "../ijksdl_stdinc.h" #include "../ijksdl_vout.h" typedef struct SDL_AMediaCodec SDL_AMediaCodec; typedef struct SDL_AMediaCodecBufferInfo SDL_AMediaCodecBufferInfo; SDL_VoutOverlay *SDL_VoutAMediaCodec_CreateOverlay(int width, int height, SDL_Vout *vout); bool SDL_VoutOverlayAMediaCodec_isKindOf(SDL_VoutOverlay *overlay); int SDL_VoutOverlayAMediaCodec_releaseFrame_l(SDL_VoutOverlay *overlay, SDL_AMediaCodec *acodec, bool render); #endif ================================================ FILE: ijkmedia/ijksdl/dummy/ijksdl_dummy.h ================================================ /***************************************************************************** * ijksdl_dummy.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_DUMMY__IJKSDL_DUMMY_H #define IJKSDL_DUMMY__IJKSDL_DUMMY_H #include "../ijksdl.h" // #include "ijksdl_aout_dummy.h" #include "ijksdl_vout_dummy.h" #endif ================================================ FILE: ijkmedia/ijksdl/dummy/ijksdl_vout_dummy.c ================================================ /***************************************************************************** * ijksdl_vout_dummy.c ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_vout_dummy.h" #include "../ijksdl_vout.h" #include "../ijksdl_vout_internal.h" typedef struct SDL_VoutSurface_Opaque { SDL_Vout *vout; } SDL_VoutSurface_Opaque; struct SDL_Vout_Opaque { char dummy; }; static void func_free_l(SDL_Vout *vout) { if (!vout) return; SDL_Vout_Opaque *opaque = vout->opaque; if (opaque) { } SDL_Vout_FreeInternal(vout); } static int func_display_overlay_l(SDL_Vout *vout, SDL_VoutOverlay *overlay) { return 0; } static int func_display_overlay(SDL_Vout *vout, SDL_VoutOverlay *overlay) { SDL_LockMutex(vout->mutex); int retval = func_display_overlay_l(vout, overlay); SDL_UnlockMutex(vout->mutex); return retval; } SDL_Vout *SDL_VoutDummy_Create() { SDL_Vout *vout = SDL_Vout_CreateInternal(sizeof(SDL_Vout_Opaque)); if (!vout) return NULL; // SDL_Vout_Opaque *opaque = vout->opaque; vout->free_l = func_free_l; vout->display_overlay = func_display_overlay; return vout; } ================================================ FILE: ijkmedia/ijksdl/dummy/ijksdl_vout_dummy.h ================================================ /***************************************************************************** * ijksdl_vout_dummy.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL_DUMMY__IJKSDL_VOUT_DUMMY_H #define IJKSDL_DUMMY__IJKSDL_VOUT_DUMMY_H #include "../ijksdl_stdinc.h" #include "../ijksdl_vout.h" SDL_Vout *SDL_VoutDummy_Create(); #endif ================================================ FILE: ijkmedia/ijksdl/ffmpeg/abi_all/image_convert.c ================================================ /***************************************************************************** * yuv_rgb.c : ARM NEONv1 YUV to RGB32 chroma conversion for VLC ***************************************************************************** * Copyright (C) 2011 Bilibili * Copyright (C) 2011 Sébastien Toque * Rémi Denis-Courmont * Copyright (C) 2013 Zhang Rui * * This program 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. * * This program 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 this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ #include "../ijksdl_image_convert.h" #if defined(__ANDROID__) #include "libyuv.h" #endif 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) { #if defined(__ANDROID__) switch (src_format) { 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( 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); case AV_PIX_FMT_0BGR32: return 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); default: break; } break; default: break; } #endif return -1; } ================================================ FILE: ijkmedia/ijksdl/ffmpeg/ijksdl_image_convert.h ================================================ /* * ijksdl_ffinc.h * ffmpeg headers * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__FFMPEG__IJKSDL_IMAGE_CONVERT_H #define IJKSDL__FFMPEG__IJKSDL_IMAGE_CONVERT_H #include #include "ijksdl_inc_ffmpeg.h" 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); #endif ================================================ FILE: ijkmedia/ijksdl/ffmpeg/ijksdl_inc_ffmpeg.h ================================================ /* * ijksdl_ffinc.h * ffmpeg headers * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__FFMPEG__IJKSDL_FFINC_H #define IJKSDL__FFMPEG__IJKSDL_FFINC_H #include "libavutil/imgutils.h" #include "libavutil/pixfmt.h" #include "libavutil/frame.h" #include "libavutil/common.h" #include "libavcodec/avcodec.h" #include "libswscale/swscale.h" #include "../ijksdl_inc_internal.h" #endif ================================================ FILE: ijkmedia/ijksdl/ffmpeg/ijksdl_vout_overlay_ffmpeg.c ================================================ /***************************************************************************** * ijksdl_vout_overlay_ffmpeg.c ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_vout_overlay_ffmpeg.h" #include #include #include "../ijksdl_stdinc.h" #include "../ijksdl_misc.h" #include "../ijksdl_mutex.h" #include "../ijksdl_vout_internal.h" #include "../ijksdl_video.h" #include "ijksdl_inc_ffmpeg.h" #include "ijksdl_image_convert.h" struct SDL_VoutOverlay_Opaque { SDL_mutex *mutex; AVFrame *managed_frame; AVBufferRef *frame_buffer; int planes; AVFrame *linked_frame; Uint16 pitches[AV_NUM_DATA_POINTERS]; Uint8 *pixels[AV_NUM_DATA_POINTERS]; int no_neon_warned; struct SwsContext *img_convert_ctx; int sws_flags; }; /* Always assume a linesize alignment of 1 here */ // TODO: 9 alignment to speed up memcpy when display static AVFrame *opaque_setup_frame(SDL_VoutOverlay_Opaque* opaque, enum AVPixelFormat format, int width, int height) { AVFrame *managed_frame = av_frame_alloc(); if (!managed_frame) { return NULL; } AVFrame *linked_frame = av_frame_alloc(); if (!linked_frame) { av_frame_free(&managed_frame); return NULL; } /*- * Lazily allocate frame buffer in opaque_obtain_managed_frame_buffer * * For refererenced frame management, we use buffer allocated by decoder * int frame_bytes = avpicture_get_size(format, width, height); AVBufferRef *frame_buffer_ref = av_buffer_alloc(frame_bytes); if (!frame_buffer_ref) return NULL; opaque->frame_buffer = frame_buffer_ref; */ managed_frame->format = format; managed_frame->width = width; managed_frame->height = height; av_image_fill_arrays(managed_frame->data, managed_frame->linesize ,NULL, format, width, height, 1); opaque->managed_frame = managed_frame; opaque->linked_frame = linked_frame; return managed_frame; } static AVFrame *opaque_obtain_managed_frame_buffer(SDL_VoutOverlay_Opaque* opaque) { if (opaque->frame_buffer != NULL) return opaque->managed_frame; AVFrame *managed_frame = opaque->managed_frame; int frame_bytes = av_image_get_buffer_size(managed_frame->format, managed_frame->width, managed_frame->height, 1); AVBufferRef *frame_buffer_ref = av_buffer_alloc(frame_bytes); if (!frame_buffer_ref) return NULL; av_image_fill_arrays(managed_frame->data, managed_frame->linesize, frame_buffer_ref->data, managed_frame->format, managed_frame->width, managed_frame->height, 1); opaque->frame_buffer = frame_buffer_ref; return opaque->managed_frame; } static void func_free_l(SDL_VoutOverlay *overlay) { ALOGE("SDL_Overlay(ffmpeg): overlay_free_l(%p)\n", overlay); if (!overlay) return; SDL_VoutOverlay_Opaque *opaque = overlay->opaque; if (!opaque) return; sws_freeContext(opaque->img_convert_ctx); if (opaque->managed_frame) av_frame_free(&opaque->managed_frame); if (opaque->linked_frame) { av_frame_unref(opaque->linked_frame); av_frame_free(&opaque->linked_frame); } if (opaque->frame_buffer) av_buffer_unref(&opaque->frame_buffer); if (opaque->mutex) SDL_DestroyMutex(opaque->mutex); SDL_VoutOverlay_FreeInternal(overlay); } static void overlay_fill(SDL_VoutOverlay *overlay, AVFrame *frame, int planes) { overlay->planes = planes; for (int i = 0; i < AV_NUM_DATA_POINTERS; ++i) { overlay->pixels[i] = frame->data[i]; overlay->pitches[i] = frame->linesize[i]; } } static int func_lock(SDL_VoutOverlay *overlay) { SDL_VoutOverlay_Opaque *opaque = overlay->opaque; return SDL_LockMutex(opaque->mutex); } static int func_unlock(SDL_VoutOverlay *overlay) { SDL_VoutOverlay_Opaque *opaque = overlay->opaque; return SDL_UnlockMutex(opaque->mutex); } static int func_fill_frame(SDL_VoutOverlay *overlay, const AVFrame *frame) { assert(overlay); SDL_VoutOverlay_Opaque *opaque = overlay->opaque; AVFrame swscale_dst_pic = { { 0 } }; av_frame_unref(opaque->linked_frame); int need_swap_uv = 0; int use_linked_frame = 0; enum AVPixelFormat dst_format = AV_PIX_FMT_NONE; switch (overlay->format) { case SDL_FCC_YV12: need_swap_uv = 1; // no break; case SDL_FCC_I420: if (frame->format == AV_PIX_FMT_YUV420P || frame->format == AV_PIX_FMT_YUVJ420P) { // ALOGE("direct draw frame"); use_linked_frame = 1; dst_format = frame->format; } else { // ALOGE("copy draw frame"); dst_format = AV_PIX_FMT_YUV420P; } break; case SDL_FCC_I444P10LE: if (frame->format == AV_PIX_FMT_YUV444P10LE) { // ALOGE("direct draw frame"); use_linked_frame = 1; dst_format = frame->format; } else { // ALOGE("copy draw frame"); dst_format = AV_PIX_FMT_YUV444P10LE; } break; case SDL_FCC_RV32: dst_format = AV_PIX_FMT_0BGR32; break; case SDL_FCC_RV24: dst_format = AV_PIX_FMT_RGB24; break; case SDL_FCC_RV16: dst_format = AV_PIX_FMT_RGB565; break; default: ALOGE("SDL_VoutFFmpeg_ConvertPicture: unexpected overlay format %s(%d)", (char*)&overlay->format, overlay->format); return -1; } // setup frame if (use_linked_frame) { // linked frame av_frame_ref(opaque->linked_frame, frame); overlay_fill(overlay, opaque->linked_frame, opaque->planes); if (need_swap_uv) FFSWAP(Uint8*, overlay->pixels[1], overlay->pixels[2]); } else { // managed frame AVFrame* managed_frame = opaque_obtain_managed_frame_buffer(opaque); if (!managed_frame) { ALOGE("OOM in opaque_obtain_managed_frame_buffer"); return -1; } overlay_fill(overlay, opaque->managed_frame, opaque->planes); // setup frame managed for (int i = 0; i < overlay->planes; ++i) { swscale_dst_pic.data[i] = overlay->pixels[i]; swscale_dst_pic.linesize[i] = overlay->pitches[i]; } if (need_swap_uv) FFSWAP(Uint8*, swscale_dst_pic.data[1], swscale_dst_pic.data[2]); } // swscale / direct draw /* ALOGE("ijk_image_convert w=%d, h=%d, df=%d, dd=%d, dl=%d, sf=%d, sd=%d, sl=%d", (int)frame->width, (int)frame->height, (int)dst_format, (int)swscale_dst_pic.data[0], (int)swscale_dst_pic.linesize[0], (int)frame->format, (int)(const uint8_t**) frame->data, (int)frame->linesize); */ if (use_linked_frame) { // do nothing } else if (ijk_image_convert(frame->width, frame->height, dst_format, swscale_dst_pic.data, swscale_dst_pic.linesize, frame->format, (const uint8_t**) frame->data, frame->linesize)) { opaque->img_convert_ctx = sws_getCachedContext(opaque->img_convert_ctx, frame->width, frame->height, frame->format, frame->width, frame->height, dst_format, opaque->sws_flags, NULL, NULL, NULL); if (opaque->img_convert_ctx == NULL) { ALOGE("sws_getCachedContext failed"); return -1; } sws_scale(opaque->img_convert_ctx, (const uint8_t**) frame->data, frame->linesize, 0, frame->height, swscale_dst_pic.data, swscale_dst_pic.linesize); 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)); } } // TODO: 9 draw black if overlay is larger than screen return 0; } static SDL_Class g_vout_overlay_ffmpeg_class = { .name = "FFmpegVoutOverlay", }; #ifndef __clang_analyzer__ SDL_VoutOverlay *SDL_VoutFFmpeg_CreateOverlay(int width, int height, int frame_format, SDL_Vout *display) { Uint32 overlay_format = display->overlay_format; switch (overlay_format) { case SDL_FCC__GLES2: { switch (frame_format) { case AV_PIX_FMT_YUV444P10LE: overlay_format = SDL_FCC_I444P10LE; break; case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUVJ420P: default: #if defined(__ANDROID__) overlay_format = SDL_FCC_YV12; #else overlay_format = SDL_FCC_I420; #endif break; } break; } } SDLTRACE("SDL_VoutFFmpeg_CreateOverlay(w=%d, h=%d, fmt=%.4s(0x%x, dp=%p)\n", width, height, (const char*) &overlay_format, overlay_format, display); SDL_VoutOverlay *overlay = SDL_VoutOverlay_CreateInternal(sizeof(SDL_VoutOverlay_Opaque)); if (!overlay) { ALOGE("overlay allocation failed"); return NULL; } SDL_VoutOverlay_Opaque *opaque = overlay->opaque; opaque->mutex = SDL_CreateMutex(); opaque->sws_flags = SWS_BILINEAR; overlay->opaque_class = &g_vout_overlay_ffmpeg_class; overlay->format = overlay_format; overlay->pitches = opaque->pitches; overlay->pixels = opaque->pixels; overlay->w = width; overlay->h = height; overlay->free_l = func_free_l; overlay->lock = func_lock; overlay->unlock = func_unlock; overlay->func_fill_frame = func_fill_frame; enum AVPixelFormat ff_format = AV_PIX_FMT_NONE; int buf_width = width; int buf_height = height; switch (overlay_format) { case SDL_FCC_I420: case SDL_FCC_YV12: { ff_format = AV_PIX_FMT_YUV420P; // FIXME: need runtime config #if defined(__ANDROID__) // 16 bytes align pitch for arm-neon image-convert buf_width = IJKALIGN(width, 16); // 1 bytes per pixel for Y-plane #elif defined(__APPLE__) // 2^n align for width buf_width = width; if (width > 0) buf_width = 1 << (sizeof(int) * 8 - __builtin_clz(width)); #else buf_width = IJKALIGN(width, 16); // unknown platform #endif opaque->planes = 3; break; } case SDL_FCC_I444P10LE: { ff_format = AV_PIX_FMT_YUV444P10LE; // FIXME: need runtime config #if defined(__ANDROID__) // 16 bytes align pitch for arm-neon image-convert buf_width = IJKALIGN(width, 16); // 1 bytes per pixel for Y-plane #elif defined(__APPLE__) // 2^n align for width buf_width = width; if (width > 0) buf_width = 1 << (sizeof(int) * 8 - __builtin_clz(width)); #else buf_width = IJKALIGN(width, 16); // unknown platform #endif opaque->planes = 3; break; } case SDL_FCC_RV16: { ff_format = AV_PIX_FMT_RGB565; buf_width = IJKALIGN(width, 8); // 2 bytes per pixel opaque->planes = 1; break; } case SDL_FCC_RV24: { ff_format = AV_PIX_FMT_RGB24; #if defined(__ANDROID__) // 16 bytes align pitch for arm-neon image-convert buf_width = IJKALIGN(width, 16); // 1 bytes per pixel for Y-plane #elif defined(__APPLE__) buf_width = width; #else buf_width = IJKALIGN(width, 16); // unknown platform #endif opaque->planes = 1; break; } case SDL_FCC_RV32: { ff_format = AV_PIX_FMT_0BGR32; buf_width = IJKALIGN(width, 4); // 4 bytes per pixel opaque->planes = 1; break; } default: ALOGE("SDL_VoutFFmpeg_CreateOverlay(...): unknown format %.4s(0x%x)\n", (char*)&overlay_format, overlay_format); goto fail; } opaque->managed_frame = opaque_setup_frame(opaque, ff_format, buf_width, buf_height); if (!opaque->managed_frame) { ALOGE("overlay->opaque->frame allocation failed\n"); goto fail; } overlay_fill(overlay, opaque->managed_frame, opaque->planes); return overlay; fail: func_free_l(overlay); return NULL; } #endif//__clang_analyzer__ ================================================ FILE: ijkmedia/ijksdl/ffmpeg/ijksdl_vout_overlay_ffmpeg.h ================================================ /***************************************************************************** * ijksdl_vout_overlay_ffmpeg.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__FFMPEG__IJKSDL_VOUT_OVERLAY_FFMPEG_H #define IJKSDL__FFMPEG__IJKSDL_VOUT_OVERLAY_FFMPEG_H #include "../ijksdl_stdinc.h" #include "../ijksdl_vout.h" #include "ijksdl_inc_ffmpeg.h" // TODO: 9 alignment to speed up memcpy when display SDL_VoutOverlay *SDL_VoutFFmpeg_CreateOverlay(int width, int height, int frame_format, SDL_Vout *vout); #endif ================================================ FILE: ijkmedia/ijksdl/gles2/color.c ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "internal.h" // BT.709, which is the standard for HDTV. static const GLfloat g_bt709[] = { 1.164, 1.164, 1.164, 0.0, -0.213, 2.112, 1.793, -0.533, 0.0, }; const GLfloat *IJK_GLES2_getColorMatrix_bt709() { return g_bt709; } static const GLfloat g_bt601[] = { 1.164, 1.164, 1.164, 0.0, -0.392, 2.017, 1.596, -0.813, 0.0, }; const GLfloat *IJK_GLES2_getColorMatrix_bt601() { return g_bt601; } ================================================ FILE: ijkmedia/ijksdl/gles2/common.c ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "internal.h" void IJK_GLES2_checkError(const char* op) { for (GLint error = glGetError(); error; error = glGetError()) { ALOGE("[GLES2] after %s() glError (0x%x)\n", op, error); } } void IJK_GLES2_printString(const char *name, GLenum s) { const char *v = (const char *) glGetString(s); ALOGI("[GLES2] %s = %s\n", name, v); } void IJK_GLES2_loadOrtho(IJK_GLES_Matrix *matrix, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far) { GLfloat r_l = right - left; GLfloat t_b = top - bottom; GLfloat f_n = far - near; GLfloat tx = - (right + left) / (right - left); GLfloat ty = - (top + bottom) / (top - bottom); GLfloat tz = - (far + near) / (far - near); matrix->m[0] = 2.0f / r_l; matrix->m[1] = 0.0f; matrix->m[2] = 0.0f; matrix->m[3] = 0.0f; matrix->m[4] = 0.0f; matrix->m[5] = 2.0f / t_b; matrix->m[6] = 0.0f; matrix->m[7] = 0.0f; matrix->m[8] = 0.0f; matrix->m[9] = 0.0f; matrix->m[10] = -2.0f / f_n; matrix->m[11] = 0.0f; matrix->m[12] = tx; matrix->m[13] = ty; matrix->m[14] = tz; matrix->m[15] = 1.0f; } ================================================ FILE: ijkmedia/ijksdl/gles2/fsh/rgb.fsh.c ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl/gles2/internal.h" static const char g_shader[] = IJK_GLES_STRING( precision highp float; varying highp vec2 vv2_Texcoord; uniform lowp sampler2D us2_SamplerX; void main() { gl_FragColor = vec4(texture2D(us2_SamplerX, vv2_Texcoord).rgb, 1); } ); const char *IJK_GLES2_getFragmentShader_rgb() { return g_shader; } ================================================ FILE: ijkmedia/ijksdl/gles2/fsh/yuv420p.fsh.c ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl/gles2/internal.h" static const char g_shader[] = IJK_GLES_STRING( precision highp float; varying highp vec2 vv2_Texcoord; uniform mat3 um3_ColorConversion; uniform lowp sampler2D us2_SamplerX; uniform lowp sampler2D us2_SamplerY; uniform lowp sampler2D us2_SamplerZ; void main() { mediump vec3 yuv; lowp vec3 rgb; yuv.x = (texture2D(us2_SamplerX, vv2_Texcoord).r - (16.0 / 255.0)); yuv.y = (texture2D(us2_SamplerY, vv2_Texcoord).r - 0.5); yuv.z = (texture2D(us2_SamplerZ, vv2_Texcoord).r - 0.5); rgb = um3_ColorConversion * yuv; gl_FragColor = vec4(rgb, 1); } ); const char *IJK_GLES2_getFragmentShader_yuv420p() { return g_shader; } ================================================ FILE: ijkmedia/ijksdl/gles2/fsh/yuv420sp.fsh.c ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl/gles2/internal.h" static const char g_shader[] = IJK_GLES_STRING( precision highp float; varying highp vec2 vv2_Texcoord; uniform mat3 um3_ColorConversion; uniform lowp sampler2D us2_SamplerX; uniform lowp sampler2D us2_SamplerY; void main() { mediump vec3 yuv; lowp vec3 rgb; yuv.x = (texture2D(us2_SamplerX, vv2_Texcoord).r - (16.0 / 255.0)); yuv.yz = (texture2D(us2_SamplerY, vv2_Texcoord).rg - vec2(0.5, 0.5)); rgb = um3_ColorConversion * yuv; gl_FragColor = vec4(rgb, 1); } ); const char *IJK_GLES2_getFragmentShader_yuv420sp() { return g_shader; } ================================================ FILE: ijkmedia/ijksdl/gles2/fsh/yuv444p10le.fsh.c ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl/gles2/internal.h" static const char g_shader[] = IJK_GLES_STRING( precision highp float; varying highp vec2 vv2_Texcoord; uniform mat3 um3_ColorConversion; uniform lowp sampler2D us2_SamplerX; uniform lowp sampler2D us2_SamplerY; uniform lowp sampler2D us2_SamplerZ; void main() { mediump vec3 yuv_l; mediump vec3 yuv_h; mediump vec3 yuv; lowp vec3 rgb; yuv_l.x = texture2D(us2_SamplerX, vv2_Texcoord).r; yuv_h.x = texture2D(us2_SamplerX, vv2_Texcoord).a; yuv_l.y = texture2D(us2_SamplerY, vv2_Texcoord).r; yuv_h.y = texture2D(us2_SamplerY, vv2_Texcoord).a; yuv_l.z = texture2D(us2_SamplerZ, vv2_Texcoord).r; yuv_h.z = texture2D(us2_SamplerZ, vv2_Texcoord).a; yuv = (yuv_l * 255.0 + yuv_h * 255.0 * 256.0) / (1023.0) - vec3(16.0 / 255.0, 0.5, 0.5); rgb = um3_ColorConversion * yuv; gl_FragColor = vec4(rgb, 1); } ); const char *IJK_GLES2_getFragmentShader_yuv444p10le() { return g_shader; } ================================================ FILE: ijkmedia/ijksdl/gles2/internal.h ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_GLES2__INTERNAL__H #define IJKSDL__IJKSDL_GLES2__INTERNAL__H #include #include #include "ijksdl/ijksdl_fourcc.h" #include "ijksdl/ijksdl_log.h" #include "ijksdl/ijksdl_gles2.h" #include "ijksdl/ijksdl_vout.h" #define IJK_GLES_STRINGIZE(x) #x #define IJK_GLES_STRINGIZE2(x) IJK_GLES_STRINGIZE(x) #define IJK_GLES_STRING(x) IJK_GLES_STRINGIZE2(x) typedef struct IJK_GLES2_Renderer_Opaque IJK_GLES2_Renderer_Opaque; typedef struct IJK_GLES2_Renderer { IJK_GLES2_Renderer_Opaque *opaque; GLuint program; GLuint vertex_shader; GLuint fragment_shader; GLuint plane_textures[IJK_GLES2_MAX_PLANE]; GLuint av4_position; GLuint av2_texcoord; GLuint um4_mvp; GLuint us2_sampler[IJK_GLES2_MAX_PLANE]; GLuint um3_color_conversion; GLboolean (*func_use)(IJK_GLES2_Renderer *renderer); GLsizei (*func_getBufferWidth)(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay); GLboolean (*func_uploadTexture)(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay); GLvoid (*func_destroy)(IJK_GLES2_Renderer *renderer); GLsizei buffer_width; GLsizei visible_width; GLfloat texcoords[8]; GLfloat vertices[8]; int vertices_changed; int format; int gravity; GLsizei layer_width; GLsizei layer_height; int frame_width; int frame_height; int frame_sar_num; int frame_sar_den; GLsizei last_buffer_width; } IJK_GLES2_Renderer; typedef struct IJK_GLES_Matrix { GLfloat m[16]; } IJK_GLES_Matrix; void IJK_GLES2_loadOrtho(IJK_GLES_Matrix *matrix, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far); const char *IJK_GLES2_getVertexShader_default(); const char *IJK_GLES2_getFragmentShader_yuv420p(); const char *IJK_GLES2_getFragmentShader_yuv444p10le(); const char *IJK_GLES2_getFragmentShader_yuv420sp(); const char *IJK_GLES2_getFragmentShader_rgb(); const GLfloat *IJK_GLES2_getColorMatrix_bt709(); const GLfloat *IJK_GLES2_getColorMatrix_bt601(); IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_base(const char *fragment_shader_source); IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv420p(); IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv444p10le(); IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv420sp(); IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv420sp_vtb(SDL_VoutOverlay *overlay); IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_rgb565(); IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_rgb888(); IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_rgbx8888(); #endif ================================================ FILE: ijkmedia/ijksdl/gles2/renderer.c ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "internal.h" static void IJK_GLES2_printProgramInfo(GLuint program) { if (!program) return; GLint info_len = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_len); if (!info_len) { ALOGE("[GLES2][Program] empty info\n"); return; } char buf_stack[32]; char *buf_heap = NULL; char *buf = buf_stack; GLsizei buf_len = sizeof(buf_stack) - 1; if (info_len > sizeof(buf_stack)) { buf_heap = (char*) malloc(info_len + 1); if (buf_heap) { buf = buf_heap; buf_len = info_len; } } glGetProgramInfoLog(program, buf_len, NULL, buf); ALOGE("[GLES2][Program] error %s\n", buf); if (buf_heap) free(buf_heap); } void IJK_GLES2_Renderer_reset(IJK_GLES2_Renderer *renderer) { if (!renderer) return; if (renderer->vertex_shader) glDeleteShader(renderer->vertex_shader); if (renderer->fragment_shader) glDeleteShader(renderer->fragment_shader); if (renderer->program) glDeleteProgram(renderer->program); renderer->vertex_shader = 0; renderer->fragment_shader = 0; renderer->program = 0; for (int i = 0; i < IJK_GLES2_MAX_PLANE; ++i) { if (renderer->plane_textures[i]) { glDeleteTextures(1, &renderer->plane_textures[i]); renderer->plane_textures[i] = 0; } } } void IJK_GLES2_Renderer_free(IJK_GLES2_Renderer *renderer) { if (!renderer) return; if (renderer->func_destroy) renderer->func_destroy(renderer); #if 0 if (renderer->vertex_shader) ALOGW("[GLES2] renderer: vertex_shader not deleted.\n"); if (renderer->fragment_shader) ALOGW("[GLES2] renderer: fragment_shader not deleted.\n"); if (renderer->program) ALOGW("[GLES2] renderer: program not deleted.\n"); for (int i = 0; i < IJK_GLES2_MAX_PLANE; ++i) { if (renderer->plane_textures[i]) ALOGW("[GLES2] renderer: plane texture[%d] not deleted.\n", i); } #endif free(renderer); } void IJK_GLES2_Renderer_freeP(IJK_GLES2_Renderer **renderer) { if (!renderer || !*renderer) return; IJK_GLES2_Renderer_free(*renderer); *renderer = NULL; } IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_base(const char *fragment_shader_source) { assert(fragment_shader_source); IJK_GLES2_Renderer *renderer = (IJK_GLES2_Renderer *)calloc(1, sizeof(IJK_GLES2_Renderer)); if (!renderer) goto fail; renderer->vertex_shader = IJK_GLES2_loadShader(GL_VERTEX_SHADER, IJK_GLES2_getVertexShader_default()); if (!renderer->vertex_shader) goto fail; renderer->fragment_shader = IJK_GLES2_loadShader(GL_FRAGMENT_SHADER, fragment_shader_source); if (!renderer->fragment_shader) goto fail; renderer->program = glCreateProgram(); IJK_GLES2_checkError("glCreateProgram"); if (!renderer->program) goto fail; glAttachShader(renderer->program, renderer->vertex_shader); IJK_GLES2_checkError("glAttachShader(vertex)"); glAttachShader(renderer->program, renderer->fragment_shader); IJK_GLES2_checkError("glAttachShader(fragment)"); glLinkProgram(renderer->program); IJK_GLES2_checkError("glLinkProgram"); GLint link_status = GL_FALSE; glGetProgramiv(renderer->program, GL_LINK_STATUS, &link_status); if (!link_status) goto fail; renderer->av4_position = glGetAttribLocation(renderer->program, "av4_Position"); IJK_GLES2_checkError_TRACE("glGetAttribLocation(av4_Position)"); renderer->av2_texcoord = glGetAttribLocation(renderer->program, "av2_Texcoord"); IJK_GLES2_checkError_TRACE("glGetAttribLocation(av2_Texcoord)"); renderer->um4_mvp = glGetUniformLocation(renderer->program, "um4_ModelViewProjection"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(um4_ModelViewProjection)"); return renderer; fail: if (renderer && renderer->program) IJK_GLES2_printProgramInfo(renderer->program); IJK_GLES2_Renderer_free(renderer); return NULL; } IJK_GLES2_Renderer *IJK_GLES2_Renderer_create(SDL_VoutOverlay *overlay) { if (!overlay) return NULL; IJK_GLES2_printString("Version", GL_VERSION); IJK_GLES2_printString("Vendor", GL_VENDOR); IJK_GLES2_printString("Renderer", GL_RENDERER); IJK_GLES2_printString("Extensions", GL_EXTENSIONS); IJK_GLES2_Renderer *renderer = NULL; switch (overlay->format) { case SDL_FCC_RV16: renderer = IJK_GLES2_Renderer_create_rgb565(); break; case SDL_FCC_RV24: renderer = IJK_GLES2_Renderer_create_rgb888(); break; case SDL_FCC_RV32: renderer = IJK_GLES2_Renderer_create_rgbx8888(); break; #ifdef __APPLE__ case SDL_FCC_NV12: renderer = IJK_GLES2_Renderer_create_yuv420sp(); break; case SDL_FCC__VTB: renderer = IJK_GLES2_Renderer_create_yuv420sp_vtb(overlay); break; #endif case SDL_FCC_YV12: renderer = IJK_GLES2_Renderer_create_yuv420p(); break; case SDL_FCC_I420: renderer = IJK_GLES2_Renderer_create_yuv420p(); break; case SDL_FCC_I444P10LE: renderer = IJK_GLES2_Renderer_create_yuv444p10le(); break; default: ALOGE("[GLES2] unknown format %4s(%d)\n", (char *)&overlay->format, overlay->format); return NULL; } renderer->format = overlay->format; return renderer; } GLboolean IJK_GLES2_Renderer_isValid(IJK_GLES2_Renderer *renderer) { return renderer && renderer->program ? GL_TRUE : GL_FALSE; } GLboolean IJK_GLES2_Renderer_isFormat(IJK_GLES2_Renderer *renderer, int format) { if (!IJK_GLES2_Renderer_isValid(renderer)) return GL_FALSE; return renderer->format == format ? GL_TRUE : GL_FALSE; } /* * Per-Context routine */ GLboolean IJK_GLES2_Renderer_setupGLES() { glClearColor(0.0f, 0.0f, 0.0f, 1.0f); IJK_GLES2_checkError_TRACE("glClearColor"); glEnable(GL_CULL_FACE); IJK_GLES2_checkError_TRACE("glEnable(GL_CULL_FACE)"); glCullFace(GL_BACK); IJK_GLES2_checkError_TRACE("glCullFace"); glDisable(GL_DEPTH_TEST); return GL_TRUE; } static void IJK_GLES2_Renderer_Vertices_reset(IJK_GLES2_Renderer *renderer) { renderer->vertices[0] = -1.0f; renderer->vertices[1] = -1.0f; renderer->vertices[2] = 1.0f; renderer->vertices[3] = -1.0f; renderer->vertices[4] = -1.0f; renderer->vertices[5] = 1.0f; renderer->vertices[6] = 1.0f; renderer->vertices[7] = 1.0f; } static void IJK_GLES2_Renderer_Vertices_apply(IJK_GLES2_Renderer *renderer) { switch (renderer->gravity) { case IJK_GLES2_GRAVITY_RESIZE_ASPECT: break; case IJK_GLES2_GRAVITY_RESIZE_ASPECT_FILL: break; case IJK_GLES2_GRAVITY_RESIZE: IJK_GLES2_Renderer_Vertices_reset(renderer); return; default: ALOGE("[GLES2] unknown gravity %d\n", renderer->gravity); IJK_GLES2_Renderer_Vertices_reset(renderer); return; } if (renderer->layer_width <= 0 || renderer->layer_height <= 0 || renderer->frame_width <= 0 || renderer->frame_height <= 0) { ALOGE("[GLES2] invalid width/height for gravity aspect\n"); IJK_GLES2_Renderer_Vertices_reset(renderer); return; } float width = renderer->frame_width; float height = renderer->frame_height; if (renderer->frame_sar_num > 0 && renderer->frame_sar_den > 0) { width = width * renderer->frame_sar_num / renderer->frame_sar_den; } const float dW = (float)renderer->layer_width / width; const float dH = (float)renderer->layer_height / height; float dd = 1.0f; float nW = 1.0f; float nH = 1.0f; switch (renderer->gravity) { case IJK_GLES2_GRAVITY_RESIZE_ASPECT_FILL: dd = FFMAX(dW, dH); break; case IJK_GLES2_GRAVITY_RESIZE_ASPECT: dd = FFMIN(dW, dH); break; } nW = (width * dd / (float)renderer->layer_width); nH = (height * dd / (float)renderer->layer_height); renderer->vertices[0] = - nW; renderer->vertices[1] = - nH; renderer->vertices[2] = nW; renderer->vertices[3] = - nH; renderer->vertices[4] = - nW; renderer->vertices[5] = nH; renderer->vertices[6] = nW; renderer->vertices[7] = nH; } static void IJK_GLES2_Renderer_Vertices_reloadVertex(IJK_GLES2_Renderer *renderer) { glVertexAttribPointer(renderer->av4_position, 2, GL_FLOAT, GL_FALSE, 0, renderer->vertices); IJK_GLES2_checkError_TRACE("glVertexAttribPointer(av2_texcoord)"); glEnableVertexAttribArray(renderer->av4_position); IJK_GLES2_checkError_TRACE("glEnableVertexAttribArray(av2_texcoord)"); } #define IJK_GLES2_GRAVITY_MIN (0) #define IJK_GLES2_GRAVITY_RESIZE (0) // Stretch to fill layer bounds. #define IJK_GLES2_GRAVITY_RESIZE_ASPECT (1) // Preserve aspect ratio; fit within layer bounds. #define IJK_GLES2_GRAVITY_RESIZE_ASPECT_FILL (2) // Preserve aspect ratio; fill layer bounds. #define IJK_GLES2_GRAVITY_MAX (2) GLboolean IJK_GLES2_Renderer_setGravity(IJK_GLES2_Renderer *renderer, int gravity, GLsizei layer_width, GLsizei layer_height) { if (renderer->gravity != gravity && gravity >= IJK_GLES2_GRAVITY_MIN && gravity <= IJK_GLES2_GRAVITY_MAX) renderer->vertices_changed = 1; else if (renderer->layer_width != layer_width) renderer->vertices_changed = 1; else if (renderer->layer_height != layer_height) renderer->vertices_changed = 1; else return GL_TRUE; renderer->gravity = gravity; renderer->layer_width = layer_width; renderer->layer_height = layer_height; return GL_TRUE; } static void IJK_GLES2_Renderer_TexCoords_reset(IJK_GLES2_Renderer *renderer) { renderer->texcoords[0] = 0.0f; renderer->texcoords[1] = 1.0f; renderer->texcoords[2] = 1.0f; renderer->texcoords[3] = 1.0f; renderer->texcoords[4] = 0.0f; renderer->texcoords[5] = 0.0f; renderer->texcoords[6] = 1.0f; renderer->texcoords[7] = 0.0f; } static void IJK_GLES2_Renderer_TexCoords_cropRight(IJK_GLES2_Renderer *renderer, GLfloat cropRight) { ALOGE("IJK_GLES2_Renderer_TexCoords_cropRight\n"); renderer->texcoords[0] = 0.0f; renderer->texcoords[1] = 1.0f; renderer->texcoords[2] = 1.0f - cropRight; renderer->texcoords[3] = 1.0f; renderer->texcoords[4] = 0.0f; renderer->texcoords[5] = 0.0f; renderer->texcoords[6] = 1.0f - cropRight; renderer->texcoords[7] = 0.0f; } static void IJK_GLES2_Renderer_TexCoords_reloadVertex(IJK_GLES2_Renderer *renderer) { glVertexAttribPointer(renderer->av2_texcoord, 2, GL_FLOAT, GL_FALSE, 0, renderer->texcoords); IJK_GLES2_checkError_TRACE("glVertexAttribPointer(av2_texcoord)"); glEnableVertexAttribArray(renderer->av2_texcoord); IJK_GLES2_checkError_TRACE("glEnableVertexAttribArray(av2_texcoord)"); } /* * Per-Renderer routine */ GLboolean IJK_GLES2_Renderer_use(IJK_GLES2_Renderer *renderer) { if (!renderer) return GL_FALSE; assert(renderer->func_use); if (!renderer->func_use(renderer)) return GL_FALSE; IJK_GLES_Matrix modelViewProj; IJK_GLES2_loadOrtho(&modelViewProj, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f); glUniformMatrix4fv(renderer->um4_mvp, 1, GL_FALSE, modelViewProj.m); IJK_GLES2_checkError_TRACE("glUniformMatrix4fv(um4_mvp)"); IJK_GLES2_Renderer_TexCoords_reset(renderer); IJK_GLES2_Renderer_TexCoords_reloadVertex(renderer); IJK_GLES2_Renderer_Vertices_reset(renderer); IJK_GLES2_Renderer_Vertices_reloadVertex(renderer); return GL_TRUE; } /* * Per-Frame routine */ GLboolean IJK_GLES2_Renderer_renderOverlay(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay) { if (!renderer || !renderer->func_uploadTexture) return GL_FALSE; glClear(GL_COLOR_BUFFER_BIT); IJK_GLES2_checkError_TRACE("glClear"); GLsizei visible_width = renderer->frame_width; GLsizei visible_height = renderer->frame_height; if (overlay) { visible_width = overlay->w; visible_height = overlay->h; if (renderer->frame_width != visible_width || renderer->frame_height != visible_height || renderer->frame_sar_num != overlay->sar_num || renderer->frame_sar_den != overlay->sar_den) { renderer->frame_width = visible_width; renderer->frame_height = visible_height; renderer->frame_sar_num = overlay->sar_num; renderer->frame_sar_den = overlay->sar_den; renderer->vertices_changed = 1; } renderer->last_buffer_width = renderer->func_getBufferWidth(renderer, overlay); if (!renderer->func_uploadTexture(renderer, overlay)) return GL_FALSE; } else { // NULL overlay means force reload vertice renderer->vertices_changed = 1; } GLsizei buffer_width = renderer->last_buffer_width; if (renderer->vertices_changed || (buffer_width > 0 && buffer_width > visible_width && buffer_width != renderer->buffer_width && visible_width != renderer->visible_width)){ renderer->vertices_changed = 0; IJK_GLES2_Renderer_Vertices_apply(renderer); IJK_GLES2_Renderer_Vertices_reloadVertex(renderer); renderer->buffer_width = buffer_width; renderer->visible_width = visible_width; GLsizei padding_pixels = buffer_width - visible_width; GLfloat padding_normalized = ((GLfloat)padding_pixels) / buffer_width; IJK_GLES2_Renderer_TexCoords_reset(renderer); IJK_GLES2_Renderer_TexCoords_cropRight(renderer, padding_normalized); IJK_GLES2_Renderer_TexCoords_reloadVertex(renderer); } glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); IJK_GLES2_checkError_TRACE("glDrawArrays"); return GL_TRUE; } ================================================ FILE: ijkmedia/ijksdl/gles2/renderer_rgb.c ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "internal.h" static GLboolean rgb_use(IJK_GLES2_Renderer *renderer) { ALOGI("use render rgb\n"); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glUseProgram(renderer->program); IJK_GLES2_checkError_TRACE("glUseProgram"); if (0 == renderer->plane_textures[0]) glGenTextures(1, renderer->plane_textures); for (int i = 0; i < 1; ++i) { glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glUniform1i(renderer->us2_sampler[i], i); } return GL_TRUE; } static GLsizei rgb565_getBufferWidth(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay) { if (!overlay) return 0; return overlay->pitches[0] / 2; } static GLboolean rgb565_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay) { if (!renderer || !overlay) return GL_FALSE; int planes[1] = { 0 }; const GLsizei widths[1] = { overlay->pitches[0] / 2 }; const GLsizei heights[3] = { overlay->h }; const GLubyte *pixels[3] = { overlay->pixels[0] }; switch (overlay->format) { case SDL_FCC_RV16: break; default: ALOGE("[rgb565] unexpected format %x\n", overlay->format); return GL_FALSE; } for (int i = 0; i < 1; ++i) { int plane = planes[i]; glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, widths[plane], heights[plane], 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels[plane]); } return GL_TRUE; } IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_rgb565() { ALOGI("create render rgb565\n"); IJK_GLES2_Renderer *renderer = IJK_GLES2_Renderer_create_base(IJK_GLES2_getFragmentShader_rgb()); if (!renderer) goto fail; renderer->us2_sampler[0] = glGetUniformLocation(renderer->program, "us2_SamplerX"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerX)"); renderer->func_use = rgb_use; renderer->func_getBufferWidth = rgb565_getBufferWidth; renderer->func_uploadTexture = rgb565_uploadTexture; return renderer; fail: IJK_GLES2_Renderer_free(renderer); return NULL; } static GLsizei rgb888_getBufferWidth(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay) { if (!overlay) return 0; return overlay->pitches[0] / 3; } static GLboolean rgb888_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay) { if (!renderer || !overlay) return GL_FALSE; int planes[1] = { 0 }; const GLsizei widths[1] = { overlay->pitches[0] / 3 }; const GLsizei heights[3] = { overlay->h }; const GLubyte *pixels[3] = { overlay->pixels[0] }; switch (overlay->format) { case SDL_FCC_RV24: break; default: ALOGE("[rgb888] unexpected format %x\n", overlay->format); return GL_FALSE; } for (int i = 0; i < 1; ++i) { int plane = planes[i]; glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, widths[plane], heights[plane], 0, GL_RGB, GL_UNSIGNED_BYTE, pixels[plane]); } return GL_TRUE; } IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_rgb888() { ALOGI("create render rgb888\n"); IJK_GLES2_Renderer *renderer = IJK_GLES2_Renderer_create_base(IJK_GLES2_getFragmentShader_rgb()); if (!renderer) goto fail; renderer->us2_sampler[0] = glGetUniformLocation(renderer->program, "us2_SamplerX"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerX)"); renderer->func_use = rgb_use; renderer->func_getBufferWidth = rgb888_getBufferWidth; renderer->func_uploadTexture = rgb888_uploadTexture; return renderer; fail: IJK_GLES2_Renderer_free(renderer); return NULL; } static GLsizei rgbx8888_getBufferWidth(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay) { if (!overlay) return 0; return overlay->pitches[0] / 4; } static GLboolean rgbx8888_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay) { if (!renderer || !overlay) return GL_FALSE; int planes[1] = { 0 }; const GLsizei widths[1] = { overlay->pitches[0] / 4 }; const GLsizei heights[3] = { overlay->h }; const GLubyte *pixels[3] = { overlay->pixels[0] }; switch (overlay->format) { case SDL_FCC_RV32: break; default: ALOGE("[rgbx8888] unexpected format %x\n", overlay->format); return GL_FALSE; } for (int i = 0; i < 1; ++i) { int plane = planes[i]; glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, widths[plane], heights[plane], 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels[plane]); } return GL_TRUE; } IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_rgbx8888() { ALOGI("create render rgbx8888\n"); IJK_GLES2_Renderer *renderer = IJK_GLES2_Renderer_create_base(IJK_GLES2_getFragmentShader_rgb()); if (!renderer) goto fail; renderer->us2_sampler[0] = glGetUniformLocation(renderer->program, "us2_SamplerX"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerX)"); renderer->func_use = rgb_use; renderer->func_getBufferWidth = rgbx8888_getBufferWidth; renderer->func_uploadTexture = rgbx8888_uploadTexture; return renderer; fail: IJK_GLES2_Renderer_free(renderer); return NULL; } ================================================ FILE: ijkmedia/ijksdl/gles2/renderer_yuv420p.c ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "internal.h" static GLboolean yuv420p_use(IJK_GLES2_Renderer *renderer) { ALOGI("use render yuv420p\n"); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glUseProgram(renderer->program); IJK_GLES2_checkError_TRACE("glUseProgram"); if (0 == renderer->plane_textures[0]) glGenTextures(3, renderer->plane_textures); for (int i = 0; i < 3; ++i) { glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glUniform1i(renderer->us2_sampler[i], i); } glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt709()); return GL_TRUE; } static GLsizei yuv420p_getBufferWidth(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay) { if (!overlay) return 0; return overlay->pitches[0] / 1; } static GLboolean yuv420p_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay) { if (!renderer || !overlay) return GL_FALSE; int planes[3] = { 0, 1, 2 }; const GLsizei widths[3] = { overlay->pitches[0], overlay->pitches[1], overlay->pitches[2] }; const GLsizei heights[3] = { overlay->h, overlay->h / 2, overlay->h / 2 }; const GLubyte *pixels[3] = { overlay->pixels[0], overlay->pixels[1], overlay->pixels[2] }; switch (overlay->format) { case SDL_FCC_I420: break; case SDL_FCC_YV12: planes[1] = 2; planes[2] = 1; break; default: ALOGE("[yuv420p] unexpected format %x\n", overlay->format); return GL_FALSE; } for (int i = 0; i < 3; ++i) { int plane = planes[i]; glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, widths[plane], heights[plane], 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels[plane]); } return GL_TRUE; } IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv420p() { ALOGI("create render yuv420p\n"); IJK_GLES2_Renderer *renderer = IJK_GLES2_Renderer_create_base(IJK_GLES2_getFragmentShader_yuv420p()); if (!renderer) goto fail; renderer->us2_sampler[0] = glGetUniformLocation(renderer->program, "us2_SamplerX"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerX)"); renderer->us2_sampler[1] = glGetUniformLocation(renderer->program, "us2_SamplerY"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerY)"); renderer->us2_sampler[2] = glGetUniformLocation(renderer->program, "us2_SamplerZ"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerZ)"); renderer->um3_color_conversion = glGetUniformLocation(renderer->program, "um3_ColorConversion"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(um3_ColorConversionMatrix)"); renderer->func_use = yuv420p_use; renderer->func_getBufferWidth = yuv420p_getBufferWidth; renderer->func_uploadTexture = yuv420p_uploadTexture; return renderer; fail: IJK_GLES2_Renderer_free(renderer); return NULL; } ================================================ FILE: ijkmedia/ijksdl/gles2/renderer_yuv420sp.c ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "internal.h" #ifdef __APPLE__ #import #include "ijksdl_vout_overlay_videotoolbox.h" #endif static GLboolean yuv420sp_use(IJK_GLES2_Renderer *renderer) { ALOGI("use render yuv420sp\n"); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glUseProgram(renderer->program); IJK_GLES2_checkError_TRACE("glUseProgram"); if (0 == renderer->plane_textures[0]) glGenTextures(2, renderer->plane_textures); for (int i = 0; i < 2; ++i) { glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glUniform1i(renderer->us2_sampler[i], i); } glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt709()); return GL_TRUE; } static GLsizei yuv420sp_getBufferWidth(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay) { if (!overlay) return 0; return overlay->pitches[0] / 1; } static GLboolean yuv420sp_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay) { if (!renderer || !overlay) return GL_FALSE; const GLsizei widths[2] = { overlay->pitches[0], overlay->pitches[1] / 2 }; const GLsizei heights[2] = { overlay->h, overlay->h / 2 }; const GLubyte *pixels[2] = { overlay->pixels[0], overlay->pixels[1] }; switch (overlay->format) { case SDL_FCC__VTB: break; default: ALOGE("[yuv420sp] unexpected format %x\n", overlay->format); return GL_FALSE; } glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RED_EXT, widths[0], heights[0], 0, GL_RED_EXT, GL_UNSIGNED_BYTE, pixels[0]); glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RG_EXT, widths[1], heights[1], 0, GL_RG_EXT, GL_UNSIGNED_BYTE, pixels[1]); return GL_TRUE; } IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv420sp() { IJK_GLES2_Renderer *renderer = IJK_GLES2_Renderer_create_base(IJK_GLES2_getFragmentShader_yuv420sp()); if (!renderer) goto fail; renderer->us2_sampler[0] = glGetUniformLocation(renderer->program, "us2_SamplerX"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerX)"); renderer->us2_sampler[1] = glGetUniformLocation(renderer->program, "us2_SamplerY"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerY)"); renderer->um3_color_conversion = glGetUniformLocation(renderer->program, "um3_ColorConversion"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(um3_ColorConversionMatrix)"); renderer->func_use = yuv420sp_use; renderer->func_getBufferWidth = yuv420sp_getBufferWidth; renderer->func_uploadTexture = yuv420sp_uploadTexture; return renderer; fail: IJK_GLES2_Renderer_free(renderer); return NULL; } ================================================ FILE: ijkmedia/ijksdl/gles2/renderer_yuv420sp_vtb.m ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "internal.h" #import #import #include "ijksdl_vout_overlay_videotoolbox.h" typedef struct IJK_GLES2_Renderer_Opaque { CVOpenGLESTextureCacheRef cv_texture_cache; CVOpenGLESTextureRef cv_texture[2]; CFTypeRef color_attachments; } IJK_GLES2_Renderer_Opaque; static GLboolean yuv420sp_vtb_use(IJK_GLES2_Renderer *renderer) { ALOGI("use render yuv420sp_vtb\n"); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glUseProgram(renderer->program); IJK_GLES2_checkError_TRACE("glUseProgram"); for (int i = 0; i < 2; ++i) { glUniform1i(renderer->us2_sampler[i], i); } glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt709()); return GL_TRUE; } static GLvoid yuv420sp_vtb_clean_textures(IJK_GLES2_Renderer *renderer) { if (!renderer || !renderer->opaque) return; IJK_GLES2_Renderer_Opaque *opaque = renderer->opaque; for (int i = 0; i < 2; ++i) { if (opaque->cv_texture[i]) { CFRelease(opaque->cv_texture[i]); opaque->cv_texture[i] = nil; } } // Periodic texture cache flush every frame if (opaque->cv_texture_cache) CVOpenGLESTextureCacheFlush(opaque->cv_texture_cache, 0); } static GLsizei yuv420sp_vtb_getBufferWidth(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay) { if (!overlay) return 0; return overlay->pitches[0] / 1; } static GLboolean yuv420sp_vtb_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay) { if (!renderer || !renderer->opaque || !overlay) return GL_FALSE; if (!overlay->is_private) return GL_FALSE; switch (overlay->format) { case SDL_FCC__VTB: break; default: ALOGE("[yuv420sp_vtb] unexpected format %x\n", overlay->format); return GL_FALSE; } IJK_GLES2_Renderer_Opaque *opaque = renderer->opaque; if (!opaque->cv_texture_cache) { ALOGE("nil textureCache\n"); return GL_FALSE; } CVPixelBufferRef pixel_buffer = SDL_VoutOverlayVideoToolBox_GetCVPixelBufferRef(overlay); if (!pixel_buffer) { ALOGE("nil pixelBuffer in overlay\n"); return GL_FALSE; } CFTypeRef color_attachments = CVBufferGetAttachment(pixel_buffer, kCVImageBufferYCbCrMatrixKey, NULL); if (color_attachments != opaque->color_attachments) { if (color_attachments == nil) { glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt709()); } else if (opaque->color_attachments != nil && CFStringCompare(color_attachments, opaque->color_attachments, 0) == kCFCompareEqualTo) { // remain prvious color attachment } else if (CFStringCompare(color_attachments, kCVImageBufferYCbCrMatrix_ITU_R_709_2, 0) == kCFCompareEqualTo) { glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt709()); } else if (CFStringCompare(color_attachments, kCVImageBufferYCbCrMatrix_ITU_R_601_4, 0) == kCFCompareEqualTo) { glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt601()); } else { glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt709()); } if (opaque->color_attachments != nil) { CFRelease(opaque->color_attachments); opaque->color_attachments = nil; } if (color_attachments != nil) { opaque->color_attachments = CFRetain(color_attachments); } } yuv420sp_vtb_clean_textures(renderer); GLsizei frame_width = (GLsizei)CVPixelBufferGetWidth(pixel_buffer); GLsizei frame_height = (GLsizei)CVPixelBufferGetHeight(pixel_buffer); glActiveTexture(GL_TEXTURE0); CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, opaque->cv_texture_cache, pixel_buffer, NULL, GL_TEXTURE_2D, GL_RED_EXT, (GLsizei)frame_width, (GLsizei)frame_height, GL_RED_EXT, GL_UNSIGNED_BYTE, 0, &opaque->cv_texture[0]); glBindTexture(CVOpenGLESTextureGetTarget(opaque->cv_texture[0]), CVOpenGLESTextureGetName(opaque->cv_texture[0])); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glActiveTexture(GL_TEXTURE1); CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, opaque->cv_texture_cache, pixel_buffer, NULL, GL_TEXTURE_2D, GL_RG_EXT, (GLsizei)frame_width / 2, (GLsizei)frame_height / 2, GL_RG_EXT, GL_UNSIGNED_BYTE, 1, &opaque->cv_texture[1]); glBindTexture(CVOpenGLESTextureGetTarget(opaque->cv_texture[1]), CVOpenGLESTextureGetName(opaque->cv_texture[1])); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); return GL_TRUE; } static GLvoid yuv420sp_vtb_destroy(IJK_GLES2_Renderer *renderer) { if (!renderer || !renderer->opaque) return; yuv420sp_vtb_clean_textures(renderer); IJK_GLES2_Renderer_Opaque *opaque = renderer->opaque; if (opaque->cv_texture_cache) { CFRelease(opaque->cv_texture_cache); opaque->cv_texture_cache = nil; } if (opaque->color_attachments != nil) { CFRelease(opaque->color_attachments); opaque->color_attachments = nil; } free(renderer->opaque); renderer->opaque = nil; } IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv420sp_vtb(SDL_VoutOverlay *overlay) { CVReturn err = 0; EAGLContext *context = [EAGLContext currentContext]; if (!overlay) { ALOGW("invalid overlay, fall back to yuv420sp renderer\n"); return IJK_GLES2_Renderer_create_yuv420sp(); } if (!overlay) { ALOGW("non-private overlay, fall back to yuv420sp renderer\n"); return IJK_GLES2_Renderer_create_yuv420sp(); } if (!context) { ALOGW("nil EAGLContext, fall back to yuv420sp renderer\n"); return IJK_GLES2_Renderer_create_yuv420sp(); } ALOGI("create render yuv420sp_vtb\n"); IJK_GLES2_Renderer *renderer = IJK_GLES2_Renderer_create_base(IJK_GLES2_getFragmentShader_yuv420sp()); if (!renderer) goto fail; renderer->us2_sampler[0] = glGetUniformLocation(renderer->program, "us2_SamplerX"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerX)"); renderer->us2_sampler[1] = glGetUniformLocation(renderer->program, "us2_SamplerY"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerY)"); renderer->um3_color_conversion = glGetUniformLocation(renderer->program, "um3_ColorConversion"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(um3_ColorConversionMatrix)"); renderer->func_use = yuv420sp_vtb_use; renderer->func_getBufferWidth = yuv420sp_vtb_getBufferWidth; renderer->func_uploadTexture = yuv420sp_vtb_uploadTexture; renderer->func_destroy = yuv420sp_vtb_destroy; renderer->opaque = calloc(1, sizeof(IJK_GLES2_Renderer_Opaque)); if (!renderer->opaque) goto fail; err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, context, NULL, &renderer->opaque->cv_texture_cache); if (err || renderer->opaque->cv_texture_cache == nil) { ALOGE("Error at CVOpenGLESTextureCacheCreate %d\n", err); goto fail; } renderer->opaque->color_attachments = CFRetain(kCVImageBufferYCbCrMatrix_ITU_R_709_2); return renderer; fail: IJK_GLES2_Renderer_free(renderer); return NULL; } ================================================ FILE: ijkmedia/ijksdl/gles2/renderer_yuv444p10le.c ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "internal.h" static GLboolean yuv444p10le_use(IJK_GLES2_Renderer *renderer) { ALOGI("use render yuv420p10le\n"); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glUseProgram(renderer->program); IJK_GLES2_checkError_TRACE("glUseProgram"); if (0 == renderer->plane_textures[0]) glGenTextures(3, renderer->plane_textures); for (int i = 0; i < 3; ++i) { glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glUniform1i(renderer->us2_sampler[i], i); } glUniformMatrix3fv(renderer->um3_color_conversion, 1, GL_FALSE, IJK_GLES2_getColorMatrix_bt709()); return GL_TRUE; } static GLsizei yuv444p10le_getBufferWidth(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay) { if (!overlay) return 0; return overlay->pitches[0] / 2; } static GLboolean yuv444p10le_uploadTexture(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay) { if (!renderer || !overlay) return GL_FALSE; int planes[3] = { 0, 1, 2 }; const GLsizei widths[3] = { overlay->pitches[0] / 2, overlay->pitches[1] / 2, overlay->pitches[2] / 2 }; const GLsizei heights[3] = { overlay->h, overlay->h, overlay->h }; const GLubyte *pixels[3] = { overlay->pixels[0], overlay->pixels[1], overlay->pixels[2] }; switch (overlay->format) { case SDL_FCC_I444P10LE: break; default: ALOGE("[yuv420p10le] unexpected format %x\n", overlay->format); return GL_FALSE; } for (int i = 0; i < 3; ++i) { int plane = planes[i]; glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]); IJK_GLES2_checkError_TRACE("glBindTexture"); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, widths[plane], heights[plane], 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels[plane]); IJK_GLES2_checkError_TRACE("glTexImage2D"); } return GL_TRUE; } IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_yuv444p10le() { ALOGI("create render yuv444p10le\n"); IJK_GLES2_Renderer *renderer = IJK_GLES2_Renderer_create_base(IJK_GLES2_getFragmentShader_yuv444p10le()); if (!renderer) goto fail; renderer->us2_sampler[0] = glGetUniformLocation(renderer->program, "us2_SamplerX"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerX)"); renderer->us2_sampler[1] = glGetUniformLocation(renderer->program, "us2_SamplerY"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerY)"); renderer->us2_sampler[2] = glGetUniformLocation(renderer->program, "us2_SamplerZ"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(us2_SamplerZ)"); renderer->um3_color_conversion = glGetUniformLocation(renderer->program, "um3_ColorConversion"); IJK_GLES2_checkError_TRACE("glGetUniformLocation(um3_ColorConversionMatrix)"); renderer->func_use = yuv444p10le_use; renderer->func_getBufferWidth = yuv444p10le_getBufferWidth; renderer->func_uploadTexture = yuv444p10le_uploadTexture; return renderer; fail: IJK_GLES2_Renderer_free(renderer); return NULL; } ================================================ FILE: ijkmedia/ijksdl/gles2/shader.c ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "internal.h" static void IJK_GLES2_printShaderInfo(GLuint shader) { if (!shader) return; GLint info_len = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_len); if (!info_len) { ALOGE("[GLES2][Shader] empty info\n"); return; } char buf_stack[32]; char *buf_heap = NULL; char *buf = buf_stack; GLsizei buf_len = sizeof(buf_stack) - 1; if (info_len > sizeof(buf_stack)) { buf_heap = (char*) malloc(info_len + 1); if (buf_heap) { buf = buf_heap; buf_len = info_len; } } glGetShaderInfoLog(shader, buf_len, NULL, buf); ALOGE("[GLES2][Shader] error %s\n", buf); if (buf_heap) free(buf_heap); } GLuint IJK_GLES2_loadShader(GLenum shader_type, const char *shader_source) { assert(shader_source); GLuint shader = glCreateShader(shader_type); IJK_GLES2_checkError("glCreateShader"); if (!shader) return 0; assert(shader_source); glShaderSource(shader, 1, &shader_source, NULL); IJK_GLES2_checkError_TRACE("glShaderSource"); glCompileShader(shader); IJK_GLES2_checkError_TRACE("glCompileShader"); GLint compile_status = 0; glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status); if (!compile_status) goto fail; return shader; fail: if (shader) { IJK_GLES2_printShaderInfo(shader); glDeleteShader(shader); } return 0; } ================================================ FILE: ijkmedia/ijksdl/gles2/vsh/mvp.vsh.c ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl/gles2/internal.h" static const char g_shader[] = IJK_GLES_STRING( precision highp float; varying highp vec2 vv2_Texcoord; attribute highp vec4 av4_Position; attribute highp vec2 av2_Texcoord; uniform mat4 um4_ModelViewProjection; void main() { gl_Position = um4_ModelViewProjection * av4_Position; vv2_Texcoord = av2_Texcoord.xy; } ); const char *IJK_GLES2_getVertexShader_default() { return g_shader; } ================================================ FILE: ijkmedia/ijksdl/ijksdl.h ================================================ /***************************************************************************** * ijksdl.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_H #define IJKSDL__IJKSDL_H #include "ijksdl_audio.h" #include "ijksdl_aout.h" #include "ijksdl_class.h" #include "ijksdl_error.h" #include "ijksdl_log.h" #include "ijksdl_misc.h" #include "ijksdl_mutex.h" #include "ijksdl_thread.h" #include "ijksdl_timer.h" #include "ijksdl_video.h" #include "ijksdl_vout.h" #include "ffmpeg/ijksdl_vout_overlay_ffmpeg.h" #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_aout.c ================================================ /***************************************************************************** * ijksdl_aout.c ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_aout.h" #include #include "ijkplayer/ff_ffplay_def.h" int SDL_AoutOpenAudio(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained) { if (aout && desired && aout->open_audio) return aout->open_audio(aout, desired, obtained); return -1; } void SDL_AoutPauseAudio(SDL_Aout *aout, int pause_on) { if (aout && aout->pause_audio) aout->pause_audio(aout, pause_on); } void SDL_AoutFlushAudio(SDL_Aout *aout) { if (aout && aout->flush_audio) aout->flush_audio(aout); } void SDL_AoutSetStereoVolume(SDL_Aout *aout, float left_volume, float right_volume) { if (aout && aout->set_volume) aout->set_volume(aout, left_volume, right_volume); } void SDL_AoutCloseAudio(SDL_Aout *aout) { if (aout && aout->close_audio) return aout->close_audio(aout); } void SDL_AoutFree(SDL_Aout *aout) { if (!aout) return; if (aout->free_l) aout->free_l(aout); else free(aout); } void SDL_AoutFreeP(SDL_Aout **paout) { if (!paout) return; SDL_AoutFree(*paout); *paout = NULL; } double SDL_AoutGetLatencySeconds(SDL_Aout *aout) { if (!aout) return 0; if (aout->func_get_latency_seconds) return aout->func_get_latency_seconds(aout); return aout->minimal_latency_seconds; } void SDL_AoutSetDefaultLatencySeconds(SDL_Aout *aout, double latency) { if (aout) { if (aout->func_set_default_latency_seconds) aout->func_set_default_latency_seconds(aout, latency); aout->minimal_latency_seconds = latency; } } void SDL_AoutSetPlaybackRate(SDL_Aout *aout, float playbackRate) { if (aout) { if (aout->func_set_playback_rate) aout->func_set_playback_rate(aout, playbackRate); } } void SDL_AoutSetPlaybackVolume(SDL_Aout *aout, float volume) { if (aout) { if (aout->func_set_playback_volume) aout->func_set_playback_volume(aout, volume); } } int SDL_AoutGetAudioSessionId(SDL_Aout *aout) { if (aout) { if (aout->func_get_audio_session_id) { return aout->func_get_audio_session_id(aout); } } return 0; } int SDL_AoutGetAudioPerSecondCallBacks(SDL_Aout *aout) { if (aout) { if (aout->func_get_audio_persecond_callbacks) { return aout->func_get_audio_persecond_callbacks(aout); } } return SDL_AUDIO_MAX_CALLBACKS_PER_SEC; } ================================================ FILE: ijkmedia/ijksdl/ijksdl_aout.h ================================================ /***************************************************************************** * ijksdl_aout.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_AOUT_H #define IJKSDL__IJKSDL_AOUT_H #include "ijksdl_audio.h" #include "ijksdl_class.h" #include "ijksdl_mutex.h" typedef struct SDL_Aout_Opaque SDL_Aout_Opaque; typedef struct SDL_Aout SDL_Aout; struct SDL_Aout { SDL_mutex *mutex; double minimal_latency_seconds; SDL_Class *opaque_class; SDL_Aout_Opaque *opaque; void (*free_l)(SDL_Aout *vout); int (*open_audio)(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained); void (*pause_audio)(SDL_Aout *aout, int pause_on); void (*flush_audio)(SDL_Aout *aout); void (*set_volume)(SDL_Aout *aout, float left, float right); void (*close_audio)(SDL_Aout *aout); double (*func_get_latency_seconds)(SDL_Aout *aout); void (*func_set_default_latency_seconds)(SDL_Aout *aout, double latency); // optional void (*func_set_playback_rate)(SDL_Aout *aout, float playbackRate); void (*func_set_playback_volume)(SDL_Aout *aout, float playbackVolume); int (*func_get_audio_persecond_callbacks)(SDL_Aout *aout); // Android only int (*func_get_audio_session_id)(SDL_Aout *aout); }; int SDL_AoutOpenAudio(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained); void SDL_AoutPauseAudio(SDL_Aout *aout, int pause_on); void SDL_AoutFlushAudio(SDL_Aout *aout); void SDL_AoutSetStereoVolume(SDL_Aout *aout, float left_volume, float right_volume); void SDL_AoutCloseAudio(SDL_Aout *aout); void SDL_AoutFree(SDL_Aout *aout); void SDL_AoutFreeP(SDL_Aout **paout); double SDL_AoutGetLatencySeconds(SDL_Aout *aout); void SDL_AoutSetDefaultLatencySeconds(SDL_Aout *aout, double latency); int SDL_AoutGetAudioPerSecondCallBacks(SDL_Aout *aout); // optional void SDL_AoutSetPlaybackRate(SDL_Aout *aout, float playbackRate); void SDL_AoutSetPlaybackVolume(SDL_Aout *aout, float volume); // android only int SDL_AoutGetAudioSessionId(SDL_Aout *aout); #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_aout_internal.h ================================================ /***************************************************************************** * ijksdl_aout_internal.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_AOUT_INTERNAL_H #define IJKSDL__IJKSDL_AOUT_INTERNAL_H #include "ijksdl_mutex.h" #include "ijksdl_aout.h" inline static SDL_Aout *SDL_Aout_CreateInternal(size_t opaque_size) { SDL_Aout *aout = (SDL_Aout*) mallocz(sizeof(SDL_Aout)); if (!aout) return NULL; aout->opaque = mallocz(opaque_size); if (!aout->opaque) { free(aout); return NULL; } aout->mutex = SDL_CreateMutex(); if (aout->mutex == NULL) { free(aout->opaque); free(aout); return NULL; } return aout; } inline static void SDL_Aout_FreeInternal(SDL_Aout *aout) { if (!aout) return; if (aout->mutex) { SDL_DestroyMutex(aout->mutex); } free(aout->opaque); memset(aout, 0, sizeof(SDL_Aout)); free(aout); } #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_audio.c ================================================ /***************************************************************************** * ijksdl_audio.c ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_audio.h" void SDL_CalculateAudioSpec(SDL_AudioSpec * spec) { switch (spec->format) { case AUDIO_U8: spec->silence = 0x80; break; default: spec->silence = 0x00; break; } spec->size = SDL_AUDIO_BITSIZE(spec->format) / 8; spec->size *= spec->channels; spec->size *= spec->samples; } void SDL_MixAudio(Uint8* dst, const Uint8* src, Uint32 len, int volume) { // do nothing; } ================================================ FILE: ijkmedia/ijksdl/ijksdl_audio.h ================================================ /***************************************************************************** * ijksdl_audio.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_AUDIO_H #define IJKSDL__IJKSDL_AUDIO_H #include "ijksdl_stdinc.h" #include "ijksdl_endian.h" typedef uint16_t SDL_AudioFormat; #define SDL_AUDIO_MASK_BITSIZE (0xFF) #define SDL_AUDIO_MASK_DATATYPE (1<<8) #define SDL_AUDIO_MASK_ENDIAN (1<<12) #define SDL_AUDIO_MASK_SIGNED (1<<15) #define SDL_AUDIO_BITSIZE(x) (x & SDL_AUDIO_MASK_BITSIZE) #define SDL_AUDIO_ISFLOAT(x) (x & SDL_AUDIO_MASK_DATATYPE) #define SDL_AUDIO_ISBIGENDIAN(x) (x & SDL_AUDIO_MASK_ENDIAN) #define SDL_AUDIO_ISSIGNED(x) (x & SDL_AUDIO_MASK_SIGNED) #define SDL_AUDIO_ISINT(x) (!SDL_AUDIO_ISFLOAT(x)) #define SDL_AUDIO_ISLITTLEENDIAN(x) (!SDL_AUDIO_ISBIGENDIAN(x)) #define SDL_AUDIO_ISUNSIGNED(x) (!SDL_AUDIO_ISSIGNED(x)) #define AUDIO_INVALID 0x0000 #define AUDIO_U8 0x0008 /**< Unsigned 8-bit samples */ #define AUDIO_S8 0x8008 /**< Signed 8-bit samples */ #define AUDIO_U16LSB 0x0010 /**< Unsigned 16-bit samples */ #define AUDIO_S16LSB 0x8010 /**< Signed 16-bit samples */ #define AUDIO_U16MSB 0x1010 /**< As above, but big-endian byte order */ #define AUDIO_S16MSB 0x9010 /**< As above, but big-endian byte order */ #define AUDIO_U16 AUDIO_U16LSB #define AUDIO_S16 AUDIO_S16LSB #define AUDIO_S32LSB 0x8020 /**< 32-bit integer samples */ #define AUDIO_S32MSB 0x9020 /**< As above, but big-endian byte order */ #define AUDIO_S32 AUDIO_S32LSB #define AUDIO_F32LSB 0x8120 /**< 32-bit floating point samples */ #define AUDIO_F32MSB 0x9120 /**< As above, but big-endian byte order */ #define AUDIO_F32 AUDIO_F32LSB #if SDL_BYTEORDER == SDL_LIL_ENDIAN #define AUDIO_U16SYS AUDIO_U16LSB #define AUDIO_S16SYS AUDIO_S16LSB #define AUDIO_S32SYS AUDIO_S32LSB #define AUDIO_F32SYS AUDIO_F32LSB #else #define AUDIO_U16SYS AUDIO_U16MSB #define AUDIO_S16SYS AUDIO_S16MSB #define AUDIO_S32SYS AUDIO_S32MSB #define AUDIO_F32SYS AUDIO_F32MSB #endif #define SDL_MIX_MAXVOLUME (128) typedef void (*SDL_AudioCallback) (void *userdata, Uint8 * stream, int len); typedef struct SDL_AudioSpec { int freq; /**< DSP frequency -- samples per second */ SDL_AudioFormat format; /**< Audio data format */ Uint8 channels; /**< Number of channels: 1 mono, 2 stereo */ Uint8 silence; /**< Audio buffer silence value (calculated) */ Uint16 samples; /**< Audio buffer size in samples (power of 2) */ Uint16 padding; /**< NOT USED. Necessary for some compile environments */ Uint32 size; /**< Audio buffer size in bytes (calculated) */ SDL_AudioCallback callback; void *userdata; } SDL_AudioSpec; void SDL_CalculateAudioSpec(SDL_AudioSpec * spec); void SDL_MixAudio(Uint8* dst, const Uint8* src, Uint32 len, int volume); #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_class.h ================================================ /***************************************************************************** * ijksdl_class.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_CLASS_H #define IJKSDL__IJKSDL_CLASS_H typedef struct SDL_Class { const char *name; } SDL_Class; #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_container.h ================================================ /* * Copyright (c) 2015 Bilibili * copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_CONTAINER_H #define IJKSDL__IJKSDL_CONTAINER_H #include typedef int isdl_error; /* * Array */ typedef struct ISDL_Array { void **elements; size_t capacity; size_t size; } ISDL_Array; inline static isdl_error ISDL_Array__grow(ISDL_Array *array, size_t new_capacity) { assert(array); if (array->capacity >= new_capacity) return 0; void **new_elements = realloc(array->elements, sizeof(void *) * new_capacity); if (!new_elements) return -1; array->elements = new_elements; array->capacity = new_capacity; return 0; } inline static isdl_error ISDL_Array__init(ISDL_Array *array, size_t capacity) { assert(array); memset(array, 0, sizeof(ISDL_Array)); if (ISDL_Array__grow(array, capacity)) return -1; return 0; } inline static isdl_error ISDL_Array__push_back(ISDL_Array *array, void *val) { assert(array); if (array->size >= array->capacity) { if (ISDL_Array__grow(array, array->capacity * 2)) return -1; } array->elements[array->size++] = val; return 0; } inline static void *ISDL_Array__pop_back(ISDL_Array *array) { assert(array); assert(array->size >= 1); return array->elements[--array->size]; } inline static void ISDL_Array__clear(ISDL_Array *array) { assert(array); array->size = 0; } inline static void *ISDL_Array__at(ISDL_Array *array, int pos) { assert(array); assert(pos >= 0); assert(pos < array->size); return array->elements[pos]; } inline static size_t ISDL_Array__size(ISDL_Array *array) { assert(array); return array->size; } inline static void **ISDL_Array__begin(ISDL_Array *array) { assert(array); return array->elements; } inline static void **ISDL_Array__end(ISDL_Array *array) { assert(array); return array->elements + array->size; } inline static void *ISDL_Array__back(ISDL_Array *array) { assert(array); assert(array->size >= 1); return array->elements[array->size - 1]; } #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_egl.c ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __APPLE__ #include "ijksdl_egl.h" #include #include #include "ijksdl/ijksdl_gles2.h" #include "ijksdl/ijksdl_log.h" #include "ijksdl/ijksdl_vout.h" #include "ijksdl/gles2/internal.h" #define IJK_EGL_RENDER_BUFFER 0 typedef struct IJK_EGL_Opaque { IJK_GLES2_Renderer *renderer; } IJK_EGL_Opaque; static EGLBoolean IJK_EGL_isValid(IJK_EGL* egl) { if (egl && egl->window && egl->display && egl->surface && egl->context) { return EGL_TRUE; } return EGL_FALSE; } void IJK_EGL_terminate(IJK_EGL* egl) { if (!IJK_EGL_isValid(egl)) return; if (egl->opaque) IJK_GLES2_Renderer_freeP(&egl->opaque->renderer); if (egl->display) { eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (egl->context) eglDestroyContext(egl->display, egl->context); if (egl->surface) eglDestroySurface(egl->display, egl->surface); eglTerminate(egl->display); eglReleaseThread(); // FIXME: call at thread exit } egl->context = EGL_NO_CONTEXT; egl->surface = EGL_NO_SURFACE; egl->display = EGL_NO_DISPLAY; } static int IJK_EGL_getSurfaceWidth(IJK_EGL* egl) { EGLint width = 0; if (!eglQuerySurface(egl->display, egl->surface, EGL_WIDTH, &width)) { ALOGE("[EGL] eglQuerySurface(EGL_WIDTH) returned error %d", eglGetError()); return 0; } return width; } static int IJK_EGL_getSurfaceHeight(IJK_EGL* egl) { EGLint height = 0; if (!eglQuerySurface(egl->display, egl->surface, EGL_HEIGHT, &height)) { ALOGE("[EGL] eglQuerySurface(EGL_HEIGHT) returned error %d", eglGetError()); return 0; } return height; } static EGLBoolean IJK_EGL_setSurfaceSize(IJK_EGL* egl, int width, int height) { if (!IJK_EGL_isValid(egl)) return EGL_FALSE; #ifdef __ANDROID__ egl->width = IJK_EGL_getSurfaceWidth(egl); egl->height = IJK_EGL_getSurfaceHeight(egl); if (width != egl->width || height != egl->height) { int format = ANativeWindow_getFormat(egl->window); ALOGI("ANativeWindow_setBuffersGeometry(w=%d,h=%d) -> (w=%d,h=%d);", egl->width, egl->height, width, height); int ret = ANativeWindow_setBuffersGeometry(egl->window, width, height, format); if (ret) { ALOGE("[EGL] ANativeWindow_setBuffersGeometry() returned error %d", ret); return EGL_FALSE; } egl->width = IJK_EGL_getSurfaceWidth(egl); egl->height = IJK_EGL_getSurfaceHeight(egl); return (egl->width && egl->height) ? EGL_TRUE : EGL_FALSE; } return EGL_TRUE; #else // FIXME: other platform? #endif return EGL_FALSE; } static EGLBoolean IJK_EGL_makeCurrent(IJK_EGL* egl, EGLNativeWindowType window) { if (window && window == egl->window && egl->display && egl->surface && egl->context) { if (!eglMakeCurrent(egl->display, egl->surface, egl->surface, egl->context)) { ALOGE("[EGL] elgMakeCurrent() failed (cached)\n"); return EGL_FALSE; } return EGL_TRUE; } IJK_EGL_terminate(egl); egl->window = window; if (!window) return EGL_FALSE; EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (display == EGL_NO_DISPLAY) { ALOGE("[EGL] eglGetDisplay failed\n"); return EGL_FALSE; } EGLint major, minor; if (!eglInitialize(display, &major, &minor)) { ALOGE("[EGL] eglInitialize failed\n"); return EGL_FALSE; } ALOGI("[EGL] eglInitialize %d.%d\n", (int)major, (int)minor); static const EGLint configAttribs[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_NONE }; static const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; EGLConfig config; EGLint numConfig; if (!eglChooseConfig(display, configAttribs, &config, 1, &numConfig)) { ALOGE("[EGL] eglChooseConfig failed\n"); eglTerminate(display); return EGL_FALSE; } #ifdef __ANDROID__ { EGLint native_visual_id = 0; if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &native_visual_id)) { ALOGE("[EGL] eglGetConfigAttrib() returned error %d", eglGetError()); eglTerminate(display); return EGL_FALSE; } int32_t width = ANativeWindow_getWidth(window); int32_t height = ANativeWindow_getWidth(window); ALOGI("[EGL] ANativeWindow_setBuffersGeometry(f=%d);", native_visual_id); int ret = ANativeWindow_setBuffersGeometry(window, width, height, native_visual_id); if (ret) { ALOGE("[EGL] ANativeWindow_setBuffersGeometry(format) returned error %d", ret); eglTerminate(display); return EGL_FALSE; } } #endif EGLSurface surface = eglCreateWindowSurface(display, config, window, NULL); if (surface == EGL_NO_SURFACE) { ALOGE("[EGL] eglCreateWindowSurface failed\n"); eglTerminate(display); return EGL_FALSE; } EGLSurface context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); if (context == EGL_NO_CONTEXT) { ALOGE("[EGL] eglCreateContext failed\n"); eglDestroySurface(display, surface); eglTerminate(display); return EGL_FALSE; } if (!eglMakeCurrent(display, surface, surface, context)) { ALOGE("[EGL] elgMakeCurrent() failed (new)\n"); eglDestroyContext(display, context); eglDestroySurface(display, surface); eglTerminate(display); return EGL_FALSE; } #if 0 #if defined(__ANDROID__) { const char *extensions = (const char *) glGetString(GL_EXTENSIONS); if (extensions) { char *dup_extensions = strdup(extensions); if (dup_extensions) { char *brk = NULL; char *ext = strtok_r(dup_extensions, " ", &brk); while (ext) { if (0 == strcmp(ext, "GL_EXT_texture_rg")) egl->gles2_extensions[IJK_GLES2__GL_EXT_texture_rg] = 1; ext = strtok_r(NULL, " ", &brk); } free(dup_extensions); } } } #elif defined(__APPLE__) egl->gles2_extensions[IJK_GLES2__GL_EXT_texture_rg] = 1; #endif ALOGI("[EGL] GLES2 extensions begin:\n"); ALOGI("[EGL] GL_EXT_texture_rg: %d\n", egl->gles2_extensions[IJK_GLES2__GL_EXT_texture_rg]); ALOGI("[EGL] GLES2 extensions end.\n"); #endif IJK_GLES2_Renderer_setupGLES(); egl->context = context; egl->surface = surface; egl->display = display; return EGL_TRUE; } static EGLBoolean IJK_EGL_prepareRenderer(IJK_EGL* egl, SDL_VoutOverlay *overlay) { assert(egl); assert(egl->opaque); IJK_EGL_Opaque *opaque = egl->opaque; if (!IJK_GLES2_Renderer_isValid(opaque->renderer) || !IJK_GLES2_Renderer_isFormat(opaque->renderer, overlay->format)) { IJK_GLES2_Renderer_reset(opaque->renderer); IJK_GLES2_Renderer_freeP(&opaque->renderer); opaque->renderer = IJK_GLES2_Renderer_create(overlay); if (!opaque->renderer) { ALOGE("[EGL] Could not create render."); return EGL_FALSE; } if (!IJK_GLES2_Renderer_use(opaque->renderer)) { ALOGE("[EGL] Could not use render."); IJK_GLES2_Renderer_freeP(&opaque->renderer); return EGL_FALSE; } } if (!IJK_EGL_setSurfaceSize(egl, overlay->w, overlay->h)) { ALOGE("[EGL] IJK_EGL_setSurfaceSize(%d, %d) failed\n", overlay->w, overlay->h); return EGL_FALSE; } glViewport(0, 0, egl->width, egl->height); IJK_GLES2_checkError_TRACE("glViewport"); return EGL_TRUE; } static EGLBoolean IJK_EGL_display_internal(IJK_EGL* egl, EGLNativeWindowType window, SDL_VoutOverlay *overlay) { IJK_EGL_Opaque *opaque = egl->opaque; if (!IJK_EGL_prepareRenderer(egl, overlay)) { ALOGE("[EGL] IJK_EGL_prepareRenderer failed\n"); return EGL_FALSE; } if (!IJK_GLES2_Renderer_renderOverlay(opaque->renderer, overlay)) { ALOGE("[EGL] IJK_GLES2_render failed\n"); return EGL_FALSE; } eglSwapBuffers(egl->display, egl->surface); return EGL_TRUE; } EGLBoolean IJK_EGL_display(IJK_EGL* egl, EGLNativeWindowType window, SDL_VoutOverlay *overlay) { EGLBoolean ret = EGL_FALSE; if (!egl) return EGL_FALSE; IJK_EGL_Opaque *opaque = egl->opaque; if (!opaque) return EGL_FALSE; if (!IJK_EGL_makeCurrent(egl, window)) return EGL_FALSE; ret = IJK_EGL_display_internal(egl, window, overlay); eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglReleaseThread(); // FIXME: call at thread exit return ret; } void IJK_EGL_releaseWindow(IJK_EGL* egl) { if (!egl || !egl->opaque || !egl->opaque->renderer) return; IJK_EGL_terminate(egl); } void IJK_EGL_free(IJK_EGL *egl) { if (!egl) return; IJK_EGL_terminate(egl); memset(egl, 0, sizeof(IJK_EGL)); free(egl); } void IJK_EGL_freep(IJK_EGL **egl) { if (!egl || !*egl) return; IJK_EGL_free(*egl); *egl = NULL; } static SDL_Class g_class = { .name = "EGL", }; IJK_EGL *IJK_EGL_create() { IJK_EGL *egl = (IJK_EGL*) mallocz(sizeof(IJK_EGL)); if (!egl) return NULL; egl->opaque_class = &g_class; egl->opaque = mallocz(sizeof(IJK_EGL_Opaque)); if (!egl->opaque) { free(egl); return NULL; } return egl; } #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_egl.h ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_EGL_H #define IJKSDL__IJKSDL_EGL_H #ifdef __APPLE__ #include "ijksdl/ios/EGL/egl.h" #include "ijksdl/ios/EGL/eglplatform.h" #else #include #include #include #endif #include "ijksdl_class.h" typedef struct SDL_VoutOverlay SDL_VoutOverlay; typedef struct IJK_EGL_Opaque IJK_EGL_Opaque; #if 0 enum { IJK_GLES2__GL_EXT_texture_rg, IJK_GLES2__MAX_EXT, }; #endif typedef struct IJK_EGL { SDL_Class *opaque_class; IJK_EGL_Opaque *opaque; EGLNativeWindowType window; EGLDisplay display; EGLSurface surface; EGLContext context; EGLint width; EGLint height; #if 0 uint8_t gles2_extensions[IJK_GLES2__MAX_EXT]; #endif } IJK_EGL; IJK_EGL *IJK_EGL_create(); void IJK_EGL_free(IJK_EGL *egl); void IJK_EGL_freep(IJK_EGL **egl); EGLBoolean IJK_EGL_display(IJK_EGL* egl, EGLNativeWindowType window, SDL_VoutOverlay *overlay); void IJK_EGL_terminate(IJK_EGL* egl); #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_endian.h ================================================ /***************************************************************************** * ijksdl_endian.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_ENDIAN_H #define IJKSDL__IJKSDL_ENDIAN_H #define SDL_LIL_ENDIAN 1234 #define SDL_BIG_ENDIAN 4321 #ifndef SDL_BYTEORDER /* Not defined in SDL_config.h? */ #ifdef __linux__ #include #define SDL_BYTEORDER __BYTE_ORDER #else /* __linux __ */ #if defined(__hppa__) || \ defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \ (defined(__MIPS__) && defined(__MISPEB__)) || \ defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \ defined(__sparc__) #define SDL_BYTEORDER SDL_BIG_ENDIAN #else #define SDL_BYTEORDER SDL_LIL_ENDIAN #endif #endif /* __linux __ */ #endif /* !SDL_BYTEORDER */ #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_error.c ================================================ /***************************************************************************** * ijksdl_error.c ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_error.h" #include "ijksdl_stdinc.h" const char *SDL_GetError(void) { return NULL; } ================================================ FILE: ijkmedia/ijksdl/ijksdl_error.h ================================================ /***************************************************************************** * ijksdl_error.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_ERROR_H #define IJKSDL__IJKSDL_ERROR_H const char *SDL_GetError(void); #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_extra_log.c ================================================ /***************************************************************************** * ijksdl_extra_log.c ***************************************************************************** * * Copyright (c) 2017 Bilibili * copyright (c) 2017 Raymond Zheng * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_extra_log.h" #include "ijksdl/android/ijksdl_android_jni.h" #include #define LOG_BUF_SIZE 1024 #ifdef EXTRA_LOG_PRINT void ffp_log_extra_print(int level, const char *tag, const char *fmt, ...) { JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { return; } va_list ap; char log_buffer[LOG_BUF_SIZE] = {0}; va_start(ap, fmt); vsnprintf(log_buffer, LOG_BUF_SIZE, fmt, ap); va_end(ap); switch (level) { case ANDROID_LOG_UNKNOWN: case ANDROID_LOG_DEFAULT: case ANDROID_LOG_VERBOSE: J4AC_BLog__v__withCString__catchAll(env, tag, log_buffer); break; case ANDROID_LOG_DEBUG: J4AC_BLog__d__withCString__catchAll(env, tag, log_buffer); break; case ANDROID_LOG_INFO: J4AC_BLog__i__withCString__catchAll(env, tag, log_buffer); break; case ANDROID_LOG_WARN: J4AC_BLog__w__withCString__catchAll(env, tag, log_buffer); break; case ANDROID_LOG_FATAL: case ANDROID_LOG_SILENT: case ANDROID_LOG_ERROR: J4AC_BLog__e__withCString__catchAll(env, tag, log_buffer); break; default: break; } } void ffp_log_extra_vprint(int level, const char *tag, const char *fmt, va_list ap) { JNIEnv *env = NULL; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { return; } char log_buffer[LOG_BUF_SIZE] = {0}; vsnprintf(log_buffer, LOG_BUF_SIZE, fmt, ap); switch (level) { case ANDROID_LOG_UNKNOWN: case ANDROID_LOG_DEFAULT: case ANDROID_LOG_VERBOSE: J4AC_BLog__v__withCString__catchAll(env, tag, log_buffer); break; case ANDROID_LOG_DEBUG: J4AC_BLog__d__withCString__catchAll(env, tag, log_buffer); break; case ANDROID_LOG_INFO: J4AC_BLog__i__withCString__catchAll(env, tag, log_buffer); break; case ANDROID_LOG_WARN: J4AC_BLog__w__withCString__catchAll(env, tag, log_buffer); break; case ANDROID_LOG_FATAL: case ANDROID_LOG_SILENT: case ANDROID_LOG_ERROR: J4AC_BLog__e__withCString__catchAll(env, tag, log_buffer); break; default: break; } } #endif // EXTRA_LOG_PRINT ================================================ FILE: ijkmedia/ijksdl/ijksdl_extra_log.h ================================================ /***************************************************************************** * ijksdl_extra_log.h ***************************************************************************** * * Copyright (c) 2017 Bilibili * copyright (c) 2017 Raymond Zheng * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_EXTRA_LOG_H #define IJKSDL__IJKSDL_EXTRA_LOG_H #ifdef __ANDROID__ #include void ffp_log_extra_print(int level, const char *tag, const char *fmt, ...); void ffp_log_extra_vprint(int level, const char *tag, const char *fmt, va_list ap); #endif #endif // IJKSDL__IJKSDL_EXTRA_LOG_H ================================================ FILE: ijkmedia/ijksdl/ijksdl_fourcc.h ================================================ /***************************************************************************** * ijksdl_fourcc.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_FOURCC_H #define IJKSDL__IJKSDL_FOURCC_H #include "ijksdl_stdinc.h" #include "ijksdl_endian.h" #if SDL_BYTEORDER == SDL_LIL_ENDIAN # define SDL_FOURCC(a, b, c, d) \ (((uint32_t)a) | (((uint32_t)b) << 8) | (((uint32_t)c) << 16) | (((uint32_t)d) << 24)) # define SDL_TWOCC(a, b) \ ((uint16_t)(a) | ((uint16_t)(b) << 8)) #else # define SDL_FOURCC(a, b, c, d) \ (((uint32_t)d) | (((uint32_t)c) << 8) | (((uint32_t)b) << 16) | (((uint32_t)a) << 24)) # define SDL_TWOCC( a, b ) \ ((uint16_t)(b) | ((uint16_t)(a) << 8)) #endif /*- * http://www.webartz.com/fourcc/indexyuv.htm * http://www.neuro.sfc.keio.ac.jp/~aly/polygon/info/color-space-faq.html * http://www.fourcc.org/yuv.php */ // YUV formats #define SDL_FCC_YV12 SDL_FOURCC('Y', 'V', '1', '2') /**< bpp=12, Planar mode: Y + V + U (3 planes) */ #define SDL_FCC_IYUV SDL_FOURCC('I', 'Y', 'U', 'V') /**< bpp=12, Planar mode: Y + U + V (3 planes) */ #define SDL_FCC_I420 SDL_FOURCC('I', '4', '2', '0') /**< bpp=12, Planar mode: Y + U + V (3 planes) */ #define SDL_FCC_I444P10LE SDL_FOURCC('I', '4', 'A', 'L') #define SDL_FCC_YUV2 SDL_FOURCC('Y', 'U', 'V', '2') /**< bpp=16, Packed mode: Y0+U0+Y1+V0 (1 plane) */ #define SDL_FCC_UYVY SDL_FOURCC('U', 'Y', 'V', 'Y') /**< bpp=16, Packed mode: U0+Y0+V0+Y1 (1 plane) */ #define SDL_FCC_YVYU SDL_FOURCC('Y', 'V', 'Y', 'U') /**< bpp=16, Packed mode: Y0+V0+Y1+U0 (1 plane) */ #define SDL_FCC_NV12 SDL_FOURCC('N', 'V', '1', '2') // RGB formats #define SDL_FCC_RV16 SDL_FOURCC('R', 'V', '1', '6') /**< bpp=16, RGB565 */ #define SDL_FCC_RV24 SDL_FOURCC('R', 'V', '2', '4') /**< bpp=24, RGB888 */ #define SDL_FCC_RV32 SDL_FOURCC('R', 'V', '3', '2') /**< bpp=32, RGBX8888 */ // opaque formats #define SDL_FCC__AMC SDL_FOURCC('_', 'A', 'M', 'C') /**< Android MediaCodec */ #define SDL_FCC__VTB SDL_FOURCC('_', 'V', 'T', 'B') /**< iOS VideoToolbox */ #define SDL_FCC__GLES2 SDL_FOURCC('_', 'E', 'S', '2') /**< let Vout choose format */ // undefine #define SDL_FCC_UNDF SDL_FOURCC('U', 'N', 'D', 'F') /**< undefined */ enum { IJK_AV_PIX_FMT__START = 10000, IJK_AV_PIX_FMT__ANDROID_MEDIACODEC, IJK_AV_PIX_FMT__VIDEO_TOOLBOX, }; #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_gles2.h ================================================ /* * Copyright (c) 2016 Bilibili * copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_GLES2_H #define IJKSDL__IJKSDL_GLES2_H #ifdef __APPLE__ #include #include #else #include #include #include #endif typedef struct SDL_VoutOverlay SDL_VoutOverlay; /* * Common */ #ifdef DEBUG #define IJK_GLES2_checkError_TRACE(op) #define IJK_GLES2_checkError_DEBUG(op) #else #define IJK_GLES2_checkError_TRACE(op) IJK_GLES2_checkError(op) #define IJK_GLES2_checkError_DEBUG(op) IJK_GLES2_checkError(op) #endif void IJK_GLES2_printString(const char *name, GLenum s); void IJK_GLES2_checkError(const char *op); GLuint IJK_GLES2_loadShader(GLenum shader_type, const char *shader_source); /* * Renderer */ #define IJK_GLES2_MAX_PLANE 3 typedef struct IJK_GLES2_Renderer IJK_GLES2_Renderer; IJK_GLES2_Renderer *IJK_GLES2_Renderer_create(SDL_VoutOverlay *overlay); void IJK_GLES2_Renderer_reset(IJK_GLES2_Renderer *renderer); void IJK_GLES2_Renderer_free(IJK_GLES2_Renderer *renderer); void IJK_GLES2_Renderer_freeP(IJK_GLES2_Renderer **renderer); GLboolean IJK_GLES2_Renderer_setupGLES(); GLboolean IJK_GLES2_Renderer_isValid(IJK_GLES2_Renderer *renderer); GLboolean IJK_GLES2_Renderer_isFormat(IJK_GLES2_Renderer *renderer, int format); GLboolean IJK_GLES2_Renderer_use(IJK_GLES2_Renderer *renderer); GLboolean IJK_GLES2_Renderer_renderOverlay(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay); #define IJK_GLES2_GRAVITY_RESIZE (0) // Stretch to fill view bounds. #define IJK_GLES2_GRAVITY_RESIZE_ASPECT (1) // Preserve aspect ratio; fit within view bounds. #define IJK_GLES2_GRAVITY_RESIZE_ASPECT_FILL (2) // Preserve aspect ratio; fill view bounds. GLboolean IJK_GLES2_Renderer_setGravity(IJK_GLES2_Renderer *renderer, int gravity, GLsizei view_width, GLsizei view_height); #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_inc_internal.h ================================================ /* * ijksdl_inc_internal.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKPLAYER__IJKSDL_INC_INTERNAL_H #define IJKPLAYER__IJKSDL_INC_INTERNAL_H #include #include "ijksdl_log.h" #include "ijksdl_misc.h" #include "ijksdl_stdinc.h" #define SDLTRACE ALOGD #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_log.h ================================================ /***************************************************************************** * ijksdl_log.h ***************************************************************************** * * Copyright (c) 2015 Bilibili * copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_LOG_H #define IJKSDL__IJKSDL_LOG_H #include #ifdef __ANDROID__ #include #include "ijksdl_extra_log.h" #define IJK_LOG_UNKNOWN ANDROID_LOG_UNKNOWN #define IJK_LOG_DEFAULT ANDROID_LOG_DEFAULT #define IJK_LOG_VERBOSE ANDROID_LOG_VERBOSE #define IJK_LOG_DEBUG ANDROID_LOG_DEBUG #define IJK_LOG_INFO ANDROID_LOG_INFO #define IJK_LOG_WARN ANDROID_LOG_WARN #define IJK_LOG_ERROR ANDROID_LOG_ERROR #define IJK_LOG_FATAL ANDROID_LOG_FATAL #define IJK_LOG_SILENT ANDROID_LOG_SILENT #ifdef EXTRA_LOG_PRINT #define VLOG(level, TAG, ...) ffp_log_extra_vprint(level, TAG, __VA_ARGS__) #define ALOG(level, TAG, ...) ffp_log_extra_print(level, TAG, __VA_ARGS__) #else #define VLOG(level, TAG, ...) ((void)__android_log_vprint(level, TAG, __VA_ARGS__)) #define ALOG(level, TAG, ...) ((void)__android_log_print(level, TAG, __VA_ARGS__)) #endif #else #define IJK_LOG_UNKNOWN 0 #define IJK_LOG_DEFAULT 1 #define IJK_LOG_VERBOSE 2 #define IJK_LOG_DEBUG 3 #define IJK_LOG_INFO 4 #define IJK_LOG_WARN 5 #define IJK_LOG_ERROR 6 #define IJK_LOG_FATAL 7 #define IJK_LOG_SILENT 8 #define VLOG(level, TAG, ...) ((void)vprintf(__VA_ARGS__)) #define ALOG(level, TAG, ...) ((void)printf(__VA_ARGS__)) #endif #define IJK_LOG_TAG "IJKMEDIA" #define VLOGV(...) VLOG(IJK_LOG_VERBOSE, IJK_LOG_TAG, __VA_ARGS__) #define VLOGD(...) VLOG(IJK_LOG_DEBUG, IJK_LOG_TAG, __VA_ARGS__) #define VLOGI(...) VLOG(IJK_LOG_INFO, IJK_LOG_TAG, __VA_ARGS__) #define VLOGW(...) VLOG(IJK_LOG_WARN, IJK_LOG_TAG, __VA_ARGS__) #define VLOGE(...) VLOG(IJK_LOG_ERROR, IJK_LOG_TAG, __VA_ARGS__) #define ALOGV(...) ALOG(IJK_LOG_VERBOSE, IJK_LOG_TAG, __VA_ARGS__) #define ALOGD(...) ALOG(IJK_LOG_DEBUG, IJK_LOG_TAG, __VA_ARGS__) #define ALOGI(...) ALOG(IJK_LOG_INFO, IJK_LOG_TAG, __VA_ARGS__) #define ALOGW(...) ALOG(IJK_LOG_WARN, IJK_LOG_TAG, __VA_ARGS__) #define ALOGE(...) ALOG(IJK_LOG_ERROR, IJK_LOG_TAG, __VA_ARGS__) #define LOG_ALWAYS_FATAL(...) do { ALOGE(__VA_ARGS__); exit(1); } while (0) #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_misc.h ================================================ /***************************************************************************** * ijksdl_misc.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_MISC_H #define IJKSDL__IJKSDL_MISC_H #include #include #ifndef IJKMAX #define IJKMAX(a, b) ((a) > (b) ? (a) : (b)) #endif #ifndef IJKMIN #define IJKMIN(a, b) ((a) < (b) ? (a) : (b)) #endif #ifndef IJKALIGN #define IJKALIGN(x, align) ((( x ) + (align) - 1) / (align) * (align)) #endif #define IJK_CHECK_RET(condition__, retval__, ...) \ if (!(condition__)) { \ ALOGE(__VA_ARGS__); \ return (retval__); \ } #ifndef NELEM #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0]))) #endif inline static void *mallocz(size_t size) { void *mem = malloc(size); if (!mem) return mem; memset(mem, 0, size); return mem; } inline static void freep(void **mem) { if (mem && *mem) { free(*mem); *mem = NULL; } } #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_mutex.c ================================================ /***************************************************************************** * ijksdl_mutex.c ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_mutex.h" #include #include #include #include "ijksdl_inc_internal.h" SDL_mutex *SDL_CreateMutex(void) { SDL_mutex *mutex; mutex = (SDL_mutex *) mallocz(sizeof(SDL_mutex)); if (!mutex) return NULL; if (pthread_mutex_init(&mutex->id, NULL) != 0) { free(mutex); return NULL; } return mutex; } void SDL_DestroyMutex(SDL_mutex *mutex) { if (mutex) { pthread_mutex_destroy(&mutex->id); free(mutex); } } void SDL_DestroyMutexP(SDL_mutex **mutex) { if (mutex) { SDL_DestroyMutex(*mutex); *mutex = NULL; } } int SDL_LockMutex(SDL_mutex *mutex) { assert(mutex); if (!mutex) return -1; return pthread_mutex_lock(&mutex->id); } int SDL_UnlockMutex(SDL_mutex *mutex) { assert(mutex); if (!mutex) return -1; return pthread_mutex_unlock(&mutex->id); } SDL_cond *SDL_CreateCond(void) { SDL_cond *cond; cond = (SDL_cond *) mallocz(sizeof(SDL_cond)); if (!cond) return NULL; if (pthread_cond_init(&cond->id, NULL) != 0) { free(cond); return NULL; } return cond; } void SDL_DestroyCond(SDL_cond *cond) { if (cond) { pthread_cond_destroy(&cond->id); free(cond); } } void SDL_DestroyCondP(SDL_cond **cond) { if (cond) { SDL_DestroyCond(*cond); *cond = NULL; } } int SDL_CondSignal(SDL_cond *cond) { assert(cond); if (!cond) return -1; return pthread_cond_signal(&cond->id); } int SDL_CondBroadcast(SDL_cond *cond) { assert(cond); if (!cond) return -1; return pthread_cond_broadcast(&cond->id); } int SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, uint32_t ms) { int retval; struct timeval delta; struct timespec abstime; assert(cond); assert(mutex); if (!cond || !mutex) { return -1; } gettimeofday(&delta, NULL); abstime.tv_sec = delta.tv_sec + (ms / 1000); abstime.tv_nsec = (delta.tv_usec + (ms % 1000) * 1000) * 1000; if (abstime.tv_nsec > 1000000000) { abstime.tv_sec += 1; abstime.tv_nsec -= 1000000000; } while (1) { retval = pthread_cond_timedwait(&cond->id, &mutex->id, &abstime); if (retval == 0) return 0; else if (retval == EINTR) continue; else if (retval == ETIMEDOUT) return SDL_MUTEX_TIMEDOUT; else break; } return -1; } int SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex) { assert(cond); assert(mutex); if (!cond || !mutex) return -1; return pthread_cond_wait(&cond->id, &mutex->id); } ================================================ FILE: ijkmedia/ijksdl/ijksdl_mutex.h ================================================ /***************************************************************************** * ijksdl_mutex.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_MUTEX_H #define IJKSDL__IJKSDL_MUTEX_H #include #include #define SDL_MUTEX_TIMEDOUT 1 #define SDL_MUTEX_MAXWAIT (~(uint32_t)0) typedef struct SDL_mutex { pthread_mutex_t id; } SDL_mutex; SDL_mutex *SDL_CreateMutex(void); void SDL_DestroyMutex(SDL_mutex *mutex); void SDL_DestroyMutexP(SDL_mutex **mutex); int SDL_LockMutex(SDL_mutex *mutex); int SDL_UnlockMutex(SDL_mutex *mutex); typedef struct SDL_cond { pthread_cond_t id; } SDL_cond; SDL_cond *SDL_CreateCond(void); void SDL_DestroyCond(SDL_cond *cond); void SDL_DestroyCondP(SDL_cond **mutex); int SDL_CondSignal(SDL_cond *cond); int SDL_CondBroadcast(SDL_cond *cond); int SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, uint32_t ms); int SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex); #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_stdinc.c ================================================ /***************************************************************************** * ijksdl_stdinc.c ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_stdinc.h" char *SDL_getenv(const char *name) { return NULL; } ================================================ FILE: ijkmedia/ijksdl/ijksdl_stdinc.h ================================================ /***************************************************************************** * ijksdl_stdinc.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_STDINC_H #define IJKSDL__IJKSDL_STDINC_H #include #include #include typedef int8_t Sint8; typedef uint8_t Uint8; typedef int16_t Sint16; typedef uint16_t Uint16; typedef int32_t Sint32; typedef uint32_t Uint32; typedef int64_t Sint64; typedef uint64_t Uint64; char *SDL_getenv(const char *name); #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_thread.c ================================================ /***************************************************************************** * ijksdl_thread.c ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "ijksdl_inc_internal.h" #include "ijksdl_thread.h" #ifdef __ANDROID__ #include "ijksdl/android/ijksdl_android_jni.h" #endif #if !defined(__APPLE__) // using ios implement for autorelease static void *SDL_RunThread(void *data) { SDL_Thread *thread = data; ALOGI("SDL_RunThread: [%d] %s\n", (int)gettid(), thread->name); pthread_setname_np(pthread_self(), thread->name); thread->retval = thread->func(thread->data); #ifdef __ANDROID__ SDL_JNI_DetachThreadEnv(); #endif return NULL; } SDL_Thread *SDL_CreateThreadEx(SDL_Thread *thread, int (*fn)(void *), void *data, const char *name) { thread->func = fn; thread->data = data; strlcpy(thread->name, name, sizeof(thread->name) - 1); int retval = pthread_create(&thread->id, NULL, SDL_RunThread, thread); if (retval) return NULL; return thread; } #endif int SDL_SetThreadPriority(SDL_ThreadPriority priority) { struct sched_param sched; int policy; pthread_t thread = pthread_self(); if (pthread_getschedparam(thread, &policy, &sched) < 0) { ALOGE("pthread_getschedparam() failed"); return -1; } if (priority == SDL_THREAD_PRIORITY_LOW) { sched.sched_priority = sched_get_priority_min(policy); } else if (priority == SDL_THREAD_PRIORITY_HIGH) { sched.sched_priority = sched_get_priority_max(policy); } else { int min_priority = sched_get_priority_min(policy); int max_priority = sched_get_priority_max(policy); sched.sched_priority = (min_priority + (max_priority - min_priority) / 2); } if (pthread_setschedparam(thread, policy, &sched) < 0) { ALOGE("pthread_setschedparam() failed"); return -1; } return 0; } void SDL_WaitThread(SDL_Thread *thread, int *status) { assert(thread); if (!thread) return; pthread_join(thread->id, NULL); if (status) *status = thread->retval; } void SDL_DetachThread(SDL_Thread *thread) { assert(thread); if (!thread) return; pthread_detach(thread->id); } ================================================ FILE: ijkmedia/ijksdl/ijksdl_thread.h ================================================ /***************************************************************************** * ijksdl_thread.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_THREAD_H #define IJKSDL__IJKSDL_THREAD_H #include #include typedef enum { SDL_THREAD_PRIORITY_LOW, SDL_THREAD_PRIORITY_NORMAL, SDL_THREAD_PRIORITY_HIGH } SDL_ThreadPriority; typedef struct SDL_Thread { pthread_t id; int (*func)(void *); void *data; char name[32]; int retval; } SDL_Thread; SDL_Thread *SDL_CreateThreadEx(SDL_Thread *thread, int (*fn)(void *), void *data, const char *name); int SDL_SetThreadPriority(SDL_ThreadPriority priority); void SDL_WaitThread(SDL_Thread *thread, int *status); void SDL_DetachThread(SDL_Thread *thread); #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_timer.c ================================================ /***************************************************************************** * ijksdl_thread.c ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_timer.h" #include #include #include #include #include #if defined(__APPLE__) #include static int g_is_mach_base_info_inited = 0; static kern_return_t g_mach_base_info_ret = 0; static mach_timebase_info_data_t g_mach_base_info; /* nanosleep is not included in c99, just a workaround for CocoaPods */ int nanosleep(const struct timespec *, struct timespec *) __DARWIN_ALIAS_C(nanosleep); #endif #include "ijksdl_log.h" void SDL_Delay(Uint32 ms) { int was_error; struct timespec elapsed, tv; /* Set the timeout interval */ elapsed.tv_sec = ms / 1000; elapsed.tv_nsec = (ms % 1000) * 1000000; do { tv.tv_sec = elapsed.tv_sec; tv.tv_nsec = elapsed.tv_nsec; was_error = nanosleep(&tv, &elapsed); } while (was_error); } Uint64 SDL_GetTickHR(void) { Uint64 clock; #if defined(__ANDROID__) struct timespec now; #ifdef CLOCK_MONOTONIC_COARSE clock_gettime(CLOCK_MONOTONIC_COARSE, &now); #else clock_gettime(CLOCK_MONOTONIC_HR, &now); #endif clock = now.tv_sec * 1000 + now.tv_nsec / 1000000; #elif defined(__APPLE__) if (!g_is_mach_base_info_inited) { g_mach_base_info_ret = mach_timebase_info(&g_mach_base_info); g_is_mach_base_info_inited = 1; } if (g_mach_base_info_ret == 0) { uint64_t now = mach_absolute_time(); clock = now * g_mach_base_info.numer / g_mach_base_info.denom / 1000000; } else { struct timeval now; gettimeofday(&now, NULL); clock = now.tv_sec * 1000 + now.tv_usec / 1000; } #endif return (clock); } void SDL_ProfilerReset(SDL_Profiler* profiler, int max_sample) { memset(profiler, 0, sizeof(SDL_Profiler)); if (max_sample < 0) profiler->max_sample = 3; else profiler->max_sample = max_sample; } void SDL_ProfilerBegin(SDL_Profiler* profiler) { profiler->begin_time = SDL_GetTickHR(); } int64_t SDL_ProfilerEnd(SDL_Profiler* profiler) { int64_t delta = SDL_GetTickHR() - profiler->begin_time; if (profiler->max_sample > 0) { profiler->total_elapsed += delta; profiler->total_counter += 1; profiler->sample_elapsed += delta; profiler->sample_counter += 1; if (profiler->sample_counter > profiler->max_sample) { profiler->sample_elapsed -= profiler->average_elapsed; profiler->sample_counter -= 1; } if (profiler->sample_counter > 0) { profiler->average_elapsed = profiler->sample_elapsed / profiler->sample_counter; } if (profiler->sample_elapsed > 0) { profiler->sample_per_seconds = profiler->sample_counter * 1000.f / profiler->sample_elapsed; } } return delta; } void SDL_SpeedSamplerReset(SDL_SpeedSampler *sampler) { memset(sampler, 0, sizeof(SDL_SpeedSampler)); sampler->capacity = sizeof(sampler->samples) / sizeof(Uint64); } float SDL_SpeedSamplerAdd(SDL_SpeedSampler *sampler, int enable_log, const char *log_tag) { Uint64 current = SDL_GetTickHR(); sampler->samples[sampler->next_index] = current; sampler->next_index++; sampler->next_index %= sampler->capacity; if (sampler->count + 1 >= sampler->capacity) { sampler->first_index++; sampler->first_index %= sampler->capacity; } else { sampler->count++; } if (sampler->count < 2) return 0; float samples_per_second = 1000.0f * (sampler->count - 1) / (current - sampler->samples[sampler->first_index]); if (enable_log && (sampler->last_log_time + 1000 < current || sampler->last_log_time > current)) { sampler->last_log_time = current; ALOGW("%s: %.2f\n", log_tag ? log_tag : "N/A", samples_per_second); } return samples_per_second; } void SDL_SpeedSampler2Reset(SDL_SpeedSampler2 *sampler, int sample_range) { memset(sampler, 0, sizeof(SDL_SpeedSampler2)); sampler->sample_range = sample_range; sampler->last_profile_tick = (int64_t)SDL_GetTickHR(); } int64_t SDL_SpeedSampler2Add(SDL_SpeedSampler2 *sampler, int quantity) { if (quantity < 0) return 0; int64_t sample_range = sampler->sample_range; int64_t last_tick = sampler->last_profile_tick; int64_t last_duration = sampler->last_profile_duration; int64_t last_quantity = sampler->last_profile_quantity; int64_t now = (int64_t)SDL_GetTickHR(); int64_t elapsed = (int64_t)llabs(now - last_tick); if (elapsed < 0 || elapsed >= sample_range) { // overflow, reset to initialized state sampler->last_profile_tick = now; sampler->last_profile_duration = sample_range; sampler->last_profile_quantity = quantity; sampler->last_profile_speed = quantity * 1000 / sample_range; return sampler->last_profile_speed; } int64_t new_quantity = last_quantity + quantity; int64_t new_duration = last_duration + elapsed; if (new_duration > sample_range) { new_quantity = new_quantity * sample_range / new_duration; new_duration = sample_range; } sampler->last_profile_tick = now; sampler->last_profile_duration = new_duration; sampler->last_profile_quantity = new_quantity; if (new_duration > 0) sampler->last_profile_speed = new_quantity * 1000 / new_duration; return sampler->last_profile_speed; } int64_t SDL_SpeedSampler2GetSpeed(SDL_SpeedSampler2 *sampler) { int64_t sample_range = sampler->sample_range; int64_t last_tick = sampler->last_profile_tick; int64_t last_quantity = sampler->last_profile_quantity; int64_t last_duration = sampler->last_profile_duration; int64_t now = (int64_t)SDL_GetTickHR(); int64_t elapsed = (int64_t)llabs(now - last_tick); if (elapsed < 0 || elapsed >= sample_range) return 0; int64_t new_quantity = last_quantity; int64_t new_duration = last_duration + elapsed; if (new_duration > sample_range) { new_quantity = new_quantity * sample_range / new_duration; new_duration = sample_range; } if (new_duration <= 0) return 0; return new_quantity * 1000 / new_duration; } ================================================ FILE: ijkmedia/ijksdl/ijksdl_timer.h ================================================ /***************************************************************************** * ijksdl_thread.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_TIMER_H #define IJKSDL__IJKSDL_TIMER_H #include "ijksdl_stdinc.h" void SDL_Delay(Uint32 ms); Uint64 SDL_GetTickHR(void); typedef struct SDL_Profiler { int64_t total_elapsed; int total_counter; int64_t sample_elapsed; int sample_counter; float sample_per_seconds; int64_t average_elapsed; int64_t begin_time; int max_sample; } SDL_Profiler; void SDL_ProfilerReset(SDL_Profiler* profiler, int max_sample); void SDL_ProfilerBegin(SDL_Profiler* profiler); int64_t SDL_ProfilerEnd(SDL_Profiler* profiler); typedef struct SDL_SpeedSampler { Uint64 samples[10]; int capacity; int count; int first_index; int next_index; Uint64 last_log_time; } SDL_SpeedSampler; void SDL_SpeedSamplerReset(SDL_SpeedSampler *sampler); // return samples per seconds float SDL_SpeedSamplerAdd(SDL_SpeedSampler *sampler, int enable_log, const char *log_tag); typedef struct SDL_SpeedSampler2 { int64_t sample_range; int64_t last_profile_tick; int64_t last_profile_duration; int64_t last_profile_quantity; int64_t last_profile_speed; } SDL_SpeedSampler2; void SDL_SpeedSampler2Reset(SDL_SpeedSampler2 *sampler, int sample_range); int64_t SDL_SpeedSampler2Add(SDL_SpeedSampler2 *sampler, int quantity); int64_t SDL_SpeedSampler2GetSpeed(SDL_SpeedSampler2 *sampler); #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_video.h ================================================ /***************************************************************************** * ijksdl_video.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_VIDEO_H #define IJKSDL__IJKSDL_VIDEO_H #include "ijksdl_stdinc.h" #include "ijksdl_fourcc.h" #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_vout.c ================================================ /***************************************************************************** * ijksdl_vout.c ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_vout.h" #include #include #if defined(__ANDROID__) #include #endif void SDL_VoutFree(SDL_Vout *vout) { if (!vout) return; if (vout->free_l) { vout->free_l(vout); } else { free(vout); } } void SDL_VoutFreeP(SDL_Vout **pvout) { if (!pvout) return; SDL_VoutFree(*pvout); *pvout = NULL; } int SDL_VoutDisplayYUVOverlay(SDL_Vout *vout, SDL_VoutOverlay *overlay) { if (vout && overlay && vout->display_overlay) return vout->display_overlay(vout, overlay); return -1; } int SDL_VoutSetOverlayFormat(SDL_Vout *vout, Uint32 overlay_format) { if (!vout) return -1; vout->overlay_format = overlay_format; return 0; } SDL_VoutOverlay *SDL_Vout_CreateOverlay(int width, int height, int frame_format, SDL_Vout *vout) { if (vout && vout->create_overlay) return vout->create_overlay(width, height, frame_format, vout); return NULL; } int SDL_VoutLockYUVOverlay(SDL_VoutOverlay *overlay) { if (overlay && overlay->lock) return overlay->lock(overlay); return -1; } int SDL_VoutUnlockYUVOverlay(SDL_VoutOverlay *overlay) { if (overlay && overlay->unlock) return overlay->unlock(overlay); return -1; } void SDL_VoutFreeYUVOverlay(SDL_VoutOverlay *overlay) { if (!overlay) return; if (overlay->free_l) { overlay->free_l(overlay); } else { free(overlay); } } void SDL_VoutUnrefYUVOverlay(SDL_VoutOverlay *overlay) { if (overlay && overlay->unref) overlay->unref(overlay); } int SDL_VoutFillFrameYUVOverlay(SDL_VoutOverlay *overlay, const AVFrame *frame) { if (!overlay || !overlay->func_fill_frame) return -1; return overlay->func_fill_frame(overlay, frame); } ================================================ FILE: ijkmedia/ijksdl/ijksdl_vout.h ================================================ /***************************************************************************** * ijksdl_vout.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_VOUT_H #define IJKSDL__IJKSDL_VOUT_H #include "ijksdl_stdinc.h" #include "ijksdl_class.h" #include "ijksdl_mutex.h" #include "ijksdl_video.h" #include "ffmpeg/ijksdl_inc_ffmpeg.h" typedef struct SDL_VoutOverlay_Opaque SDL_VoutOverlay_Opaque; typedef struct SDL_VoutOverlay SDL_VoutOverlay; struct SDL_VoutOverlay { int w; /**< Read-only */ int h; /**< Read-only */ Uint32 format; /**< Read-only */ int planes; /**< Read-only */ Uint16 *pitches; /**< in bytes, Read-only */ Uint8 **pixels; /**< Read-write */ int is_private; int sar_num; int sar_den; SDL_Class *opaque_class; SDL_VoutOverlay_Opaque *opaque; void (*free_l)(SDL_VoutOverlay *overlay); int (*lock)(SDL_VoutOverlay *overlay); int (*unlock)(SDL_VoutOverlay *overlay); void (*unref)(SDL_VoutOverlay *overlay); int (*func_fill_frame)(SDL_VoutOverlay *overlay, const AVFrame *frame); }; typedef struct SDL_Vout_Opaque SDL_Vout_Opaque; typedef struct SDL_Vout SDL_Vout; struct SDL_Vout { SDL_mutex *mutex; SDL_Class *opaque_class; SDL_Vout_Opaque *opaque; SDL_VoutOverlay *(*create_overlay)(int width, int height, int frame_format, SDL_Vout *vout); void (*free_l)(SDL_Vout *vout); int (*display_overlay)(SDL_Vout *vout, SDL_VoutOverlay *overlay); Uint32 overlay_format; }; void SDL_VoutFree(SDL_Vout *vout); void SDL_VoutFreeP(SDL_Vout **pvout); int SDL_VoutDisplayYUVOverlay(SDL_Vout *vout, SDL_VoutOverlay *overlay); int SDL_VoutSetOverlayFormat(SDL_Vout *vout, Uint32 overlay_format); SDL_VoutOverlay *SDL_Vout_CreateOverlay(int width, int height, int frame_format, SDL_Vout *vout); int SDL_VoutLockYUVOverlay(SDL_VoutOverlay *overlay); int SDL_VoutUnlockYUVOverlay(SDL_VoutOverlay *overlay); void SDL_VoutFreeYUVOverlay(SDL_VoutOverlay *overlay); void SDL_VoutUnrefYUVOverlay(SDL_VoutOverlay *overlay); int SDL_VoutFillFrameYUVOverlay(SDL_VoutOverlay *overlay, const AVFrame *frame); #endif ================================================ FILE: ijkmedia/ijksdl/ijksdl_vout_internal.h ================================================ /***************************************************************************** * ijksdl_vout_internal.h ***************************************************************************** * * Copyright (c) 2013 Bilibili * copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDL__IJKSDL_VOUT_INTERNAL_H #define IJKSDL__IJKSDL_VOUT_INTERNAL_H #include #include #include "ijksdl_vout.h" inline static SDL_Vout *SDL_Vout_CreateInternal(size_t opaque_size) { SDL_Vout *vout = (SDL_Vout*) calloc(1, sizeof(SDL_Vout)); if (!vout) return NULL; vout->opaque = calloc(1, opaque_size); if (!vout->opaque) { free(vout); return NULL; } vout->mutex = SDL_CreateMutex(); if (vout->mutex == NULL) { free(vout->opaque); free(vout); return NULL; } return vout; } inline static void SDL_Vout_FreeInternal(SDL_Vout *vout) { if (!vout) return; if (vout->mutex) { SDL_DestroyMutex(vout->mutex); } free(vout->opaque); memset(vout, 0, sizeof(SDL_Vout)); free(vout); } inline static SDL_VoutOverlay *SDL_VoutOverlay_CreateInternal(size_t opaque_size) { SDL_VoutOverlay *overlay = (SDL_VoutOverlay*) calloc(1, sizeof(SDL_VoutOverlay)); if (!overlay) return NULL; overlay->opaque = calloc(1, opaque_size); if (!overlay->opaque) { free(overlay); return NULL; } return overlay; } inline static void SDL_VoutOverlay_FreeInternal(SDL_VoutOverlay *overlay) { if (!overlay) return; if (overlay->opaque) free(overlay->opaque); memset(overlay, 0, sizeof(SDL_VoutOverlay)); free(overlay); } #endif ================================================ FILE: ijkprof/android-ndk-profiler-dummy/jni/Android-include.mk ================================================ # Copyright (c) 2013 Bilibili # copyright (c) 2013 Zhang Rui # # This file is part of ijkPlayer. # # ijkPlayer 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. # # ijkPlayer 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 ijkPlayer; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # do nothing here ================================================ FILE: ijkprof/android-ndk-profiler-dummy/jni/Android.mk ================================================ # Copyright (c) 2015 Bilibili # copyright (c) 2015 Zhang Rui # # This file is part of ijkPlayer. # # ijkPlayer 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. # # ijkPlayer 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 ijkPlayer; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := android-ndk-profiler LOCAL_SRC_FILES := prof.c include $(BUILD_STATIC_LIBRARY) ================================================ FILE: ijkprof/android-ndk-profiler-dummy/jni/prof.c ================================================ /***************************************************************************** * prof.c ***************************************************************************** * * Copyright (c) 2015 Bilibili * copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "prof.h" #include extern void monstartup(const char *libname) { __android_log_print(ANDROID_LOG_DEBUG, "aprof-fake", "fake-monstartup %s\n", libname); } extern void moncleanup(void) { __android_log_print(ANDROID_LOG_DEBUG, "aprof-fake", "fake-momcleanup\n"); } ================================================ FILE: ijkprof/android-ndk-profiler-dummy/jni/prof.h ================================================ /***************************************************************************** * prof.c ***************************************************************************** * * Copyright (c) 2015 Bilibili * copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef ANDROID_NDK_PROF__PROF_H #define ANDROID_NDK_PROF__PROF_H #ifdef __cplusplus extern "C" { #endif void monstartup(const char *libname); void moncleanup(void); #ifdef __cplusplus } #endif #endif//ANDROID_NDK_PROF__PROF_H ================================================ FILE: init-android-exo.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2015 Bilibili # Copyright (C) 2013-2015 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # IJK_EXO_UPSTREAM=https://github.com/google/ExoPlayer.git IJK_EXO_FORK=https://github.com/google/ExoPlayer.git IJK_EXO_COMMIT=r1.5.11 IJK_EXO_LOCAL_REPO=extra/ExoPlayer set -e TOOLS=tools echo "== pull ExoPlayer base ==" sh $TOOLS/pull-repo-base.sh $IJK_EXO_UPSTREAM $IJK_EXO_LOCAL_REPO echo "== pull ExoPlayer fork ==" cd extra/ExoPlayer git checkout ${IJK_EXO_COMMIT} -B ijkplayer cd - SRC_EXO_DIR=extra/ExoPlayer/demo/src/main/java/com/google/android/exoplayer/demo DST_EXO_DIR=android/ijkplayer/ijkplayer-exo/src/main/java/tv/danmaku/ijk/media/exo/demo mkdir -p $DST_EXO_DIR/player function install_java() { JAVA_FILE=$1 cat $SRC_EXO_DIR/$JAVA_FILE \ | sed "s/^package com.google.android.exoplayer.demo/package tv.danmaku.ijk.media.exo.demo/g" \ | sed "s/^import com.google.android.exoplayer.demo/import tv.danmaku.ijk.media.exo.demo/g" \ | sed "s/@link/link/g" \ > $DST_EXO_DIR/$JAVA_FILE } install_java player/DashRendererBuilder.java install_java player/DemoPlayer.java install_java player/ExtractorRendererBuilder.java install_java player/HlsRendererBuilder.java install_java player/SmoothStreamingRendererBuilder.java install_java EventLogger.java install_java SmoothStreamingTestMediaDrmCallback.java # install_java WidevineTestMediaDrmCallback.java ================================================ FILE: init-android-j4a.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2016 Bilibili # Copyright (C) 2016 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # IJK_J4A_UPSTREAM=https://github.com/Bilibili/jni4android.git IJK_J4A_FORK=https://github.com/Bilibili/jni4android.git IJK_J4A_COMMIT=v0.0.2 IJK_J4A_LOCAL_REPO=extra/jni4android set -e TOOLS=tools echo "== pull j4a base ==" sh $TOOLS/pull-repo-base.sh $IJK_J4A_UPSTREAM $IJK_J4A_LOCAL_REPO echo "== pull j4a fork ==" sh $TOOLS/pull-repo-ref.sh $IJK_J4A_FORK extra/jni4android-fork ${IJK_J4A_LOCAL_REPO} cd extra/jni4android-fork git checkout ${IJK_J4A_COMMIT} cd - ================================================ FILE: init-android-libsoxr.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2015 Bilibili # Copyright (C) 2013-2015 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # IJK_LIBSOXR_UPSTREAM=http://git.code.sf.net/p/soxr/code IJK_LIBSOXR_FORK=http://git.code.sf.net/p/soxr/code IJK_LIBSOXR_COMMIT=0.1.2 IJK_LIBSOXR_COMMIT_64=master IJK_LIBSOXR_LOCAL_REPO=extra/soxr set -e TOOLS=tools echo "== pull soxr base ==" sh $TOOLS/pull-repo-base.sh $IJK_LIBSOXR_UPSTREAM $IJK_LIBSOXR_LOCAL_REPO function pull_fork() { echo "== pull soxr fork $1 ==" sh $TOOLS/pull-repo-ref.sh $IJK_LIBSOXR_FORK android/contrib/libsoxr-$1 ${IJK_LIBSOXR_LOCAL_REPO} cp extra/android-cmake/android.toolchain.cmake android/contrib/libsoxr-$1 cd android/contrib/libsoxr-$1 case "$1" in arm64|x86_64) git checkout ${IJK_LIBSOXR_COMMIT_64} -B ijkplayer ;; *) git checkout ${IJK_LIBSOXR_COMMIT} -B ijkplayer ;; esac cd - } function pull_android_toolchain_cmake() { ANDROID_TOOLCHAIN_CMAKE_UPSTREAM=https://github.com/taka-no-me/android-cmake.git echo "== pull android toolchain cmake from $ANDROID_TOOLCHAIN_CMAKE_UPSTREAM ==" sh $TOOLS/pull-repo-base.sh $ANDROID_TOOLCHAIN_CMAKE_UPSTREAM extra/android-cmake } pull_android_toolchain_cmake pull_fork "armv5" pull_fork "armv7a" pull_fork "arm64" pull_fork "x86" pull_fork "x86_64" ================================================ FILE: init-android-libyuv.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2015 Bilibili # Copyright (C) 2013-2015 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # IJK_LIBYUV_UPSTREAM=https://github.com/Bilibili/libyuv.git IJK_LIBYUV_FORK=https://github.com/Bilibili/libyuv.git IJK_LIBYUV_COMMIT=ijk-r0.2.1-dev IJK_LIBYUV_LOCAL_REPO=extra/libyuv set -e TOOLS=tools echo "== pull libyuv base ==" sh $TOOLS/pull-repo-base.sh $IJK_LIBYUV_UPSTREAM $IJK_LIBYUV_LOCAL_REPO echo "== pull libyuv fork ==" sh $TOOLS/pull-repo-ref.sh $IJK_LIBYUV_FORK ijkmedia/ijkyuv ${IJK_LIBYUV_LOCAL_REPO} cd ijkmedia/ijkyuv git checkout ${IJK_LIBYUV_COMMIT} cd - ================================================ FILE: init-android-openssl.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2015 Bilibili # Copyright (C) 2013-2015 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # #IJK_OPENSSL_UPSTREAM=https://github.com/openssl/openssl IJK_OPENSSL_UPSTREAM=https://github.com/Bilibili/openssl.git IJK_OPENSSL_FORK=https://github.com/Bilibili/openssl.git IJK_OPENSSL_COMMIT=OpenSSL_1_0_2q IJK_OPENSSL_LOCAL_REPO=extra/openssl set -e TOOLS=tools echo "== pull openssl base ==" sh $TOOLS/pull-repo-base.sh $IJK_OPENSSL_UPSTREAM $IJK_OPENSSL_LOCAL_REPO function pull_fork() { echo "== pull openssl fork $1 ==" sh $TOOLS/pull-repo-ref.sh $IJK_OPENSSL_FORK android/contrib/openssl-$1 ${IJK_OPENSSL_LOCAL_REPO} cd android/contrib/openssl-$1 git checkout ${IJK_OPENSSL_COMMIT} -B ijkplayer cd - } pull_fork "armv5" pull_fork "armv7a" pull_fork "arm64" pull_fork "x86" pull_fork "x86_64" ================================================ FILE: init-android-prof.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2015 Bilibili # Copyright (C) 2013-2015 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # IJK_LIB_NAME=android-ndk-profiler IJK_LIB_UPSTREAM=https://github.com/Bilibili/android-ndk-profiler.git IJK_LIB_FORK=https://github.com/Bilibili/android-ndk-profiler.git IJK_LIB_COMMIT=ijk-r0.3.0-dev IJK_LIB_LOCAL_REPO=extra/android-ndk-profiler set -e TOOLS=tools echo "== pull $IJK_LIB_NAME base ==" sh $TOOLS/pull-repo-base.sh $IJK_LIB_UPSTREAM $IJK_LIB_LOCAL_REPO echo "== pull $IJK_LIB_NAME fork ==" sh $TOOLS/pull-repo-ref.sh $IJK_LIB_FORK ijkprof/$IJK_LIB_NAME ${IJK_LIB_LOCAL_REPO} cd ijkprof/$IJK_LIB_NAME git checkout ${IJK_LIB_COMMIT} cd - ================================================ FILE: init-android-soundtouch.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2015 Bilibili # Copyright (C) 2013-2015 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # IJK_SOUNDTOUCH_UPSTREAM=https://github.com/Bilibili/soundtouch.git IJK_SOUNDTOUCH_FORK=https://github.com/Bilibili/soundtouch.git IJK_SOUNDTOUCH_COMMIT=ijk-r0.1.2-dev IJK_SOUNDTOUCH_LOCAL_REPO=extra/soundtouch set -e TOOLS=tools echo "== pull soundtouch base ==" sh $TOOLS/pull-repo-base.sh $IJK_SOUNDTOUCH_UPSTREAM $IJK_SOUNDTOUCH_LOCAL_REPO echo "== pull soundtouch fork ==" sh $TOOLS/pull-repo-ref.sh $IJK_SOUNDTOUCH_FORK ijkmedia/ijksoundtouch ${IJK_SOUNDTOUCH_LOCAL_REPO} cd ijkmedia/ijksoundtouch git checkout ${IJK_SOUNDTOUCH_COMMIT} cd - ================================================ FILE: init-android.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2015 Bilibili # Copyright (C) 2013-2015 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # 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=ff4.0--ijk0.8.8--20210426--001 IJK_FFMPEG_LOCAL_REPO=extra/ffmpeg set -e TOOLS=tools git --version echo "== pull ffmpeg base ==" sh $TOOLS/pull-repo-base.sh $IJK_FFMPEG_UPSTREAM $IJK_FFMPEG_LOCAL_REPO function pull_fork() { echo "== pull ffmpeg fork $1 ==" sh $TOOLS/pull-repo-ref.sh $IJK_FFMPEG_FORK android/contrib/ffmpeg-$1 ${IJK_FFMPEG_LOCAL_REPO} cd android/contrib/ffmpeg-$1 git checkout ${IJK_FFMPEG_COMMIT} -B ijkplayer cd - } pull_fork "armv5" pull_fork "armv7a" pull_fork "arm64" pull_fork "x86" pull_fork "x86_64" ./init-config.sh ./init-android-libyuv.sh ./init-android-soundtouch.sh ================================================ FILE: init-config.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2015 Bilibili # Copyright (C) 2013-2015 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # if [ ! -f 'config/module.sh' ]; then cp config/module-lite.sh config/module.sh fi ================================================ FILE: init-ios-openssl.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2015 Bilibili # Copyright (C) 2013-2015 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # IJK_OPENSSL_UPSTREAM=https://github.com/openssl/openssl IJK_OPENSSL_FORK=https://github.com/Bilibili/openssl.git IJK_OPENSSL_COMMIT=OpenSSL_1_0_2q IJK_OPENSSL_LOCAL_REPO=extra/openssl set -e TOOLS=tools echo "== pull openssl base ==" sh $TOOLS/pull-repo-base.sh $IJK_OPENSSL_UPSTREAM $IJK_OPENSSL_LOCAL_REPO function pull_fork() { echo "== pull openssl fork $1 ==" sh $TOOLS/pull-repo-ref.sh $IJK_OPENSSL_FORK ios/openssl-$1 ${IJK_OPENSSL_LOCAL_REPO} cd ios/openssl-$1 git checkout ${IJK_OPENSSL_COMMIT} -B ijkplayer cd - } pull_fork "armv7" pull_fork "armv7s" pull_fork "arm64" pull_fork "i386" pull_fork "x86_64" ================================================ FILE: init-ios.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2015 Bilibili # Copyright (C) 2013-2015 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # 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=ff4.0--ijk0.8.8--20210426--001 IJK_FFMPEG_LOCAL_REPO=extra/ffmpeg IJK_GASP_UPSTREAM=https://github.com/Bilibili/gas-preprocessor.git # gas-preprocessor backup # https://github.com/Bilibili/gas-preprocessor.git if [ "$IJK_FFMPEG_REPO_URL" != "" ]; then IJK_FFMPEG_UPSTREAM=$IJK_FFMPEG_REPO_URL IJK_FFMPEG_FORK=$IJK_FFMPEG_REPO_URL fi if [ "$IJK_GASP_REPO_URL" != "" ]; then IJK_GASP_UPSTREAM=$IJK_GASP_REPO_URL fi set -e TOOLS=tools FF_ALL_ARCHS_IOS6_SDK="armv7 armv7s i386" FF_ALL_ARCHS_IOS7_SDK="armv7 armv7s arm64 i386 x86_64" FF_ALL_ARCHS_IOS8_SDK="armv7 arm64 i386 x86_64" FF_ALL_ARCHS=$FF_ALL_ARCHS_IOS8_SDK FF_TARGET=$1 function echo_ffmpeg_version() { echo $IJK_FFMPEG_COMMIT } function pull_common() { git --version echo "== pull gas-preprocessor base ==" sh $TOOLS/pull-repo-base.sh $IJK_GASP_UPSTREAM extra/gas-preprocessor echo "== pull ffmpeg base ==" sh $TOOLS/pull-repo-base.sh $IJK_FFMPEG_UPSTREAM $IJK_FFMPEG_LOCAL_REPO } function pull_fork() { echo "== pull ffmpeg fork $1 ==" sh $TOOLS/pull-repo-ref.sh $IJK_FFMPEG_FORK ios/ffmpeg-$1 ${IJK_FFMPEG_LOCAL_REPO} cd ios/ffmpeg-$1 git checkout ${IJK_FFMPEG_COMMIT} -B ijkplayer cd - } function pull_fork_all() { for ARCH in $FF_ALL_ARCHS do pull_fork $ARCH done } function sync_ff_version() { sed -i '' "s/static const char \*kIJKFFRequiredFFmpegVersion\ \=\ .*/static const char *kIJKFFRequiredFFmpegVersion = \"${IJK_FFMPEG_COMMIT}\";/g" ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m } #---------- case "$FF_TARGET" in ffmpeg-version) echo_ffmpeg_version ;; armv7|armv7s|arm64|i386|x86_64) pull_common pull_fork $FF_TARGET ;; all|*) pull_common pull_fork_all ;; esac sync_ff_version ================================================ FILE: ios/.gitignore ================================================ xcuserdata xcshareddata *.xccheckout ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/AppIcons.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "29x29", "scale" : "1x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "57x57", "scale" : "1x" }, { "idiom" : "iphone", "size" : "57x57", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/Barcode.h ================================================ // // Barcode.h // featurebuild // // Created by Jake Widmer on 10/5/13. // Copyright (c) 2013 Jake Widmer. All rights reserved. // #import #import @interface Barcode : NSObject + (Barcode * )processMetadataObject:(AVMetadataMachineReadableCodeObject*) code; - (NSString *) getBarcodeType; - (NSString *) getBarcodeData; - (void) printBarcodeData; @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/Barcode.m ================================================ // // Barcode.m // featurebuild // // Created by Jake Widmer on 10/5/13. // Copyright (c) 2013 Jake Widmer. All rights reserved. // #import "Barcode.h" @interface Barcode() @property (nonatomic, strong) AVMetadataMachineReadableCodeObject *metadataObject; @property (nonatomic, strong) NSString * barcodeType; @property (nonatomic, strong) NSString * barcodeData; @property (nonatomic, strong) UIBezierPath *cornersPath; @property (nonatomic, strong) UIBezierPath *boundingBoxPath; @end @implementation Barcode + (Barcode * )processMetadataObject: (AVMetadataMachineReadableCodeObject*)code { // 1 create the obj Barcode * barcode=[[Barcode alloc]init]; // 2 store code type and string barcode.barcodeType = [NSString stringWithString:code.type]; barcode.barcodeData = [NSString stringWithString:code.stringValue]; barcode.metadataObject = code; // 3 & 4 Create the path joining code's corners CGMutablePathRef cornersPath = CGPathCreateMutable(); // 5 Make point CGPoint point; CGPointMakeWithDictionaryRepresentation( (CFDictionaryRef)code.corners[0], &point); // 6 Make path CGPathMoveToPoint(cornersPath, nil, point.x, point.y); // 7 for (int i = 1; i < code.corners.count; i++) { CGPointMakeWithDictionaryRepresentation( (CFDictionaryRef)code.corners[i], &point); CGPathAddLineToPoint(cornersPath, nil, point.x, point.y); } // 8 Finish box CGPathCloseSubpath(cornersPath); // 9 Set path barcode.cornersPath = [UIBezierPath bezierPathWithCGPath:cornersPath]; CGPathRelease(cornersPath); // Create the path for the code's bounding box // 10 barcode.boundingBoxPath = [UIBezierPath bezierPathWithRect:code.bounds]; // 11 return return barcode; } - (NSString *) getBarcodeType{ return self.barcodeType; } - (NSString *) getBarcodeData{ return self.barcodeData; } - (void) printBarcodeData{ NSLog(@"Barcode of type: %@ and data: %@",self.metadataObject.type, self.barcodeData); } @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKAppDelegate.h ================================================ /* * Copyright (C) 2013-2015 Bilibili * Copyright (C) 2013-2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import @interface IJKAppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @property (strong, nonatomic) UIViewController *viewController; @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKAppDelegate.m ================================================ /* * Copyright (C) 2013-2015 Bilibili * Copyright (C) 2013-2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import "IJKAppDelegate.h" #import "IJKDemoMainViewController.h" @implementation IJKAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:[[IJKDemoMainViewController alloc] init]]; self.viewController = navigationController; self.window.rootViewController = self.viewController; [self.window makeKeyAndVisible]; return YES; } - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKCommon.h ================================================ /* * Copyright (C) 2013-2015 Bilibili * Copyright (C) 2013-2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import #define IOS_OLDER_THAN_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] < 6.0 ) #define IOS_NEWER_OR_EQUAL_TO_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 6.0 ) #define IOS_NEWER_OR_EQUAL_TO_7 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 7.0 ) ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKDemoHistory.h ================================================ /* * Copyright (C) 2015 Gdier * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import @interface IJKDemoHistoryItem : NSObject @property(nonatomic,strong) NSString *title; @property(nonatomic,strong) NSURL *url; @end @interface IJKDemoHistory : NSObject + (instancetype)instance; @property(nonatomic,strong,readonly) NSArray *list; - (void)removeAtIndex:(NSUInteger)index; - (void)add:(IJKDemoHistoryItem *)item; @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKDemoHistory.m ================================================ /* * Copyright (C) 2015 Gdier * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import "IJKDemoHistory.h" @implementation IJKDemoHistoryItem - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:self.url forKey:@"url"]; [aCoder encodeObject:self.title forKey:@"title"]; } - (instancetype)initWithCoder:(NSCoder *)coder { self = [super init]; if (self) { self.title = [coder decodeObjectForKey:@"title"]; self.url = [coder decodeObjectForKey:@"url"]; } return self; } @end @interface IJKDemoHistory () @end @implementation IJKDemoHistory { NSMutableArray *_list; } + (instancetype)instance { static IJKDemoHistory *s_obj = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ s_obj = [[IJKDemoHistory alloc] init]; }); return s_obj; } - (instancetype)init { self = [super init]; if (self) { _list = [NSKeyedUnarchiver unarchiveObjectWithFile:[self dbfilePath]]; if (nil == _list) _list = [NSMutableArray array]; } return self; } - (NSString *)dbfilePath { NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSAllDomainsMask, YES) firstObject]; libraryPath = [libraryPath stringByAppendingPathComponent:@"ijkhistory.plist"]; return libraryPath; } - (NSArray *)list { return _list; } - (void)removeAtIndex:(NSUInteger)index { [_list removeObjectAtIndex:index]; [NSKeyedArchiver archiveRootObject:_list toFile:[self dbfilePath]]; } - (void)add:(IJKDemoHistoryItem *)item { __block NSUInteger findIdx = NSNotFound; [_list enumerateObjectsUsingBlock:^(IJKDemoHistoryItem *enumItem, NSUInteger idx, BOOL *stop) { if ([enumItem.url isEqual:item.url]) { findIdx = idx; *stop = YES; } }]; if (NSNotFound != findIdx) { [_list removeObjectAtIndex:findIdx]; } [_list insertObject:item atIndex:0]; [NSKeyedArchiver archiveRootObject:_list toFile:[self dbfilePath]]; } @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKDemoInputURLViewController.h ================================================ /* * Copyright (C) 2015 Gdier * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import @interface IJKDemoInputURLViewController : UIViewController @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKDemoInputURLViewController.m ================================================ /* * Copyright (C) 2015 Gdier * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import "IJKDemoInputURLViewController.h" #import "IJKMoviePlayerViewController.h" @interface IJKDemoInputURLViewController () @property(nonatomic,strong) IBOutlet UITextView *textView; @end @implementation IJKDemoInputURLViewController - (instancetype)init { self = [super init]; if (self) { self.title = @"Input URL"; [self.navigationItem setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:@"Play" style:UIBarButtonItemStyleDone target:self action:@selector(onClickPlayButton)]]; } return self; } - (void)viewDidLoad { [super viewDidLoad]; } - (void)onClickPlayButton { NSURL *url = [NSURL URLWithString:self.textView.text]; NSString *scheme = [[url scheme] lowercaseString]; if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"] || [scheme isEqualToString:@"rtmp"]) { [IJKVideoViewController presentFromViewController:self withTitle:[NSString stringWithFormat:@"URL: %@", url] URL:url completion:^{ // [self.navigationController popViewControllerAnimated:NO]; }]; } } - (void)textViewDidEndEditing:(UITextView *)textView { [self onClickPlayButton]; } @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKDemoInputURLViewController.xib ================================================ ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKDemoLocalFolderViewController.h ================================================ /* * Copyright (C) 2015 Gdier * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import @interface IJKDemoLocalFolderViewController : UITableViewController - (instancetype)initWithFolderPath:(NSString *)folderPath; @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKDemoLocalFolderViewController.m ================================================ /* * Copyright (C) 2015 Gdier * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import "IJKDemoLocalFolderViewController.h" #import "IJKMoviePlayerViewController.h" @interface IJKDemoLocalFolderViewController () @end @implementation IJKDemoLocalFolderViewController { NSString *_folderPath; NSMutableArray *_subpaths; NSMutableArray *_files; } - (instancetype)initWithFolderPath:(NSString *)folderPath { self = [super init]; if (self) { folderPath = [folderPath stringByStandardizingPath]; self.title = [folderPath lastPathComponent]; _folderPath = folderPath; _subpaths = [NSMutableArray array]; _files = [NSMutableArray array]; } return self; } - (void)viewDidLoad { [super viewDidLoad]; NSError *error = nil; BOOL isDirectory = NO; NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:_folderPath error:&error]; [_subpaths addObject:@".."]; for (NSString *fileName in files) { NSString *fullFileName = [_folderPath stringByAppendingPathComponent:fileName]; [[NSFileManager defaultManager] fileExistsAtPath:fullFileName isDirectory:&isDirectory]; if (isDirectory) { [_subpaths addObject:fileName]; } else { [_files addObject:fileName]; } } } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 2; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { switch (section) { case 0: return _subpaths.count; case 1: return _files.count; default: break; } return 0; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"abc"]; if (nil == cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"abc"]; cell.textLabel.lineBreakMode = NSLineBreakByTruncatingMiddle; } switch (indexPath.section) { case 0: { cell.textLabel.text = [NSString stringWithFormat:@"[%@]", _subpaths[indexPath.row]]; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } break; case 1: { cell.textLabel.text = _files[indexPath.row]; cell.accessoryType = UITableViewCellAccessoryNone; } break; default: break; } return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; switch (indexPath.section) { case 0: { NSString *fileName = [_folderPath stringByAppendingPathComponent:_subpaths[indexPath.row]]; IJKDemoLocalFolderViewController *viewController = [[IJKDemoLocalFolderViewController alloc] initWithFolderPath:fileName]; [self.navigationController pushViewController:viewController animated:YES]; } break; case 1: { NSString *fileName = [_folderPath stringByAppendingPathComponent:_files[indexPath.row]]; fileName = [fileName stringByStandardizingPath]; [IJKVideoViewController presentFromViewController:self withTitle:[NSString stringWithFormat:@"File: %@", fileName] URL:[NSURL fileURLWithPath:fileName] completion:^{ }]; } break; default: break; } } /* // Override to support conditional editing of the table view. - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { // Return NO if you do not want the specified item to be editable. return YES; } */ /* // Override to support editing the table view. - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { // Delete the row from the data source [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } else if (editingStyle == UITableViewCellEditingStyleInsert) { // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view } } */ /* // Override to support rearranging the table view. - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { } */ /* // Override to support conditional rearranging of the table view. - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { // Return NO if you do not want the item to be re-orderable. return YES; } */ /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKDemoMainViewController.h ================================================ /* * Copyright (C) 2015 Gdier * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import @interface IJKDemoMainViewController : UIViewController @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKDemoMainViewController.m ================================================ /* * Copyright (C) 2015 Gdier * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import "IJKDemoMainViewController.h" #import "IJKDemoInputURLViewController.h" #import "IJKQRCodeScanViewController.h" #import "IJKCommon.h" #import "IJKDemoHistory.h" #import "IJKMoviePlayerViewController.h" #import "IJKDemoLocalFolderViewController.h" #import "IJKDemoSampleViewController.h" #import @interface IJKDemoMainViewController () @property(nonatomic,strong) IBOutlet UITableView *tableView; @property(nonatomic,strong) NSArray *tableViewCellTitles; @property(nonatomic,strong) NSArray *historyList; @end @implementation IJKDemoMainViewController - (void)viewDidLoad { [super viewDidLoad]; self.title = @"Main"; self.tableViewCellTitles = @[ @"Local Folder", @"Movie Picker", @"Input URL", @"Scan QRCode", @"Online Samples", ]; NSURL *documentsUrl = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject]; NSError *error = nil; [documentsUrl setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.historyList = [[IJKDemoHistory instance] list]; [self.tableView reloadData]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 2; } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { switch (section) { case 0: return @"Open from"; case 1: return @"History"; default: return nil; } } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { switch (section) { case 0: if (IOS_NEWER_OR_EQUAL_TO_7) { return self.tableViewCellTitles.count; } else { return self.tableViewCellTitles.count - 1; } case 1: return self.historyList.count; default: return 0; } } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"abc"]; if (nil == cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"abc"]; cell.textLabel.lineBreakMode = NSLineBreakByTruncatingMiddle; } switch (indexPath.section) { case 0: cell.textLabel.text = self.tableViewCellTitles[indexPath.row]; break; case 1: cell.textLabel.text = [self.historyList[indexPath.row] title]; break; default: break; } return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; switch (indexPath.section) { case 0: { switch (indexPath.row) { case 0: { NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; IJKDemoLocalFolderViewController *viewController = [[IJKDemoLocalFolderViewController alloc] initWithFolderPath:documentsPath]; [self.navigationController pushViewController:viewController animated:YES]; } break; case 1: [self startMediaBrowserFromViewController: self usingDelegate: self]; break; case 2: [self.navigationController pushViewController:[[IJKDemoInputURLViewController alloc] init] animated:YES]; break; case 3: [self.navigationController pushViewController:[[IJKQRCodeScanViewController alloc] init] animated:YES]; break; case 4: [self.navigationController pushViewController:[[IJKDemoSampleViewController alloc] init] animated:YES]; break; default: break; } } break; case 1: { IJKDemoHistoryItem *historyItem = self.historyList[indexPath.row]; [IJKVideoViewController presentFromViewController:self withTitle:historyItem.title URL:historyItem.url completion:^{ [self.navigationController popViewControllerAnimated:NO]; }]; } break; default: break; } } - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { return (indexPath.section == 1); } - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section == 1) { return UITableViewCellEditingStyleDelete; } return UITableViewCellEditingStyleNone; } - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section == 1 && editingStyle == UITableViewCellEditingStyleDelete) { [[IJKDemoHistory instance] removeAtIndex:indexPath.row]; self.historyList = [[IJKDemoHistory instance] list]; [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; } } #pragma mark UIImagePickerControllerDelegate - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType]; NSURL *movieUrl; // Handle a movied picked from a photo album if (CFStringCompare ((CFStringRef) mediaType, kUTTypeMovie, 0) == kCFCompareEqualTo) { NSString *moviePath = [[info objectForKey: UIImagePickerControllerMediaURL] path]; movieUrl = [NSURL URLWithString:moviePath]; } [self dismissViewControllerAnimated:YES completion:^(void){ [self.navigationController pushViewController:[[IJKVideoViewController alloc] initWithURL:movieUrl] animated:YES]; }]; } - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { [self dismissViewControllerAnimated:YES completion:NULL]; } #pragma mark misc - (BOOL) startMediaBrowserFromViewController: (UIViewController*) controller usingDelegate: (id ) delegate { if (([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeSavedPhotosAlbum] == NO) || (delegate == nil) || (controller == nil)) return NO; UIImagePickerController *mediaUI = [[UIImagePickerController alloc] init]; mediaUI.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum; // Displays saved pictures and movies, if both are available, from the // Camera Roll album. mediaUI.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeMovie, nil]; // Hides the controls for moving & scaling pictures, or for // trimming movies. To instead show the controls, use YES. mediaUI.allowsEditing = NO; mediaUI.delegate = delegate; [controller presentViewController:mediaUI animated:YES completion:nil]; return YES; } @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKDemoMainViewController.xib ================================================ ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKDemoSampleViewController.h ================================================ /* * Copyright (C) 2013-2015 Bilibili * Copyright (C) 2013-2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import @interface IJKDemoSampleViewController : UIViewController @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKDemoSampleViewController.m ================================================ /* * Copyright (C) 2013-2015 Bilibili * Copyright (C) 2013-2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import "IJKDemoSampleViewController.h" #import "IJKCommon.h" #import "IJKMoviePlayerViewController.h" @interface IJKDemoSampleViewController () @property(nonatomic,strong) IBOutlet UITableView *tableView; @property(nonatomic,strong) NSArray *sampleList; @end @implementation IJKDemoSampleViewController - (void)viewDidLoad { [super viewDidLoad]; self.title = @"M3U8"; NSMutableArray *sampleList = [[NSMutableArray alloc] init]; [sampleList addObject:@[@"las url", @"{\"version\":\"1.0.0\",\"adaptationSet\":[{\"duration\":1000,\"id\":1,\"representation\":[{\"id\":1,\"codec\":\"avc1.64001e,mp4a.40.5\",\"url\":\"http://las-tech.org.cn/kwai/las-test_ld500d.flv\",\"backupUrl\":[],\"host\":\"las-tech.org.cn\",\"maxBitrate\":700,\"width\":640,\"height\":360,\"frameRate\":25,\"qualityType\":\"SMOOTH\",\"qualityTypeName\":\"流畅\",\"hidden\":false,\"disabledFromAdaptive\":false,\"defaultSelected\":false},{\"id\":2,\"codec\":\"avc1.64001f,mp4a.40.5\",\"url\":\"http://las-tech.org.cn/kwai/las-test_sd1000d.flv\",\"backupUrl\":[],\"host\":\"las-tech.org.cn\",\"maxBitrate\":1300,\"width\":960,\"height\":540,\"frameRate\":25,\"qualityType\":\"STANDARD\",\"qualityTypeName\":\"标清\",\"hidden\":false,\"disabledFromAdaptive\":false,\"defaultSelected\":true},{\"id\":3,\"codec\":\"avc1.64001f,mp4a.40.5\",\"url\":\"http://las-tech.org.cn/kwai/las-test.flv\",\"backupUrl\":[],\"host\":\"las-tech.org.cn\",\"maxBitrate\":2300,\"width\":1280,\"height\":720,\"frameRate\":30,\"qualityType\":\"HIGH\",\"qualityTypeName\":\"高清\",\"hidden\":false,\"disabledFromAdaptive\":false,\"defaultSelected\":false}]}]}"]]; [sampleList addObject:@[@"bipbop basic master playlist", @"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8"]]; [sampleList addObject:@[@"bipbop basic 400x300 @ 232 kbps", @"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/prog_index.m3u8"]]; [sampleList addObject:@[@"bipbop basic 640x480 @ 650 kbps", @"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear2/prog_index.m3u8"]]; [sampleList addObject:@[@"bipbop basic 640x480 @ 1 Mbps", @"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear3/prog_index.m3u8"]]; [sampleList addObject:@[@"bipbop basic 960x720 @ 2 Mbps", @"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear4/prog_index.m3u8"]]; [sampleList addObject:@[@"bipbop basic 22.050Hz stereo @ 40 kbps", @"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear0/prog_index.m3u8"]]; [sampleList addObject:@[@"bipbop advanced master playlist", @"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"]]; [sampleList addObject:@[@"bipbop advanced 416x234 @ 265 kbps", @"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear1/prog_index.m3u8"]]; [sampleList addObject:@[@"bipbop advanced 640x360 @ 580 kbps", @"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear2/prog_index.m3u8"]]; [sampleList addObject:@[@"bipbop advanced 960x540 @ 910 kbps", @"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear3/prog_index.m3u8"]]; [sampleList addObject:@[@"bipbop advanced 1280x720 @ 1 Mbps", @"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear4/prog_index.m3u8"]]; [sampleList addObject:@[@"bipbop advanced 1920x1080 @ 2 Mbps", @"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear5/prog_index.m3u8"]]; [sampleList addObject:@[@"bipbop advanced 22.050Hz stereo @ 40 kbps", @"http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/gear0/prog_index.m3u8"]]; self.sampleList = sampleList; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.tableView reloadData]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { return @"Samples"; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (IOS_NEWER_OR_EQUAL_TO_7) { return self.sampleList.count; } else { return self.sampleList.count - 1; } } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"abc"]; if (nil == cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"abc"]; cell.textLabel.lineBreakMode = NSLineBreakByTruncatingMiddle; } cell.textLabel.text = self.sampleList[indexPath.row][0]; return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; NSArray *item = self.sampleList[indexPath.row]; NSString *url_str = item[1]; if ([url_str containsString:@"adaptationSet"]) { [self.navigationController presentViewController:[[IJKVideoViewController alloc] initWithManifest:url_str] animated:YES completion:^{}]; } else{ NSURL *url = [NSURL URLWithString:item[1]]; [self.navigationController presentViewController:[[IJKVideoViewController alloc] initWithURL:url] animated:YES completion:^{}]; } } @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKDemoSampleViewController.xib ================================================ ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKMediaControl.h ================================================ /* * Copyright (C) 2013-2015 Bilibili * Copyright (C) 2013-2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import @protocol IJKMediaPlayback; @interface IJKMediaControl : UIControl - (void)showNoFade; - (void)showAndFade; - (void)hide; - (void)refreshMediaControl; - (void)beginDragMediaSlider; - (void)endDragMediaSlider; - (void)continueDragMediaSlider; @property(nonatomic,weak) id delegatePlayer; @property(nonatomic,strong) IBOutlet UIView *overlayPanel; @property(nonatomic,strong) IBOutlet UIView *topPanel; @property(nonatomic,strong) IBOutlet UIView *bottomPanel; @property(nonatomic,strong) IBOutlet UIButton *playButton; @property(nonatomic,strong) IBOutlet UIButton *pauseButton; @property(nonatomic,strong) IBOutlet UILabel *currentTimeLabel; @property(nonatomic,strong) IBOutlet UILabel *totalDurationLabel; @property(nonatomic,strong) IBOutlet UISlider *mediaProgressSlider; @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKMediaControl.m ================================================ /* * Copyright (C) 2013-2015 Bilibili * Copyright (C) 2013-2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import "IJKMediaControl.h" #import @implementation IJKMediaControl { BOOL _isMediaSliderBeingDragged; } - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code } return self; } - (void)awakeFromNib { [self refreshMediaControl]; } - (void)showNoFade { self.overlayPanel.hidden = NO; [self cancelDelayedHide]; [self refreshMediaControl]; } - (void)showAndFade { [self showNoFade]; [self performSelector:@selector(hide) withObject:nil afterDelay:5]; } - (void)hide { self.overlayPanel.hidden = YES; [self cancelDelayedHide]; } - (void)cancelDelayedHide { [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hide) object:nil]; } - (void)beginDragMediaSlider { _isMediaSliderBeingDragged = YES; } - (void)endDragMediaSlider { _isMediaSliderBeingDragged = NO; } - (void)continueDragMediaSlider { [self refreshMediaControl]; } - (void)refreshMediaControl { // duration NSTimeInterval duration = self.delegatePlayer.duration; NSInteger intDuration = duration + 0.5; if (intDuration > 0) { self.mediaProgressSlider.maximumValue = duration; self.totalDurationLabel.text = [NSString stringWithFormat:@"%02d:%02d", (int)(intDuration / 60), (int)(intDuration % 60)]; } else { self.totalDurationLabel.text = @"--:--"; self.mediaProgressSlider.maximumValue = 1.0f; } // position NSTimeInterval position; if (_isMediaSliderBeingDragged) { position = self.mediaProgressSlider.value; } else { position = self.delegatePlayer.currentPlaybackTime; } NSInteger intPosition = position + 0.5; if (intDuration > 0) { self.mediaProgressSlider.value = position; } else { self.mediaProgressSlider.value = 0.0f; } self.currentTimeLabel.text = [NSString stringWithFormat:@"%02d:%02d", (int)(intPosition / 60), (int)(intPosition % 60)]; // status BOOL isPlaying = [self.delegatePlayer isPlaying]; self.playButton.hidden = isPlaying; self.pauseButton.hidden = !isPlaying; [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(refreshMediaControl) object:nil]; if (!self.overlayPanel.hidden) { [self performSelector:@selector(refreshMediaControl) withObject:nil afterDelay:0.5]; } } #pragma mark IBAction @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKMediaDemo-Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleDisplayName ${PRODUCT_NAME} CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIcons CFBundleIcons~ipad CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType APPL CFBundleShortVersionString 0.4.2 CFBundleSignature ???? CFBundleVersion 402 LSRequiresIPhoneOS UIFileSharingEnabled UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKMediaDemo-Prefix.pch ================================================ // // Prefix header for all source files of the 'test' target in the 'test' project // #import #ifndef __IPHONE_3_0 #warning "This project uses features only available in iOS SDK 3.0 and later." #endif #ifdef __OBJC__ #import #import #endif ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKMoviePlayerViewController.h ================================================ /* * Copyright (C) 2013-2015 Bilibili * Copyright (C) 2013-2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import #import @class IJKMediaControl; @interface IJKVideoViewController : UIViewController @property(atomic,strong) NSURL *url; @property(strong,nonatomic) NSString* manifest; @property(atomic, retain) id player; - (id)initWithURL:(NSURL *)url; - (id)initWithManifest:(NSString*)manifest_string; + (void)presentFromViewController:(UIViewController *)viewController withTitle:(NSString *)title URL:(NSURL *)url completion:(void(^)())completion; - (IBAction)onClickMediaControl:(id)sender; - (IBAction)onClickOverlay:(id)sender; - (IBAction)onClickDone:(id)sender; - (IBAction)onClickPlay:(id)sender; - (IBAction)onClickPause:(id)sender; - (IBAction)didSliderTouchDown; - (IBAction)didSliderTouchCancel; - (IBAction)didSliderTouchUpOutside; - (IBAction)didSliderTouchUpInside; - (IBAction)didSliderValueChanged; @property(nonatomic,strong) IBOutlet IJKMediaControl *mediaControl; @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKMoviePlayerViewController.m ================================================ /* * Copyright (C) 2013-2015 Bilibili * Copyright (C) 2013-2015 Zhang Rui * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import "IJKMoviePlayerViewController.h" #import "IJKMediaControl.h" #import "IJKCommon.h" #import "IJKDemoHistory.h" @implementation IJKVideoViewController - (void)dealloc { } + (void)presentFromViewController:(UIViewController *)viewController withTitle:(NSString *)title URL:(NSURL *)url completion:(void (^)())completion { IJKDemoHistoryItem *historyItem = [[IJKDemoHistoryItem alloc] init]; historyItem.title = title; historyItem.url = url; [[IJKDemoHistory instance] add:historyItem]; [viewController presentViewController:[[IJKVideoViewController alloc] initWithURL:url] animated:YES completion:completion]; } - (instancetype)initWithManifest: (NSString*)manifest_string { self = [self initWithNibName:@"IJKMoviePlayerViewController" bundle:nil]; if (self) { self.url = [NSURL URLWithString:@"ijklas:"]; self.manifest = manifest_string; } return self; } - (instancetype)initWithURL:(NSURL *)url { self = [self initWithNibName:@"IJKMoviePlayerViewController" bundle:nil]; if (self) { self.url = url; } return self; } - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization } return self; } #define EXPECTED_IJKPLAYER_VERSION (1 << 16) & 0xFF) | - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view from its nib. // [[UIApplication sharedApplication] setStatusBarHidden:YES]; // [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft animated:NO]; #ifdef DEBUG [IJKFFMoviePlayerController setLogReport:YES]; [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_DEBUG]; #else [IJKFFMoviePlayerController setLogReport:NO]; [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_INFO]; #endif [IJKFFMoviePlayerController checkIfFFmpegVersionMatch:YES]; // [IJKFFMoviePlayerController checkIfPlayerVersionMatch:YES major:1 minor:0 micro:0]; IJKFFOptions *options = [IJKFFOptions optionsByDefault]; if (self.manifest != nil){ [options setPlayerOptionValue:@"ijklas" forKey:@"iformat"]; [options setPlayerOptionIntValue:0 forKey:@"find_stream_info"]; [options setFormatOptionValue:self.manifest forKey:@"manifest_string"]; } self.player = [[IJKFFMoviePlayerController alloc] initWithContentURL:self.url withOptions:options]; self.player.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; self.player.view.frame = self.view.bounds; self.player.scalingMode = IJKMPMovieScalingModeAspectFit; self.player.shouldAutoplay = YES; self.view.autoresizesSubviews = YES; [self.view addSubview:self.player.view]; [self.view addSubview:self.mediaControl]; self.mediaControl.delegatePlayer = self.player; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self installMovieNotificationObservers]; [self.player prepareToPlay]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; [self.player shutdown]; [self removeMovieNotificationObservers]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{ return UIInterfaceOrientationIsLandscape(toInterfaceOrientation); } - (UIInterfaceOrientationMask)supportedInterfaceOrientations { return UIInterfaceOrientationMaskLandscape; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark IBAction - (IBAction)onClickMediaControl:(id)sender { [self.mediaControl showAndFade]; } - (IBAction)onClickOverlay:(id)sender { [self.mediaControl hide]; } - (IBAction)onClickDone:(id)sender { [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; } - (IBAction)onClickHUD:(UIBarButtonItem *)sender { if ([self.player isKindOfClass:[IJKFFMoviePlayerController class]]) { IJKFFMoviePlayerController *player = self.player; player.shouldShowHudView = !player.shouldShowHudView; sender.title = (player.shouldShowHudView ? @"HUD On" : @"HUD Off"); } } - (IBAction)onClickPlay:(id)sender { [self.player play]; [self.mediaControl refreshMediaControl]; } - (IBAction)onClickPause:(id)sender { [self.player pause]; [self.mediaControl refreshMediaControl]; } - (IBAction)didSliderTouchDown { [self.mediaControl beginDragMediaSlider]; } - (IBAction)didSliderTouchCancel { [self.mediaControl endDragMediaSlider]; } - (IBAction)didSliderTouchUpOutside { [self.mediaControl endDragMediaSlider]; } - (IBAction)didSliderTouchUpInside { self.player.currentPlaybackTime = self.mediaControl.mediaProgressSlider.value; [self.mediaControl endDragMediaSlider]; } - (IBAction)didSliderValueChanged { [self.mediaControl continueDragMediaSlider]; } - (void)loadStateDidChange:(NSNotification*)notification { // MPMovieLoadStateUnknown = 0, // MPMovieLoadStatePlayable = 1 << 0, // MPMovieLoadStatePlaythroughOK = 1 << 1, // Playback will be automatically started in this state when shouldAutoplay is YES // MPMovieLoadStateStalled = 1 << 2, // Playback will be automatically paused in this state, if started IJKMPMovieLoadState loadState = _player.loadState; if ((loadState & IJKMPMovieLoadStatePlaythroughOK) != 0) { NSLog(@"loadStateDidChange: IJKMPMovieLoadStatePlaythroughOK: %d\n", (int)loadState); } else if ((loadState & IJKMPMovieLoadStateStalled) != 0) { NSLog(@"loadStateDidChange: IJKMPMovieLoadStateStalled: %d\n", (int)loadState); } else { NSLog(@"loadStateDidChange: ???: %d\n", (int)loadState); } } - (void)moviePlayBackDidFinish:(NSNotification*)notification { // MPMovieFinishReasonPlaybackEnded, // MPMovieFinishReasonPlaybackError, // MPMovieFinishReasonUserExited int reason = [[[notification userInfo] valueForKey:IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue]; switch (reason) { case IJKMPMovieFinishReasonPlaybackEnded: NSLog(@"playbackStateDidChange: IJKMPMovieFinishReasonPlaybackEnded: %d\n", reason); break; case IJKMPMovieFinishReasonUserExited: NSLog(@"playbackStateDidChange: IJKMPMovieFinishReasonUserExited: %d\n", reason); break; case IJKMPMovieFinishReasonPlaybackError: NSLog(@"playbackStateDidChange: IJKMPMovieFinishReasonPlaybackError: %d\n", reason); break; default: NSLog(@"playbackPlayBackDidFinish: ???: %d\n", reason); break; } } - (void)mediaIsPreparedToPlayDidChange:(NSNotification*)notification { NSLog(@"mediaIsPreparedToPlayDidChange\n"); } - (void)moviePlayBackStateDidChange:(NSNotification*)notification { // MPMoviePlaybackStateStopped, // MPMoviePlaybackStatePlaying, // MPMoviePlaybackStatePaused, // MPMoviePlaybackStateInterrupted, // MPMoviePlaybackStateSeekingForward, // MPMoviePlaybackStateSeekingBackward switch (_player.playbackState) { case IJKMPMoviePlaybackStateStopped: { NSLog(@"IJKMPMoviePlayBackStateDidChange %d: stoped", (int)_player.playbackState); break; } case IJKMPMoviePlaybackStatePlaying: { NSLog(@"IJKMPMoviePlayBackStateDidChange %d: playing", (int)_player.playbackState); break; } case IJKMPMoviePlaybackStatePaused: { NSLog(@"IJKMPMoviePlayBackStateDidChange %d: paused", (int)_player.playbackState); break; } case IJKMPMoviePlaybackStateInterrupted: { NSLog(@"IJKMPMoviePlayBackStateDidChange %d: interrupted", (int)_player.playbackState); break; } case IJKMPMoviePlaybackStateSeekingForward: case IJKMPMoviePlaybackStateSeekingBackward: { NSLog(@"IJKMPMoviePlayBackStateDidChange %d: seeking", (int)_player.playbackState); break; } default: { NSLog(@"IJKMPMoviePlayBackStateDidChange %d: unknown", (int)_player.playbackState); break; } } } #pragma mark Install Movie Notifications /* Register observers for the various movie object notifications. */ -(void)installMovieNotificationObservers { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loadStateDidChange:) name:IJKMPMoviePlayerLoadStateDidChangeNotification object:_player]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlayBackDidFinish:) name:IJKMPMoviePlayerPlaybackDidFinishNotification object:_player]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mediaIsPreparedToPlayDidChange:) name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification object:_player]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlayBackStateDidChange:) name:IJKMPMoviePlayerPlaybackStateDidChangeNotification object:_player]; } #pragma mark Remove Movie Notification Handlers /* Remove the movie notification observers from the movie object. */ -(void)removeMovieNotificationObservers { [[NSNotificationCenter defaultCenter]removeObserver:self name:IJKMPMoviePlayerLoadStateDidChangeNotification object:_player]; [[NSNotificationCenter defaultCenter]removeObserver:self name:IJKMPMoviePlayerPlaybackDidFinishNotification object:_player]; [[NSNotificationCenter defaultCenter]removeObserver:self name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification object:_player]; [[NSNotificationCenter defaultCenter]removeObserver:self name:IJKMPMoviePlayerPlaybackStateDidChangeNotification object:_player]; } @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKMoviePlayerViewController.xib ================================================ ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKQRCodeScanViewController.h ================================================ /* * Copyright (C) 2015 Gdier * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import @interface IJKQRCodeScanViewController : UIViewController @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKQRCodeScanViewController.m ================================================ /* * Copyright (C) 2015 Gdier * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import "IJKQRCodeScanViewController.h" #import "IJKMoviePlayerViewController.h" #import "Barcode.h" #import @interface IJKQRCodeScanViewController () @property (weak, nonatomic) IBOutlet UIView *previewView; @property (strong, nonatomic) NSMutableArray * allowedBarcodeTypes; //@property (strong, nonatomic) SettingsViewController * settingsVC; @end @implementation IJKQRCodeScanViewController { AVCaptureSession *_captureSession; AVCaptureDevice *_videoDevice; AVCaptureDeviceInput *_videoInput; AVCaptureVideoPreviewLayer *_previewLayer; BOOL _running; AVCaptureMetadataOutput *_metadataOutput; } - (instancetype)init { self = [super init]; if (self) { self.title = @"Scan QRCode"; } return self; } - (void)viewDidLoad { [super viewDidLoad]; [self setupCaptureSession]; _previewLayer.frame = _previewView.bounds; [_previewView.layer addSublayer:_previewLayer]; // listen for going into the background and stop the session // set default allowed barcode types, remove types via setings menu if you don't want them to be able to be scanned self.allowedBarcodeTypes = [NSMutableArray new]; [self.allowedBarcodeTypes addObject:@"org.iso.QRCode"]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil]; _previewLayer.frame = _previewView.bounds; [self setupCaptureOrientation]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [self startRunning]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [self stopRunning]; [[NSNotificationCenter defaultCenter] removeObserver:self]; } #pragma mark - AV capture methods - (void)setupCaptureSession { if (_captureSession) { return; } _videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; if (!_videoDevice) { return; } _captureSession = [[AVCaptureSession alloc] init]; _videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:_videoDevice error:nil]; if ([_captureSession canAddInput:_videoInput]) { [_captureSession addInput:_videoInput]; } _previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession]; _previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; // capture and process the metadata _metadataOutput = [[AVCaptureMetadataOutput alloc] init]; [_metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; if ([_captureSession canAddOutput:_metadataOutput]) { [_captureSession addOutput:_metadataOutput]; } } - (void)setupCaptureOrientation { if([_previewLayer.connection isVideoOrientationSupported]) { AVCaptureVideoOrientation orientation; switch ([[UIApplication sharedApplication] statusBarOrientation]) { case UIInterfaceOrientationLandscapeLeft: orientation = AVCaptureVideoOrientationLandscapeLeft; break; case UIInterfaceOrientationLandscapeRight: orientation = AVCaptureVideoOrientationLandscapeRight; break; default: orientation = AVCaptureVideoOrientationLandscapeLeft; break; } [_previewLayer.connection setVideoOrientation:orientation]; } } - (void)startRunning { if (_running) return; [_captureSession startRunning]; _metadataOutput.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];//_metadataOutput.availableMetadataObjectTypes; _running = YES; } - (void)stopRunning { if (!_running) return; [_captureSession stopRunning]; _running = NO; } - (void)applicationWillEnterForeground:(NSNotification*)note { [self startRunning]; } - (void)applicationDidEnterBackground:(NSNotification*)note { [self stopRunning]; } #pragma mark - Delegate functions - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection { [metadataObjects enumerateObjectsUsingBlock:^(AVMetadataObject *obj, NSUInteger idx, BOOL *stop) { if ([obj isKindOfClass:[AVMetadataMachineReadableCodeObject class]]) { AVMetadataMachineReadableCodeObject *code = (AVMetadataMachineReadableCodeObject *) [_previewLayer transformedMetadataObjectForMetadataObject:obj]; Barcode * barcode = [Barcode processMetadataObject:code]; for(NSString * str in self.allowedBarcodeTypes) { if([barcode.getBarcodeType isEqualToString:str]) { [self validBarcodeFound:barcode]; return; } } } }]; } - (void) validBarcodeFound:(Barcode *)barcode { [self stopRunning]; [self showBarcodeAlert:barcode]; } - (void) showBarcodeAlert:(Barcode *)barcode { UIAlertView *message = [[UIAlertView alloc] initWithTitle:nil message:[barcode getBarcodeData] delegate:self cancelButtonTitle:@"Scan Again" otherButtonTitles:@"Play", nil]; [message show]; } - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { if(buttonIndex == alertView.cancelButtonIndex) { [self startRunning]; } else { NSURL *url = [NSURL URLWithString:alertView.message]; [IJKVideoViewController presentFromViewController:self withTitle:[NSString stringWithFormat:@"URL: %@", url] URL:url completion:^{ [self.navigationController popViewControllerAnimated:NO]; }]; } } @end ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/IJKQRCodeScanViewController.xib ================================================ ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/Images.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "29x29", "scale" : "1x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "57x57", "scale" : "1x" }, { "idiom" : "iphone", "size" : "57x57", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/Images.xcassets/LaunchImage.launchimage/Contents.json ================================================ { "images" : [ { "orientation" : "portrait", "idiom" : "iphone", "filename" : "Default@2x.png", "minimum-system-version" : "7.0", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "iphone", "filename" : "Default-568h@2x.png", "minimum-system-version" : "7.0", "subtype" : "retina4", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "iphone", "filename" : "Default.png", "scale" : "1x" }, { "orientation" : "portrait", "idiom" : "iphone", "filename" : "Default@2x.png", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "iphone", "filename" : "Default-568h@2x.png", "subtype" : "retina4", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/LaunchScreen.xib ================================================ ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/en.lproj/InfoPlist.strings ================================================ /* Localized versions of Info.plist keys */ ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo/main.m ================================================ // // main.m // IJKMediaDemo // // Created by ZhangRui on 13-9-19. // Copyright (c) 2013年 bilibili. All rights reserved. // #import #import "IJKAppDelegate.h" int main(int argc, char *argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([IJKAppDelegate class])); } } ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 45D57D611A53233200BDD389 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45D57D601A53233200BDD389 /* CoreVideo.framework */; }; 45D57D631A53233800BDD389 /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45D57D621A53233800BDD389 /* VideoToolbox.framework */; }; 546736C41E2371AE00FEE0DF /* libstdc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 546736C31E2371AE00FEE0DF /* libstdc++.tbd */; }; 55E809E21B143C47003E98A5 /* IJKDemoMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 55E809E11B143C47003E98A5 /* IJKDemoMainViewController.m */; }; 55E809E41B143C85003E98A5 /* IJKDemoMainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 55E809E31B143C85003E98A5 /* IJKDemoMainViewController.xib */; }; 55E809E61B145B55003E98A5 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 55E809E51B145B55003E98A5 /* LaunchScreen.xib */; }; 55E809EA1B145BC2003E98A5 /* IJKDemoInputURLViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 55E809E81B145BC2003E98A5 /* IJKDemoInputURLViewController.m */; }; 55E809EB1B145BC2003E98A5 /* IJKDemoInputURLViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 55E809E91B145BC2003E98A5 /* IJKDemoInputURLViewController.xib */; }; 55E809EE1B146C1E003E98A5 /* IJKQRCodeScanViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 55E809ED1B146C1E003E98A5 /* IJKQRCodeScanViewController.m */; }; 55E809F11B146C80003E98A5 /* Barcode.m in Sources */ = {isa = PBXBuildFile; fileRef = 55E809F01B146C80003E98A5 /* Barcode.m */; }; 55E809F31B146DE8003E98A5 /* IJKQRCodeScanViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 55E809F21B146DE8003E98A5 /* IJKQRCodeScanViewController.xib */; }; 55E809F61B1480BC003E98A5 /* IJKDemoHistory.m in Sources */ = {isa = PBXBuildFile; fileRef = 55E809F51B1480BC003E98A5 /* IJKDemoHistory.m */; }; 55E809F91B15A1DB003E98A5 /* IJKDemoLocalFolderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 55E809F81B15A1DB003E98A5 /* IJKDemoLocalFolderViewController.m */; }; E60E8C2A19EF70BB005B5B6E /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E60E8C2919EF70BB005B5B6E /* CoreMedia.framework */; }; E612EAE517F7E0F800BEE660 /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E612EAE417F7E0F800BEE660 /* MediaPlayer.framework */; }; E6166C9C17EDA4A20006B956 /* IJKMediaDemo-Prefix.pch in Resources */ = {isa = PBXBuildFile; fileRef = E6166C9B17EDA4A20006B956 /* IJKMediaDemo-Prefix.pch */; }; E61B45AE19EF7021002792EC /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E61B45AD19EF7021002792EC /* AVFoundation.framework */; }; E63FC29117F04C83003551EB /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E63FC28F17F04C83003551EB /* AudioToolbox.framework */; }; E63FC2B417F172EA003551EB /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E63FC2B317F172E9003551EB /* OpenGLES.framework */; }; E64D4F4E1938CCCC00F1C75D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E64D4F4D1938CCCC00F1C75D /* CoreGraphics.framework */; }; E64D4F4F1938CD2100F1C75D /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E63FC2B717F17362003551EB /* QuartzCore.framework */; }; E654EAF01B6B2A7900B0F2D0 /* IJKMediaFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E654EAD71B6B28B100B0F2D0 /* IJKMediaFramework.framework */; }; E66F8DCB17EEDD8B00354D80 /* IJKMediaControl.m in Sources */ = {isa = PBXBuildFile; fileRef = E66F8DCA17EEDD8B00354D80 /* IJKMediaControl.m */; }; E67323A71B69E6F800CB9036 /* AppIcons.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E67323A51B69E6F800CB9036 /* AppIcons.xcassets */; }; E67323A81B69E6F800CB9036 /* LaunchImages.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E67323A61B69E6F800CB9036 /* LaunchImages.xcassets */; }; E67323AC1B69E76100CB9036 /* MoviePlayerImages.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E67323AB1B69E76100CB9036 /* MoviePlayerImages.xcassets */; }; E67323B11B69ECF500CB9036 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E67323B01B69ECF500CB9036 /* MobileCoreServices.framework */; }; E6903F0017EAF70200CFD954 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E6903EFF17EAF70200CFD954 /* UIKit.framework */; }; E6903F0A17EAF70200CFD954 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = E6903F0817EAF70200CFD954 /* InfoPlist.strings */; }; E6903F0C17EAF70200CFD954 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E6903F0B17EAF70200CFD954 /* main.m */; }; E6903F1017EAF70200CFD954 /* IJKAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E6903F0F17EAF70200CFD954 /* IJKAppDelegate.m */; }; E6903F1217EAF70200CFD954 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = E6903F1117EAF70200CFD954 /* Default.png */; }; E6903F1417EAF70200CFD954 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = E6903F1317EAF70200CFD954 /* Default@2x.png */; }; E6903F1617EAF70200CFD954 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = E6903F1517EAF70200CFD954 /* Default-568h@2x.png */; }; E6A9B56417EDA72C00A1A500 /* IJKMoviePlayerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E6A9B56217EDA72C00A1A500 /* IJKMoviePlayerViewController.m */; }; E6A9B56517EDA72C00A1A500 /* IJKMoviePlayerViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = E6A9B56317EDA72C00A1A500 /* IJKMoviePlayerViewController.xib */; }; E6F1D4BE1D38F29800E8665B /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = E6F1D4BD1D38F29800E8665B /* libz.tbd */; }; E6F1D4C01D38F29D00E8665B /* libbz2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = E6F1D4BF1D38F29D00E8665B /* libbz2.tbd */; }; E6F524EB1B183A0700B69DC7 /* IJKDemoSampleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E6F524E91B183A0700B69DC7 /* IJKDemoSampleViewController.m */; }; E6F524EC1B183A0700B69DC7 /* IJKDemoSampleViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = E6F524EA1B183A0700B69DC7 /* IJKDemoSampleViewController.xib */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ E654EAD61B6B28B100B0F2D0 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = E6D74F2918A5F94B00165BFD /* IJKMediaPlayer.xcodeproj */; proxyType = 2; remoteGlobalIDString = E654EA8A1B6B27E600B0F2D0; remoteInfo = IJKMediaFramework; }; E654EAD81B6B28B100B0F2D0 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = E6D74F2918A5F94B00165BFD /* IJKMediaPlayer.xcodeproj */; proxyType = 2; remoteGlobalIDString = E654EA941B6B27E600B0F2D0; remoteInfo = IJKMediaFrameworkTests; }; E654EAEE1B6B2A1500B0F2D0 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = E6D74F2918A5F94B00165BFD /* IJKMediaPlayer.xcodeproj */; proxyType = 1; remoteGlobalIDString = E654EA891B6B27E600B0F2D0; remoteInfo = IJKMediaFramework; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 45D57D601A53233200BDD389 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; }; 45D57D621A53233800BDD389 /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; }; 546736C31E2371AE00FEE0DF /* libstdc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libstdc++.tbd"; path = "usr/lib/libstdc++.tbd"; sourceTree = SDKROOT; }; 55E809E01B143C47003E98A5 /* IJKDemoMainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKDemoMainViewController.h; sourceTree = ""; }; 55E809E11B143C47003E98A5 /* IJKDemoMainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKDemoMainViewController.m; sourceTree = ""; }; 55E809E31B143C85003E98A5 /* IJKDemoMainViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IJKDemoMainViewController.xib; sourceTree = ""; }; 55E809E51B145B55003E98A5 /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = ""; }; 55E809E71B145BC2003E98A5 /* IJKDemoInputURLViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKDemoInputURLViewController.h; sourceTree = ""; }; 55E809E81B145BC2003E98A5 /* IJKDemoInputURLViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKDemoInputURLViewController.m; sourceTree = ""; }; 55E809E91B145BC2003E98A5 /* IJKDemoInputURLViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IJKDemoInputURLViewController.xib; sourceTree = ""; }; 55E809EC1B146C1E003E98A5 /* IJKQRCodeScanViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKQRCodeScanViewController.h; sourceTree = ""; }; 55E809ED1B146C1E003E98A5 /* IJKQRCodeScanViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKQRCodeScanViewController.m; sourceTree = ""; }; 55E809EF1B146C80003E98A5 /* Barcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Barcode.h; sourceTree = ""; }; 55E809F01B146C80003E98A5 /* Barcode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Barcode.m; sourceTree = ""; }; 55E809F21B146DE8003E98A5 /* IJKQRCodeScanViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IJKQRCodeScanViewController.xib; sourceTree = ""; }; 55E809F41B1480BC003E98A5 /* IJKDemoHistory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKDemoHistory.h; sourceTree = ""; }; 55E809F51B1480BC003E98A5 /* IJKDemoHistory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKDemoHistory.m; sourceTree = ""; }; 55E809F71B15A1DB003E98A5 /* IJKDemoLocalFolderViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKDemoLocalFolderViewController.h; sourceTree = ""; }; 55E809F81B15A1DB003E98A5 /* IJKDemoLocalFolderViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKDemoLocalFolderViewController.m; sourceTree = ""; }; E60E8C2919EF70BB005B5B6E /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; }; E612EAE417F7E0F800BEE660 /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; }; E6166C9B17EDA4A20006B956 /* IJKMediaDemo-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IJKMediaDemo-Prefix.pch"; sourceTree = ""; }; E61B45AD19EF7021002792EC /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; E63FC27817F032FD003551EB /* IJKCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKCommon.h; sourceTree = ""; }; E63FC28F17F04C83003551EB /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; E63FC2B317F172E9003551EB /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; E63FC2B717F17362003551EB /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; E64D4F4D1938CCCC00F1C75D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; E66F8DC917EEDD8B00354D80 /* IJKMediaControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKMediaControl.h; sourceTree = ""; }; E66F8DCA17EEDD8B00354D80 /* IJKMediaControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKMediaControl.m; sourceTree = ""; }; E67323A51B69E6F800CB9036 /* AppIcons.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = AppIcons.xcassets; sourceTree = ""; }; E67323A61B69E6F800CB9036 /* LaunchImages.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = LaunchImages.xcassets; sourceTree = ""; }; E67323AB1B69E76100CB9036 /* MoviePlayerImages.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = MoviePlayerImages.xcassets; sourceTree = ""; }; E67323B01B69ECF500CB9036 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; E6903EFC17EAF70200CFD954 /* IJKMediaDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IJKMediaDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; E6903EFF17EAF70200CFD954 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; E6903F0717EAF70200CFD954 /* IJKMediaDemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "IJKMediaDemo-Info.plist"; sourceTree = ""; }; E6903F0917EAF70200CFD954 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; E6903F0B17EAF70200CFD954 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; E6903F0E17EAF70200CFD954 /* IJKAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJKAppDelegate.h; sourceTree = ""; }; E6903F0F17EAF70200CFD954 /* IJKAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJKAppDelegate.m; sourceTree = ""; }; E6903F1117EAF70200CFD954 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; E6903F1317EAF70200CFD954 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; E6903F1517EAF70200CFD954 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; E6A9B56117EDA72C00A1A500 /* IJKMoviePlayerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKMoviePlayerViewController.h; sourceTree = ""; }; E6A9B56217EDA72C00A1A500 /* IJKMoviePlayerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKMoviePlayerViewController.m; sourceTree = ""; }; E6A9B56317EDA72C00A1A500 /* IJKMoviePlayerViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IJKMoviePlayerViewController.xib; sourceTree = ""; }; E6D74F2918A5F94B00165BFD /* IJKMediaPlayer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = IJKMediaPlayer.xcodeproj; path = ../IJKMediaPlayer/IJKMediaPlayer.xcodeproj; sourceTree = ""; }; E6F1D4BD1D38F29800E8665B /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; E6F1D4BF1D38F29D00E8665B /* libbz2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libbz2.tbd; path = usr/lib/libbz2.tbd; sourceTree = SDKROOT; }; E6F524E81B183A0700B69DC7 /* IJKDemoSampleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKDemoSampleViewController.h; sourceTree = ""; }; E6F524E91B183A0700B69DC7 /* IJKDemoSampleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKDemoSampleViewController.m; sourceTree = ""; }; E6F524EA1B183A0700B69DC7 /* IJKDemoSampleViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IJKDemoSampleViewController.xib; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ E6903EF917EAF70200CFD954 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 546736C41E2371AE00FEE0DF /* libstdc++.tbd in Frameworks */, E63FC29117F04C83003551EB /* AudioToolbox.framework in Frameworks */, E61B45AE19EF7021002792EC /* AVFoundation.framework in Frameworks */, E64D4F4E1938CCCC00F1C75D /* CoreGraphics.framework in Frameworks */, E60E8C2A19EF70BB005B5B6E /* CoreMedia.framework in Frameworks */, 45D57D611A53233200BDD389 /* CoreVideo.framework in Frameworks */, E6F1D4C01D38F29D00E8665B /* libbz2.tbd in Frameworks */, E6F1D4BE1D38F29800E8665B /* libz.tbd in Frameworks */, E654EAF01B6B2A7900B0F2D0 /* IJKMediaFramework.framework in Frameworks */, E612EAE517F7E0F800BEE660 /* MediaPlayer.framework in Frameworks */, E67323B11B69ECF500CB9036 /* MobileCoreServices.framework in Frameworks */, E63FC2B417F172EA003551EB /* OpenGLES.framework in Frameworks */, E64D4F4F1938CD2100F1C75D /* QuartzCore.framework in Frameworks */, E6903F0017EAF70200CFD954 /* UIKit.framework in Frameworks */, 45D57D631A53233800BDD389 /* VideoToolbox.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ E63FC27717F032D9003551EB /* Misc */ = { isa = PBXGroup; children = ( E63FC27817F032FD003551EB /* IJKCommon.h */, 55E809EF1B146C80003E98A5 /* Barcode.h */, 55E809F01B146C80003E98A5 /* Barcode.m */, 55E809F41B1480BC003E98A5 /* IJKDemoHistory.h */, 55E809F51B1480BC003E98A5 /* IJKDemoHistory.m */, ); name = Misc; sourceTree = ""; }; E67323A01B69E6B800CB9036 /* XCAssets */ = { isa = PBXGroup; children = ( E67323A51B69E6F800CB9036 /* AppIcons.xcassets */, E67323A61B69E6F800CB9036 /* LaunchImages.xcassets */, E67323AB1B69E76100CB9036 /* MoviePlayerImages.xcassets */, ); path = XCAssets; sourceTree = ""; }; E6903EF317EAF70200CFD954 = { isa = PBXGroup; children = ( E6D74F2918A5F94B00165BFD /* IJKMediaPlayer.xcodeproj */, E6903EFE17EAF70200CFD954 /* Frameworks */, E6903F0517EAF70200CFD954 /* IJKMediaDemo */, E6903EFD17EAF70200CFD954 /* Products */, E67323A01B69E6B800CB9036 /* XCAssets */, ); sourceTree = ""; }; E6903EFD17EAF70200CFD954 /* Products */ = { isa = PBXGroup; children = ( E6903EFC17EAF70200CFD954 /* IJKMediaDemo.app */, ); name = Products; sourceTree = ""; }; E6903EFE17EAF70200CFD954 /* Frameworks */ = { isa = PBXGroup; children = ( 546736C31E2371AE00FEE0DF /* libstdc++.tbd */, E63FC28F17F04C83003551EB /* AudioToolbox.framework */, E61B45AD19EF7021002792EC /* AVFoundation.framework */, E64D4F4D1938CCCC00F1C75D /* CoreGraphics.framework */, E60E8C2919EF70BB005B5B6E /* CoreMedia.framework */, 45D57D601A53233200BDD389 /* CoreVideo.framework */, E6F1D4BF1D38F29D00E8665B /* libbz2.tbd */, E6F1D4BD1D38F29800E8665B /* libz.tbd */, E612EAE417F7E0F800BEE660 /* MediaPlayer.framework */, E67323B01B69ECF500CB9036 /* MobileCoreServices.framework */, E63FC2B317F172E9003551EB /* OpenGLES.framework */, E63FC2B717F17362003551EB /* QuartzCore.framework */, E6903EFF17EAF70200CFD954 /* UIKit.framework */, 45D57D621A53233800BDD389 /* VideoToolbox.framework */, ); name = Frameworks; sourceTree = ""; }; E6903F0517EAF70200CFD954 /* IJKMediaDemo */ = { isa = PBXGroup; children = ( E6903F0E17EAF70200CFD954 /* IJKAppDelegate.h */, E6903F0F17EAF70200CFD954 /* IJKAppDelegate.m */, E6A9B55C17EDA6AC00A1A500 /* View Controllers */, E63FC27717F032D9003551EB /* Misc */, E6903F0617EAF70200CFD954 /* Supporting Files */, ); path = IJKMediaDemo; sourceTree = ""; }; E6903F0617EAF70200CFD954 /* Supporting Files */ = { isa = PBXGroup; children = ( E6903F0717EAF70200CFD954 /* IJKMediaDemo-Info.plist */, E6903F0817EAF70200CFD954 /* InfoPlist.strings */, E6903F0B17EAF70200CFD954 /* main.m */, E6903F1117EAF70200CFD954 /* Default.png */, E6903F1317EAF70200CFD954 /* Default@2x.png */, E6903F1517EAF70200CFD954 /* Default-568h@2x.png */, E6166C9B17EDA4A20006B956 /* IJKMediaDemo-Prefix.pch */, 55E809E51B145B55003E98A5 /* LaunchScreen.xib */, ); name = "Supporting Files"; sourceTree = ""; }; E6A9B55C17EDA6AC00A1A500 /* View Controllers */ = { isa = PBXGroup; children = ( 55E809E71B145BC2003E98A5 /* IJKDemoInputURLViewController.h */, 55E809E81B145BC2003E98A5 /* IJKDemoInputURLViewController.m */, 55E809E91B145BC2003E98A5 /* IJKDemoInputURLViewController.xib */, 55E809F71B15A1DB003E98A5 /* IJKDemoLocalFolderViewController.h */, 55E809F81B15A1DB003E98A5 /* IJKDemoLocalFolderViewController.m */, 55E809E01B143C47003E98A5 /* IJKDemoMainViewController.h */, 55E809E11B143C47003E98A5 /* IJKDemoMainViewController.m */, 55E809E31B143C85003E98A5 /* IJKDemoMainViewController.xib */, E6F524E81B183A0700B69DC7 /* IJKDemoSampleViewController.h */, E6F524E91B183A0700B69DC7 /* IJKDemoSampleViewController.m */, E6F524EA1B183A0700B69DC7 /* IJKDemoSampleViewController.xib */, E66F8DC917EEDD8B00354D80 /* IJKMediaControl.h */, E66F8DCA17EEDD8B00354D80 /* IJKMediaControl.m */, E6A9B56117EDA72C00A1A500 /* IJKMoviePlayerViewController.h */, E6A9B56217EDA72C00A1A500 /* IJKMoviePlayerViewController.m */, E6A9B56317EDA72C00A1A500 /* IJKMoviePlayerViewController.xib */, 55E809EC1B146C1E003E98A5 /* IJKQRCodeScanViewController.h */, 55E809ED1B146C1E003E98A5 /* IJKQRCodeScanViewController.m */, 55E809F21B146DE8003E98A5 /* IJKQRCodeScanViewController.xib */, ); name = "View Controllers"; sourceTree = ""; }; E6D74F2A18A5F94B00165BFD /* Products */ = { isa = PBXGroup; children = ( E654EAD71B6B28B100B0F2D0 /* IJKMediaFramework.framework */, E654EAD91B6B28B100B0F2D0 /* IJKMediaFrameworkTests.xctest */, ); name = Products; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ E6903EFB17EAF70200CFD954 /* IJKMediaDemo */ = { isa = PBXNativeTarget; buildConfigurationList = E6903F1917EAF70200CFD954 /* Build configuration list for PBXNativeTarget "IJKMediaDemo" */; buildPhases = ( E6903EF817EAF70200CFD954 /* Sources */, E6903EF917EAF70200CFD954 /* Frameworks */, E6903EFA17EAF70200CFD954 /* Resources */, ); buildRules = ( ); dependencies = ( E654EAEF1B6B2A1500B0F2D0 /* PBXTargetDependency */, ); name = IJKMediaDemo; productName = IJKMediaDemo; productReference = E6903EFC17EAF70200CFD954 /* IJKMediaDemo.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ E6903EF417EAF70200CFD954 /* Project object */ = { isa = PBXProject; attributes = { CLASSPREFIX = IJK; LastUpgradeCheck = 0700; ORGANIZATIONNAME = bilibili; }; buildConfigurationList = E6903EF717EAF70200CFD954 /* Build configuration list for PBXProject "IJKMediaDemo" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = E6903EF317EAF70200CFD954; productRefGroup = E6903EFD17EAF70200CFD954 /* Products */; projectDirPath = ""; projectReferences = ( { ProductGroup = E6D74F2A18A5F94B00165BFD /* Products */; ProjectRef = E6D74F2918A5F94B00165BFD /* IJKMediaPlayer.xcodeproj */; }, ); projectRoot = ""; targets = ( E6903EFB17EAF70200CFD954 /* IJKMediaDemo */, ); }; /* End PBXProject section */ /* Begin PBXReferenceProxy section */ E654EAD71B6B28B100B0F2D0 /* IJKMediaFramework.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; path = IJKMediaFramework.framework; remoteRef = E654EAD61B6B28B100B0F2D0 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; E654EAD91B6B28B100B0F2D0 /* IJKMediaFrameworkTests.xctest */ = { isa = PBXReferenceProxy; fileType = wrapper.cfbundle; path = IJKMediaFrameworkTests.xctest; remoteRef = E654EAD81B6B28B100B0F2D0 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */ E6903EFA17EAF70200CFD954 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( E6903F0A17EAF70200CFD954 /* InfoPlist.strings in Resources */, E67323AC1B69E76100CB9036 /* MoviePlayerImages.xcassets in Resources */, E6903F1217EAF70200CFD954 /* Default.png in Resources */, E6903F1417EAF70200CFD954 /* Default@2x.png in Resources */, E6903F1617EAF70200CFD954 /* Default-568h@2x.png in Resources */, E67323A71B69E6F800CB9036 /* AppIcons.xcassets in Resources */, E6166C9C17EDA4A20006B956 /* IJKMediaDemo-Prefix.pch in Resources */, E6A9B56517EDA72C00A1A500 /* IJKMoviePlayerViewController.xib in Resources */, E6F524EC1B183A0700B69DC7 /* IJKDemoSampleViewController.xib in Resources */, 55E809E41B143C85003E98A5 /* IJKDemoMainViewController.xib in Resources */, 55E809F31B146DE8003E98A5 /* IJKQRCodeScanViewController.xib in Resources */, 55E809E61B145B55003E98A5 /* LaunchScreen.xib in Resources */, E67323A81B69E6F800CB9036 /* LaunchImages.xcassets in Resources */, 55E809EB1B145BC2003E98A5 /* IJKDemoInputURLViewController.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ E6903EF817EAF70200CFD954 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 55E809F91B15A1DB003E98A5 /* IJKDemoLocalFolderViewController.m in Sources */, 55E809F61B1480BC003E98A5 /* IJKDemoHistory.m in Sources */, E6903F0C17EAF70200CFD954 /* main.m in Sources */, 55E809E21B143C47003E98A5 /* IJKDemoMainViewController.m in Sources */, E6903F1017EAF70200CFD954 /* IJKAppDelegate.m in Sources */, E6F524EB1B183A0700B69DC7 /* IJKDemoSampleViewController.m in Sources */, E6A9B56417EDA72C00A1A500 /* IJKMoviePlayerViewController.m in Sources */, 55E809F11B146C80003E98A5 /* Barcode.m in Sources */, E66F8DCB17EEDD8B00354D80 /* IJKMediaControl.m in Sources */, 55E809EA1B145BC2003E98A5 /* IJKDemoInputURLViewController.m in Sources */, 55E809EE1B146C1E003E98A5 /* IJKQRCodeScanViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ E654EAEF1B6B2A1500B0F2D0 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = IJKMediaFramework; targetProxy = E654EAEE1B6B2A1500B0F2D0 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ E6903F0817EAF70200CFD954 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( E6903F0917EAF70200CFD954 /* en */, ); name = InfoPlist.strings; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ E6903F1717EAF70200CFD954 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; E6903F1817EAF70200CFD954 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; E6903F1A17EAF70200CFD954 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "IJKMediaDemo/IJKMediaDemo-Prefix.pch"; INFOPLIST_FILE = "IJKMediaDemo/IJKMediaDemo-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LIBRARY_SEARCH_PATHS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "tv.danmaku.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; TARGETED_DEVICE_FAMILY = 1; WRAPPER_EXTENSION = app; }; name = Debug; }; E6903F1B17EAF70200CFD954 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "IJKMediaDemo/IJKMediaDemo-Prefix.pch"; INFOPLIST_FILE = "IJKMediaDemo/IJKMediaDemo-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LIBRARY_SEARCH_PATHS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "tv.danmaku.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; TARGETED_DEVICE_FAMILY = 1; WRAPPER_EXTENSION = app; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ E6903EF717EAF70200CFD954 /* Build configuration list for PBXProject "IJKMediaDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( E6903F1717EAF70200CFD954 /* Debug */, E6903F1817EAF70200CFD954 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; E6903F1917EAF70200CFD954 /* Build configuration list for PBXNativeTarget "IJKMediaDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( E6903F1A17EAF70200CFD954 /* Debug */, E6903F1B17EAF70200CFD954 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = E6903EF417EAF70200CFD954 /* Project object */; } ================================================ FILE: ios/IJKMediaDemo/IJKMediaDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: ios/IJKMediaDemo/XCAssets/AppIcons.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "size" : "29x29", "idiom" : "iphone", "filename" : "icset_iphone_iosu_29pt.png", "scale" : "1x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "icset_iphone_iosu_29pt@2x.png", "scale" : "2x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "icset_iphone_iosu_29pt@3x.png", "scale" : "3x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "icset_iphone_ios7_40pt@2x.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "icset_iphone_ios7_40pt@3x.png", "scale" : "3x" }, { "size" : "57x57", "idiom" : "iphone", "filename" : "icapp_iphone_ios5_57pt.png", "scale" : "1x" }, { "size" : "57x57", "idiom" : "iphone", "filename" : "icapp_iphone_ios5_57pt@2x.png", "scale" : "2x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "icapp_iphone_ios7_60pt@2x.png", "scale" : "2x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "icapp_iphone_ios7_60pt@3x.png", "scale" : "3x" }, { "size" : "29x29", "idiom" : "ipad", "filename" : "icset_ipad_iosu_29pt.png", "scale" : "1x" }, { "size" : "29x29", "idiom" : "ipad", "filename" : "icset_ipad_iosu_29pt@2x.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "ipad", "filename" : "icset_ipad_ios7_40pt.png", "scale" : "1x" }, { "size" : "40x40", "idiom" : "ipad", "filename" : "icset_ipad_ios7_40pt@2x.png", "scale" : "2x" }, { "size" : "50x50", "idiom" : "ipad", "filename" : "icset_ipad_ios5_50pt.png", "scale" : "1x" }, { "size" : "50x50", "idiom" : "ipad", "filename" : "icset_ipad_ios5_50pt@2x.png", "scale" : "2x" }, { "size" : "72x72", "idiom" : "ipad", "filename" : "icapp_ipad_ios5_72pt.png", "scale" : "1x" }, { "size" : "72x72", "idiom" : "ipad", "filename" : "icapp_ipad_ios5_72pt@2x.png", "scale" : "2x" }, { "size" : "76x76", "idiom" : "ipad", "filename" : "icapp_ipad_ios7_76pt.png", "scale" : "1x" }, { "size" : "76x76", "idiom" : "ipad", "filename" : "icapp_ipad_ios7_76pt@2x.png", "scale" : "2x" }, { "idiom" : "ipad", "size" : "83.5x83.5", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: ios/IJKMediaDemo/XCAssets/LaunchImages.xcassets/LaunchImage.launchimage/Contents.json ================================================ { "images" : [ { "orientation" : "portrait", "idiom" : "iphone", "filename" : "iphone_ios7_640_960.png", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "2x" }, { "extent" : "full-screen", "idiom" : "iphone", "subtype" : "retina4", "filename" : "iphone_ios7_640_1136.png", "minimum-system-version" : "7.0", "orientation" : "portrait", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "iphone", "filename" : "iphone_ios5_320_480.png", "extent" : "full-screen", "scale" : "1x" }, { "orientation" : "portrait", "idiom" : "iphone", "filename" : "iphone_ios5_640_960.png", "extent" : "full-screen", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "iphone", "filename" : "iphone_ios5_640_1136.png", "extent" : "full-screen", "subtype" : "retina4", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: ios/IJKMediaDemo/XCAssets/MoviePlayerImages.xcassets/MoviePlayer/btn_player_back_highlighted.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "btn_player_back_highlighted.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "btn_player_back_highlighted@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: ios/IJKMediaDemo/XCAssets/MoviePlayerImages.xcassets/MoviePlayer/btn_player_pause.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "btn_player_pause.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "btn_player_pause@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: ios/IJKMediaDemo/XCAssets/MoviePlayerImages.xcassets/MoviePlayer/btn_player_play.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "btn_player_play.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "btn_player_play@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: ios/IJKMediaDemo/XCAssets/MoviePlayerImages.xcassets/MoviePlayer/player_bottom_control_bg.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "player_bottom_control_bg.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "player_bottom_control_bg@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: ios/IJKMediaDemo/XCAssets/MoviePlayerImages.xcassets/MoviePlayer/player_top_control_bg.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "player_top_control_bg.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "player_top_control_bg@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: ios/IJKMediaPlayer/IJKMediaFramework/IJKMediaFramework.h ================================================ /* * IJKMediaFramework.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import //! Project version number for IJKMediaFramework. FOUNDATION_EXPORT double IJKMediaFrameworkVersionNumber; //! Project version string for IJKMediaFramework. FOUNDATION_EXPORT const unsigned char IJKMediaFrameworkVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import #import #import #import #import #import #import #import #import #import #import // backward compatible for old names #define IJKMediaPlaybackIsPreparedToPlayDidChangeNotification IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification #define IJKMoviePlayerLoadStateDidChangeNotification IJKMPMoviePlayerLoadStateDidChangeNotification #define IJKMoviePlayerPlaybackDidFinishNotification IJKMPMoviePlayerPlaybackDidFinishNotification #define IJKMoviePlayerPlaybackDidFinishReasonUserInfoKey IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey #define IJKMoviePlayerPlaybackStateDidChangeNotification IJKMPMoviePlayerPlaybackStateDidChangeNotification #define IJKMoviePlayerIsAirPlayVideoActiveDidChangeNotification IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification #define IJKMoviePlayerVideoDecoderOpenNotification IJKMPMoviePlayerVideoDecoderOpenNotification #define IJKMoviePlayerFirstVideoFrameRenderedNotification IJKMPMoviePlayerFirstVideoFrameRenderedNotification #define IJKMoviePlayerFirstAudioFrameRenderedNotification IJKMPMoviePlayerFirstAudioFrameRenderedNotification #define IJKMoviePlayerFirstAudioFrameDecodedNotification IJKMPMoviePlayerFirstAudioFrameDecodedNotification #define IJKMoviePlayerFirstVideoFrameDecodedNotification IJKMPMoviePlayerFirstVideoFrameDecodedNotification #define IJKMoviePlayerOpenInputNotification IJKMPMoviePlayerOpenInputNotification #define IJKMoviePlayerFindStreamInfoNotification IJKMPMoviePlayerFindStreamInfoNotification #define IJKMoviePlayerComponentOpenNotification IJKMPMoviePlayerComponentOpenNotification #define IJKMPMoviePlayerAccurateSeekCompleteNotification IJKMPMoviePlayerAccurateSeekCompleteNotification #define IJKMoviePlayerSeekAudioStartNotification IJKMPMoviePlayerSeekAudioStartNotification #define IJKMoviePlayerSeekVideoStartNotification IJKMPMoviePlayerSeekVideoStartNotification ================================================ FILE: ios/IJKMediaPlayer/IJKMediaFramework/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass ================================================ FILE: ios/IJKMediaPlayer/IJKMediaFrameworkTests/IJKMediaFrameworkTests.m ================================================ // // IJKMediaFrameworkTests.m // IJKMediaFrameworkTests // // Created by Zhang Rui on 15/7/31. // Copyright (c) 2015年 bilibili. All rights reserved. // #import #import @interface IJKMediaFrameworkTests : XCTestCase @end @implementation IJKMediaFrameworkTests - (void)setUp { [super setUp]; // Put setup code here. This method is called before the invocation of each test method in the class. } - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the class. [super tearDown]; } - (void)testExample { // This is an example of a functional test case. XCTAssert(YES, @"Pass"); } - (void)testPerformanceExample { // This is an example of a performance test case. [self measureBlock:^{ // Put the code you want to measure the time of here. }]; } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaFrameworkTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: ios/IJKMediaPlayer/IJKMediaFrameworkWithSSL/IJKMediaFrameworkWithSSL.h ================================================ // // IJKMediaFrameworkWithSSL.h // IJKMediaFrameworkWithSSL // // Created by zhangxinzheng on 27/02/2017. // Copyright © 2017 bilibili. All rights reserved. // #import //! Project version number for IJKMediaFrameworkWithSSL. FOUNDATION_EXPORT double IJKMediaFrameworkWithSSLVersionNumber; //! Project version string for IJKMediaFrameworkWithSSL. FOUNDATION_EXPORT const unsigned char IJKMediaFrameworkWithSSLVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import #import #import #import #import #import #import #import #import #import // backward compatible for old names #define IJKMediaPlaybackIsPreparedToPlayDidChangeNotification IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification #define IJKMoviePlayerLoadStateDidChangeNotification IJKMPMoviePlayerLoadStateDidChangeNotification #define IJKMoviePlayerPlaybackDidFinishNotification IJKMPMoviePlayerPlaybackDidFinishNotification #define IJKMoviePlayerPlaybackDidFinishReasonUserInfoKey IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey #define IJKMoviePlayerPlaybackStateDidChangeNotification IJKMPMoviePlayerPlaybackStateDidChangeNotification #define IJKMoviePlayerIsAirPlayVideoActiveDidChangeNotification IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification #define IJKMoviePlayerVideoDecoderOpenNotification IJKMPMoviePlayerVideoDecoderOpenNotification #define IJKMoviePlayerFirstVideoFrameRenderedNotification IJKMPMoviePlayerFirstVideoFrameRenderedNotification #define IJKMoviePlayerFirstAudioFrameRenderedNotification IJKMPMoviePlayerFirstAudioFrameRenderedNotification #define IJKMoviePlayerFirstAudioFrameDecodedNotification IJKMPMoviePlayerFirstAudioFrameDecodedNotification #define IJKMoviePlayerFirstVideoFrameDecodedNotification IJKMPMoviePlayerFirstVideoFrameDecodedNotification #define IJKMoviePlayerOpenInputNotification IJKMPMoviePlayerOpenInputNotification #define IJKMoviePlayerFindStreamInfoNotification IJKMPMoviePlayerFindStreamInfoNotification #define IJKMoviePlayerComponentOpenNotification IJKMPMoviePlayerComponentOpenNotification #define IJKMPMoviePlayerAccurateSeekCompleteNotification IJKMPMoviePlayerAccurateSeekCompleteNotification #define IJKMoviePlayerSeekAudioStartNotification IJKMPMoviePlayerSeekAudioStartNotification #define IJKMoviePlayerSeekVideoStartNotification IJKMPMoviePlayerSeekVideoStartNotification ================================================ FILE: ios/IJKMediaPlayer/IJKMediaFrameworkWithSSL.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKAVMoviePlayerController.h ================================================ /* * IJKAVMoviePlayerController.h * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* File: AVPlayerDemoPlaybackViewController.h Abstract: UIViewController managing a playback view, thumbnail view, and associated playback UI. Version: 1.3 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this Apple software. In consideration of your agreement to abide by the following terms, and subject to these terms, Apple grants you a personal, non-exclusive license, under Apple's copyrights in this original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the Apple Software, with or without modifications, in source and/or binary forms; provided that if you redistribute the Apple Software in its entirety and without modifications, you must retain this notice and the following text and disclaimers in all such redistributions of the Apple Software. Neither the name, trademarks, service marks or logos of Apple Inc. may be used to endorse or promote products derived from the Apple Software without specific prior written permission from Apple. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by Apple herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the Apple Software may be incorporated. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Copyright (C) 2014 Apple Inc. All Rights Reserved. */ #import "IJKMediaPlayback.h" @interface IJKAVMoviePlayerController : NSObject - (id)initWithContentURL:(NSURL *)aUrl; - (id)initWithContentURLString:(NSString *)aUrl; + (id)getInstance:(NSString *)aUrl; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKAVMoviePlayerController.m ================================================ /* * IJKAVMoviePlayerController.m * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* File: AVPlayerDemoPlaybackViewController.m Abstract: UIViewController managing a playback view, thumbnail view, and associated playback UI. Version: 1.3 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this Apple software. In consideration of your agreement to abide by the following terms, and subject to these terms, Apple grants you a personal, non-exclusive license, under Apple's copyrights in this original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the Apple Software, with or without modifications, in source and/or binary forms; provided that if you redistribute the Apple Software in its entirety and without modifications, you must retain this notice and the following text and disclaimers in all such redistributions of the Apple Software. Neither the name, trademarks, service marks or logos of Apple Inc. may be used to endorse or promote products derived from the Apple Software without specific prior written permission from Apple. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by Apple herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the Apple Software may be incorporated. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Copyright (C) 2014 Apple Inc. All Rights Reserved. */ #import "IJKAVMoviePlayerController.h" #import "IJKAVPlayerLayerView.h" #import "IJKAudioKit.h" #import "IJKMediaModule.h" #import "IJKMediaUtils.h" #import "IJKKVOController.h" #import "IJKNotificationManager.h" #include "ijksdl/ios/ijksdl_ios.h" // avoid float equal compare inline static bool isFloatZero(float value) { return fabsf(value) <= 0.00001f; } // resume play after stall static const float kMaxHighWaterMarkMilli = 15 * 1000; static NSString *kErrorDomain = @"IJKAVMoviePlayer"; static const NSInteger kEC_CurrentPlayerItemIsNil = 5001; static const NSInteger kEC_PlayerItemCancelled = 5002; static void *KVO_AVPlayer_rate = &KVO_AVPlayer_rate; static void *KVO_AVPlayer_currentItem = &KVO_AVPlayer_currentItem; static void *KVO_AVPlayer_airplay = &KVO_AVPlayer_airplay; static void *KVO_AVPlayerItem_state = &KVO_AVPlayerItem_state; static void *KVO_AVPlayerItem_loadedTimeRanges = &KVO_AVPlayerItem_loadedTimeRanges; static void *KVO_AVPlayerItem_playbackLikelyToKeepUp = &KVO_AVPlayerItem_playbackLikelyToKeepUp; static void *KVO_AVPlayerItem_playbackBufferFull = &KVO_AVPlayerItem_playbackBufferFull; static void *KVO_AVPlayerItem_playbackBufferEmpty = &KVO_AVPlayerItem_playbackBufferEmpty; @interface IJKAVMoviePlayerController() // Redeclare property @property(nonatomic, readwrite) UIView *view; @property(nonatomic, readwrite) NSTimeInterval duration; @property(nonatomic, readwrite) NSTimeInterval playableDuration; @property(nonatomic, readwrite) NSInteger bufferingProgress; @property(nonatomic, readwrite) BOOL isPreparedToPlay; @end @implementation IJKAVMoviePlayerController { NSURL *_playUrl; AVURLAsset *_playAsset; AVPlayerItem *_playerItem; AVPlayer *_player; IJKAVPlayerLayerView * _avView; IJKKVOController *_playerKVO; IJKKVOController *_playerItemKVO; id _timeObserver; dispatch_once_t _readyToPlayToken; // while AVPlayer is prerolling, it could resume itself. // foring start could BOOL _isPrerolling; NSTimeInterval _seekingTime; BOOL _isSeeking; BOOL _isError; BOOL _isCompleted; BOOL _isShutdown; BOOL _pauseInBackground; BOOL _playbackLikelyToKeeyUp; BOOL _playbackBufferEmpty; BOOL _playbackBufferFull; BOOL _playingBeforeInterruption; IJKNotificationManager *_notificationManager; float _playbackRate; float _playbackVolume; } @synthesize view = _view; @synthesize currentPlaybackTime = _currentPlaybackTime; @synthesize duration = _duration; @synthesize playableDuration = _playableDuration; @synthesize bufferingProgress = _bufferingProgress; @synthesize numberOfBytesTransferred = _numberOfBytesTransferred; @synthesize playbackState = _playbackState; @synthesize loadState = _loadState; @synthesize scalingMode = _scalingMode; @synthesize shouldAutoplay = _shouldAutoplay; @synthesize isDanmakuMediaAirPlay = _isDanmakuMediaAirPlay; static IJKAVMoviePlayerController* instance; - (id)initWithContentURL:(NSURL *)aUrl { self = [super init]; if (self != nil) { self.scalingMode = IJKMPMovieScalingModeAspectFit; self.shouldAutoplay = NO; _playUrl = aUrl; _avView = [[IJKAVPlayerLayerView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.view = _avView; // TODO: [[IJKAudioKit sharedInstance] setupAudioSession]; _isPrerolling = NO; _isSeeking = NO; _isError = NO; _isCompleted = NO; self.bufferingProgress = 0; _playbackLikelyToKeeyUp = NO; _playbackBufferEmpty = YES; _playbackBufferFull = NO; _playbackRate = 1.0f; _playbackVolume = 1.0f; // init extra [self setScreenOn:YES]; _notificationManager = [[IJKNotificationManager alloc] init]; } return self; } + (id)getInstance:(NSString *)aUrl { if (instance == nil) { instance = [[IJKAVMoviePlayerController alloc] initWithContentURLString:aUrl]; } else { instance = [instance initWithContentURLString:aUrl]; } return instance; } - (id)initWithContentURLString:(NSString *)aUrl { NSURL *url; if (aUrl == nil) { aUrl = @""; } if ([aUrl rangeOfString:@"/"].location == 0) { //本地 url = [NSURL fileURLWithPath:aUrl]; } else { url = [NSURL URLWithString:aUrl]; } self = [self initWithContentURL:url]; if (self != nil) { } return self; } - (void)setScreenOn: (BOOL)on { [IJKMediaModule sharedModule].mediaModuleIdleTimerDisabled = on; } - (void)dealloc { [self shutdown]; } - (void)prepareToPlay { AVURLAsset *asset = [AVURLAsset URLAssetWithURL:_playUrl options:nil]; NSArray *requestedKeys = @[@"playable"]; _playAsset = asset; [asset loadValuesAsynchronouslyForKeys:requestedKeys completionHandler:^{ dispatch_async( dispatch_get_main_queue(), ^{ [self didPrepareToPlayAsset:asset withKeys:requestedKeys]; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMovieNaturalSizeAvailableNotification object:self]; [self setPlaybackVolume:_playbackVolume]; }); }]; } - (void)play { if (_isCompleted) { _isCompleted = NO; [_player seekToTime:kCMTimeZero]; } [_player play]; } - (void)pause { _isPrerolling = NO; [_player pause]; } - (void)stop { [_player pause]; [self setScreenOn:NO]; _isCompleted = YES; } - (BOOL)isPlaying { if (!isFloatZero(_player.rate)) { return YES; } else { if (_isPrerolling) { return YES; } else { return NO; } } } - (void)shutdown { _isShutdown = YES; [self stop]; if (_playerItem != nil) { [_playerItem cancelPendingSeeks]; } [_playerItemKVO safelyRemoveAllObservers]; [[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:_playerItem]; [_playerKVO safelyRemoveAllObservers]; [self unregisterApplicationObservers]; if (_avView != nil) { [_avView setPlayer:nil]; } self.view = nil; } - (UIImage *)thumbnailImageAtCurrentTime { AVAssetImageGenerator *imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:_playAsset]; CMTime expectedTime = _playerItem.currentTime; CGImageRef cgImage = NULL; imageGenerator.requestedTimeToleranceBefore = kCMTimeZero; imageGenerator.requestedTimeToleranceAfter = kCMTimeZero; cgImage = [imageGenerator copyCGImageAtTime:expectedTime actualTime:NULL error:NULL]; if (!cgImage) { imageGenerator.requestedTimeToleranceBefore = kCMTimePositiveInfinity; imageGenerator.requestedTimeToleranceAfter = kCMTimePositiveInfinity; cgImage = [imageGenerator copyCGImageAtTime:expectedTime actualTime:NULL error:NULL]; } UIImage *image = [UIImage imageWithCGImage:cgImage]; return image; } - (void)setCurrentPlaybackTime:(NSTimeInterval)aCurrentPlaybackTime { if (!_player) return; _seekingTime = aCurrentPlaybackTime; _isSeeking = YES; _bufferingProgress = 0; [self didPlaybackStateChange]; [self didLoadStateChange]; if (_isPrerolling) { [_player pause]; } [_player seekToTime:CMTimeMakeWithSeconds(aCurrentPlaybackTime, NSEC_PER_SEC) completionHandler:^(BOOL finished) { dispatch_async(dispatch_get_main_queue(), ^{ _isSeeking = NO; if (_isPrerolling) { [_player play]; } [self didPlaybackStateChange]; [self didLoadStateChange]; }); }]; } - (NSTimeInterval)currentPlaybackTime { if (!_player) return 0.0f; if (_isSeeking) return _seekingTime; return CMTimeGetSeconds([_player currentTime]); } -(int64_t)numberOfBytesTransferred { #if 0 if (_player == nil) return 0; AVPlayerItem *playerItem = [_player currentItem]; if (playerItem == nil) return 0; NSArray *events = playerItem.accessLog.events; if (events != nil && events.count > 0) { MPMovieAccessLogEvent *currentEvent = [events objectAtIndex:events.count -1]; return currentEvent.numberOfBytesTransferred; } #endif return 0; } - (IJKMPMoviePlaybackState)playbackState { if (!_player) return IJKMPMoviePlaybackStateStopped; IJKMPMoviePlaybackState mpState = IJKMPMoviePlaybackStateStopped; if (_isCompleted) { mpState = IJKMPMoviePlaybackStateStopped; } else if (_isSeeking) { mpState = IJKMPMoviePlaybackStateSeekingForward; } else if ([self isPlaying]) { mpState = IJKMPMoviePlaybackStatePlaying; } else { mpState = IJKMPMoviePlaybackStatePaused; } return mpState; } - (IJKMPMovieLoadState)loadState { if (_player == nil) return IJKMPMovieLoadStateUnknown; if (_isSeeking) return IJKMPMovieLoadStateStalled; AVPlayerItem *playerItem = [_player currentItem]; if (playerItem == nil) return IJKMPMovieLoadStateUnknown; if (_player != nil && !isFloatZero(_player.rate)) { // NSLog(@"loadState: playing"); return IJKMPMovieLoadStatePlayable | IJKMPMovieLoadStatePlaythroughOK; } else if ([playerItem isPlaybackBufferFull]) { // NSLog(@"loadState: isPlaybackBufferFull"); return IJKMPMovieLoadStatePlayable | IJKMPMovieLoadStatePlaythroughOK; } else if ([playerItem isPlaybackLikelyToKeepUp]) { // NSLog(@"loadState: isPlaybackLikelyToKeepUp"); return IJKMPMovieLoadStatePlayable | IJKMPMovieLoadStatePlaythroughOK; } else if ([playerItem isPlaybackBufferEmpty]) { // NSLog(@"loadState: isPlaybackBufferEmpty"); return IJKMPMovieLoadStateStalled; } else { NSLog(@"loadState: unknown"); return IJKMPMovieLoadStateUnknown; } } -(void)setPlaybackRate:(float)playbackRate { _playbackRate = playbackRate; if (_player != nil && !isFloatZero(_player.rate)) { _player.rate = _playbackRate; } } -(float)playbackRate { return _playbackRate; } -(void)setPlaybackVolume:(float)playbackVolume { _playbackVolume = playbackVolume; if (_player != nil && _player.volume != playbackVolume) { _player.volume = playbackVolume; } BOOL muted = fabs(playbackVolume) < 1e-6; if (_player != nil && _player.muted != muted) { _player.muted = muted; } } -(float)playbackVolume { return _playbackVolume; } - (void)didPrepareToPlayAsset:(AVURLAsset *)asset withKeys:(NSArray *)requestedKeys { if (_isShutdown) return; /* Make sure that the value of each key has loaded successfully. */ for (NSString *thisKey in requestedKeys) { NSError *error = nil; AVKeyValueStatus keyStatus = [asset statusOfValueForKey:thisKey error:&error]; if (keyStatus == AVKeyValueStatusFailed) { [self assetFailedToPrepareForPlayback:error]; return; } else if (keyStatus == AVKeyValueStatusCancelled) { // TODO [AVAsset cancelLoading] error = [self createErrorWithCode:kEC_PlayerItemCancelled description:@"player item cancelled" reason:nil]; [self assetFailedToPrepareForPlayback:error]; return; } } /* Use the AVAsset playable property to detect whether the asset can be played. */ if (!asset.playable) { NSError *assetCannotBePlayedError = [NSError errorWithDomain:@"AVMoviePlayer" code:0 userInfo:nil]; [self assetFailedToPrepareForPlayback:assetCannotBePlayedError]; return; } /* At this point we're ready to set up for playback of the asset. */ /* Stop observing our prior AVPlayerItem, if we have one. */ [_playerItemKVO safelyRemoveAllObservers]; [[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:_playerItem]; /* Create a new instance of AVPlayerItem from the now successfully loaded AVAsset. */ _playerItem = [AVPlayerItem playerItemWithAsset:asset]; _playerItemKVO = [[IJKKVOController alloc] initWithTarget:_playerItem]; [self registerApplicationObservers]; /* Observe the player item "status" key to determine when it is ready to play. */ [_playerItemKVO safelyAddObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:KVO_AVPlayerItem_state]; [_playerItemKVO safelyAddObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:KVO_AVPlayerItem_loadedTimeRanges]; [_playerItemKVO safelyAddObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:KVO_AVPlayerItem_playbackLikelyToKeepUp]; [_playerItemKVO safelyAddObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:KVO_AVPlayerItem_playbackBufferEmpty]; [_playerItemKVO safelyAddObserver:self forKeyPath:@"playbackBufferFull" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:KVO_AVPlayerItem_playbackBufferFull]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:_playerItem]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemFailedToPlayToEndTime:) name:AVPlayerItemFailedToPlayToEndTimeNotification object:_playerItem]; _isCompleted = NO; /* Create new player, if we don't already have one. */ if (!_player) { /* Get a new AVPlayer initialized to play the specified player item. */ _player = [AVPlayer playerWithPlayerItem:_playerItem]; _playerKVO = [[IJKKVOController alloc] initWithTarget:_player]; /* Observe the AVPlayer "currentItem" property to find out when any AVPlayer replaceCurrentItemWithPlayerItem: replacement will/did occur.*/ [_playerKVO safelyAddObserver:self forKeyPath:@"currentItem" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:KVO_AVPlayer_currentItem]; /* Observe the AVPlayer "rate" property to update the scrubber control. */ [_playerKVO safelyAddObserver:self forKeyPath:@"rate" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:KVO_AVPlayer_rate]; [_playerKVO safelyAddObserver:self forKeyPath:@"airPlayVideoActive" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:KVO_AVPlayer_airplay]; } /* Make our new AVPlayerItem the AVPlayer's current item. */ if (_player.currentItem != _playerItem) { /* Replace the player item with a new player item. The item replacement occurs asynchronously; observe the currentItem property to find out when the replacement will/did occur If needed, configure player item here (example: adding outputs, setting text style rules, selecting media options) before associating it with a player */ [_player replaceCurrentItemWithPlayerItem:_playerItem]; // TODO: notify state change } // TODO: set time to 0; } - (void)didPlaybackStateChange { if (_playbackState != self.playbackState) { _playbackState = self.playbackState; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification object:self]; } } - (void)fetchLoadStateFromItem:(AVPlayerItem*)playerItem { if (playerItem == nil) return; _playbackLikelyToKeeyUp = playerItem.isPlaybackLikelyToKeepUp; _playbackBufferEmpty = playerItem.isPlaybackBufferEmpty; _playbackBufferFull = playerItem.isPlaybackBufferFull; } - (void)didLoadStateChange { // NOTE: do not force play after stall, // which may cause AVPlayer get into wrong state // // Rely on AVPlayer's auto resume. [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerLoadStateDidChangeNotification object:self]; } - (void)didPlayableDurationUpdate { NSTimeInterval currentPlaybackTime = self.currentPlaybackTime; int playableDurationMilli = (int)(self.playableDuration * 1000); int currentPlaybackTimeMilli = (int)(currentPlaybackTime * 1000); int bufferedDurationMilli = playableDurationMilli - currentPlaybackTimeMilli; if (bufferedDurationMilli > 0) { self.bufferingProgress = bufferedDurationMilli * 100 / kMaxHighWaterMarkMilli; if (self.bufferingProgress > 100) { dispatch_async(dispatch_get_main_queue(), ^{ if (self.bufferingProgress > 100) { if ([self isPlaying]) { _player.rate = _playbackRate; } } }); } } NSLog(@"KVO_AVPlayerItem_loadedTimeRanges: %d / %d\n", bufferedDurationMilli, (int)kMaxHighWaterMarkMilli); } - (void)onError:(NSError *)error { _isError = YES; __block NSError *blockError = error; NSLog(@"AVPlayer: onError\n"); dispatch_async(dispatch_get_main_queue(), ^{ [self didPlaybackStateChange]; [self didLoadStateChange]; [self setScreenOn:NO]; if (blockError == nil) { blockError = [[NSError alloc] init]; } [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerPlaybackDidFinishNotification object:self userInfo:@{ IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey: @(IJKMPMovieFinishReasonPlaybackError), @"error": blockError }]; }); } - (void)assetFailedToPrepareForPlayback:(NSError *)error { if (_isShutdown) return; [self onError:error]; } - (void)playerItemFailedToPlayToEndTime:(NSNotification *)notification { if (_isShutdown) return; [self onError:[notification.userInfo objectForKey:@"error"]]; } - (void)playerItemDidReachEnd:(NSNotification *)notification { if (_isShutdown) return; _isCompleted = YES; dispatch_async(dispatch_get_main_queue(), ^{ [self didPlaybackStateChange]; [self didLoadStateChange]; [self setScreenOn:NO]; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerPlaybackDidFinishNotification object:self userInfo:@{ IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey: @(IJKMPMovieFinishReasonPlaybackEnded) }]; }); } #pragma mark KVO - (void)observeValueForKeyPath:(NSString*)path ofObject:(id)object change:(NSDictionary*)change context:(void*)context { if (_isShutdown) return; if (context == KVO_AVPlayerItem_state) { /* AVPlayerItem "status" property value observer. */ AVPlayerItemStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue]; switch (status) { case AVPlayerItemStatusUnknown: { /* Indicates that the status of the player is not yet known because it has not tried to load new media resources for playback */ } break; case AVPlayerItemStatusReadyToPlay: { /* Once the AVPlayerItem becomes ready to play, i.e. [playerItem status] == AVPlayerItemStatusReadyToPlay, its duration can be fetched from the item. */ dispatch_once(&_readyToPlayToken, ^{ [_avView setPlayer:_player]; self.isPreparedToPlay = YES; AVPlayerItem *playerItem = (AVPlayerItem *)object; NSTimeInterval duration = CMTimeGetSeconds(playerItem.duration); if (duration <= 0) self.duration = 0.0f; else self.duration = duration; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification object:self]; if (_shouldAutoplay && (!_pauseInBackground || [UIApplication sharedApplication].applicationState == UIApplicationStateActive)) [_player play]; }); } break; case AVPlayerItemStatusFailed: { AVPlayerItem *playerItem = (AVPlayerItem *)object; [self assetFailedToPrepareForPlayback:playerItem.error]; } break; } [self didPlaybackStateChange]; [self didLoadStateChange]; } else if (context == KVO_AVPlayerItem_loadedTimeRanges) { AVPlayerItem *playerItem = (AVPlayerItem *)object; if (_player != nil && playerItem.status == AVPlayerItemStatusReadyToPlay) { NSArray *timeRangeArray = playerItem.loadedTimeRanges; CMTime currentTime = [_player currentTime]; BOOL foundRange = NO; CMTimeRange aTimeRange = {0}; if (timeRangeArray.count) { aTimeRange = [[timeRangeArray objectAtIndex:0] CMTimeRangeValue]; if(CMTimeRangeContainsTime(aTimeRange, currentTime)) { foundRange = YES; } } if (foundRange) { CMTime maxTime = CMTimeRangeGetEnd(aTimeRange); NSTimeInterval playableDuration = CMTimeGetSeconds(maxTime); if (playableDuration > 0) { self.playableDuration = playableDuration; [self didPlayableDurationUpdate]; } } } else { self.playableDuration = 0; } } else if (context == KVO_AVPlayerItem_playbackLikelyToKeepUp) { AVPlayerItem *playerItem = (AVPlayerItem *)object; NSLog(@"KVO_AVPlayerItem_playbackLikelyToKeepUp: %@\n", playerItem.isPlaybackLikelyToKeepUp ? @"YES" : @"NO"); [self fetchLoadStateFromItem:playerItem]; [self didLoadStateChange]; } else if (context == KVO_AVPlayerItem_playbackBufferEmpty) { AVPlayerItem *playerItem = (AVPlayerItem *)object; BOOL isPlaybackBufferEmpty = playerItem.isPlaybackBufferEmpty; NSLog(@"KVO_AVPlayerItem_playbackBufferEmpty: %@\n", isPlaybackBufferEmpty ? @"YES" : @"NO"); if (isPlaybackBufferEmpty) _isPrerolling = YES; [self fetchLoadStateFromItem:playerItem]; [self didLoadStateChange]; } else if (context == KVO_AVPlayerItem_playbackBufferFull) { AVPlayerItem *playerItem = (AVPlayerItem *)object; NSLog(@"KVO_AVPlayerItem_playbackBufferFull: %@\n", playerItem.isPlaybackBufferFull ? @"YES" : @"NO"); [self fetchLoadStateFromItem:playerItem]; [self didLoadStateChange]; } else if (context == KVO_AVPlayer_rate) { if (_player != nil && !isFloatZero(_player.rate)) _isPrerolling = NO; /* AVPlayer "rate" property value observer. */ [self didPlaybackStateChange]; [self didLoadStateChange]; } else if (context == KVO_AVPlayer_currentItem) { _isPrerolling = NO; /* AVPlayer "currentItem" property observer. Called when the AVPlayer replaceCurrentItemWithPlayerItem: replacement will/did occur. */ AVPlayerItem *newPlayerItem = [change objectForKey:NSKeyValueChangeNewKey]; /* Is the new player item null? */ if (newPlayerItem == (id)[NSNull null]) { NSError *error = [self createErrorWithCode:kEC_CurrentPlayerItemIsNil description:@"current player item is nil" reason:nil]; [self assetFailedToPrepareForPlayback:error]; } else /* Replacement of player currentItem has occurred */ { [_avView setPlayer:_player]; [self didPlaybackStateChange]; [self didLoadStateChange]; } } else if (context == KVO_AVPlayer_airplay) { [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification object:nil userInfo:nil]; } else { [super observeValueForKeyPath:path ofObject:object change:change context:context]; } } - (NSError*)createErrorWithCode: (NSInteger)code description: (NSString*)description reason: (NSString*)reason { NSError *error = [IJKMediaUtils createErrorWithDomain:kErrorDomain code:code description:description reason:reason]; return error; } #pragma mark app state changed - (void)registerApplicationObservers { [_notificationManager addObserver:self selector:@selector(audioSessionInterrupt:) name:AVAudioSessionInterruptionNotification object:nil]; [_notificationManager addObserver:self selector:@selector(applicationWillEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil]; [_notificationManager addObserver:self selector:@selector(applicationDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil]; [_notificationManager addObserver:self selector:@selector(applicationWillResignActive) name:UIApplicationWillResignActiveNotification object:nil]; [_notificationManager addObserver:self selector:@selector(applicationDidEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil]; [_notificationManager addObserver:self selector:@selector(applicationWillTerminate) name:UIApplicationWillTerminateNotification object:nil]; } - (void)unregisterApplicationObservers { [_notificationManager removeAllObservers:self]; } -(BOOL)allowsMediaAirPlay { if (!_player) return NO; return _player.allowsExternalPlayback; } -(void)setAllowsMediaAirPlay:(BOOL)b { if (!_player) return; _player.allowsExternalPlayback = b; } -(BOOL)airPlayMediaActive { if (!_player) return NO; return _player.externalPlaybackActive || self.isDanmakuMediaAirPlay; } - (CGSize)naturalSize { if (_playAsset == nil) return CGSizeZero; NSArray *videoTracks = [_playAsset tracksWithMediaType:AVMediaTypeVideo]; if (videoTracks == nil || videoTracks.count <= 0) return CGSizeZero; return [videoTracks objectAtIndex:0].naturalSize; } - (void)setScalingMode: (IJKMPMovieScalingMode) aScalingMode { IJKMPMovieScalingMode newScalingMode = aScalingMode; switch (aScalingMode) { case IJKMPMovieScalingModeNone: [_view setContentMode:UIViewContentModeCenter]; break; case IJKMPMovieScalingModeAspectFit: [_view setContentMode:UIViewContentModeScaleAspectFit]; break; case IJKMPMovieScalingModeAspectFill: [_view setContentMode:UIViewContentModeScaleAspectFill]; break; case IJKMPMovieScalingModeFill: [_view setContentMode:UIViewContentModeScaleToFill]; break; default: newScalingMode = _scalingMode; } _scalingMode = newScalingMode; } - (void)setPauseInBackground:(BOOL)pause { _pauseInBackground = pause; } -(BOOL)isDanmakuMediaAirPlay { return _isDanmakuMediaAirPlay; } -(void)setIsDanmakuMediaAirPlay:(BOOL)isDanmakuMediaAirPlay { _isDanmakuMediaAirPlay = isDanmakuMediaAirPlay; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification object:nil userInfo:nil]; } - (void)audioSessionInterrupt:(NSNotification *)notification { int reason = [[[notification userInfo] valueForKey:AVAudioSessionInterruptionTypeKey] intValue]; switch (reason) { case AVAudioSessionInterruptionTypeBegan: { NSLog(@"IJKAVMoviePlayerController:audioSessionInterrupt: begin\n"); switch (self.playbackState) { case IJKMPMoviePlaybackStatePaused: case IJKMPMoviePlaybackStateStopped: _playingBeforeInterruption = NO; break; default: _playingBeforeInterruption = YES; break; } [self pause]; [[IJKAudioKit sharedInstance] setActive:NO]; break; } case AVAudioSessionInterruptionTypeEnded: { NSLog(@"IJKAVMoviePlayerController:audioSessionInterrupt: end\n"); [[IJKAudioKit sharedInstance] setActive:YES]; if (_playingBeforeInterruption) { [self play]; } break; } } } - (void)applicationWillEnterForeground { NSLog(@"IJKAVMoviePlayerController:applicationWillEnterForeground: %d\n", (int)[UIApplication sharedApplication].applicationState); } - (void)applicationDidBecomeActive { NSLog(@"IJKAVMoviePlayerController:applicationDidBecomeActive: %d\n", (int)[UIApplication sharedApplication].applicationState); [_avView setPlayer:_player]; } - (void)applicationWillResignActive { NSLog(@"IJKAVMoviePlayerController:applicationWillResignActive: %d\n", (int)[UIApplication sharedApplication].applicationState); } - (void)applicationDidEnterBackground { NSLog(@"IJKAVMoviePlayerController:applicationDidEnterBackground: %d\n", (int)[UIApplication sharedApplication].applicationState); if (_pauseInBackground && ![self airPlayMediaActive]) { [self pause]; } else { if (![self airPlayMediaActive]) { [_avView setPlayer:nil]; if (isIOS9OrLater()) { if ([self isPlaying]) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self play]; }); } } } } } - (void)applicationWillTerminate { NSLog(@"IJKAVMoviePlayerController:applicationWillTerminate: %d\n", (int)[UIApplication sharedApplication].applicationState); } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKAVPlayerLayerView.h ================================================ /* * IJKAVPlayerLayerView.h * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* File: AVPlayerDemoPlaybackView.h Abstract: UIView subclass to display the content associated with an AVPlayer Version: 1.3 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this Apple software. In consideration of your agreement to abide by the following terms, and subject to these terms, Apple grants you a personal, non-exclusive license, under Apple's copyrights in this original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the Apple Software, with or without modifications, in source and/or binary forms; provided that if you redistribute the Apple Software in its entirety and without modifications, you must retain this notice and the following text and disclaimers in all such redistributions of the Apple Software. Neither the name, trademarks, service marks or logos of Apple Inc. may be used to endorse or promote products derived from the Apple Software without specific prior written permission from Apple. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by Apple herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the Apple Software may be incorporated. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Copyright (C) 2014 Apple Inc. All Rights Reserved. */ #import @class AVPlayer; @interface IJKAVPlayerLayerView: UIView @property (nonatomic, strong) AVPlayer* player; - (void)setPlayer:(AVPlayer*)player; - (void)setVideoFillMode:(NSString *)fillMode; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKAVPlayerLayerView.m ================================================ /* * IJKAVPlayerLayerView.m * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* File: AVPlayerDemoPlaybackView.m Abstract: UIView subclass to display the content associated with an AVPlayer Version: 1.3 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this Apple software. In consideration of your agreement to abide by the following terms, and subject to these terms, Apple grants you a personal, non-exclusive license, under Apple's copyrights in this original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the Apple Software, with or without modifications, in source and/or binary forms; provided that if you redistribute the Apple Software in its entirety and without modifications, you must retain this notice and the following text and disclaimers in all such redistributions of the Apple Software. Neither the name, trademarks, service marks or logos of Apple Inc. may be used to endorse or promote products derived from the Apple Software without specific prior written permission from Apple. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by Apple herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the Apple Software may be incorporated. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Copyright (C) 2014 Apple Inc. All Rights Reserved. */ #import "IJKAVPlayerLayerView.h" #import @implementation IJKAVPlayerLayerView { NSString* _videoFillMode; } - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { _videoFillMode = @"AVLayerVideoGravityResizeAspect"; // Initialization code } return self; } + (Class)layerClass { return [AVPlayerLayer class]; } - (AVPlayer*)player { return [(AVPlayerLayer*)[self layer] player]; } - (void)setPlayer:(AVPlayer*)player { [(AVPlayerLayer*)[self layer] setPlayer:player]; [self setVideoFillMode:_videoFillMode]; } /* Specifies how the video is displayed within a player layer’s bounds. (AVLayerVideoGravityResizeAspect is default) */ - (void)setVideoFillMode:(NSString *)fillMode { _videoFillMode = fillMode; AVPlayerLayer *playerLayer = (AVPlayerLayer*)[self layer]; playerLayer.videoGravity = fillMode; } - (void)setContentMode:(UIViewContentMode)contentMode { [super setContentMode:contentMode]; switch (contentMode) { case UIViewContentModeScaleToFill: [self setVideoFillMode:AVLayerVideoGravityResize]; break; case UIViewContentModeCenter: [self setVideoFillMode:AVLayerVideoGravityResizeAspect]; break; case UIViewContentModeScaleAspectFill: [self setVideoFillMode:AVLayerVideoGravityResizeAspectFill]; break; case UIViewContentModeScaleAspectFit: [self setVideoFillMode:AVLayerVideoGravityResizeAspect]; default: break; } } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKAudioKit.h ================================================ /* * IJKAudioKit.h * * Copyright (c) 2013-2014 Bilibili * Copyright (c) 2013-2014 Zhang Rui * * based on https://github.com/kolyvan/kxmovie * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import #import @interface IJKAudioKit : NSObject + (IJKAudioKit *)sharedInstance; - (void)setupAudioSession; - (BOOL)setActive:(BOOL)active; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKAudioKit.m ================================================ /* * IJKAudioKit.m * * Copyright (c) 2013-2014 Bilibili * Copyright (c) 2013-2014 Zhang Rui * * based on https://github.com/kolyvan/kxmovie * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKAudioKit.h" @implementation IJKAudioKit { BOOL _audioSessionInitialized; } + (IJKAudioKit *)sharedInstance { static IJKAudioKit *sAudioKit = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sAudioKit = [[IJKAudioKit alloc] init]; }); return sAudioKit; } - (void)setupAudioSession { if (!_audioSessionInitialized) { [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleInterruption:) name: AVAudioSessionInterruptionNotification object: [AVAudioSession sharedInstance]]; _audioSessionInitialized = YES; } /* Set audio session to mediaplayback */ NSError *error = nil; if (NO == [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error]) { NSLog(@"IJKAudioKit: AVAudioSession.setCategory() failed: %@\n", error ? [error localizedDescription] : @"nil"); return; } error = nil; if (NO == [[AVAudioSession sharedInstance] setActive:YES error:&error]) { NSLog(@"IJKAudioKit: AVAudioSession.setActive(YES) failed: %@\n", error ? [error localizedDescription] : @"nil"); return; } return ; } - (BOOL)setActive:(BOOL)active { if (active != NO) { [[AVAudioSession sharedInstance] setActive:YES error:nil]; } else { @try { [[AVAudioSession sharedInstance] setActive:NO error:nil]; } @catch (NSException *exception) { NSLog(@"failed to inactive AVAudioSession\n"); } } } - (void)handleInterruption:(NSNotification *)notification { int reason = [[[notification userInfo] valueForKey:AVAudioSessionInterruptionTypeKey] intValue]; switch (reason) { case AVAudioSessionInterruptionTypeBegan: { NSLog(@"AVAudioSessionInterruptionTypeBegan\n"); [self setActive:NO]; break; } case AVAudioSessionInterruptionTypeEnded: { NSLog(@"AVAudioSessionInterruptionTypeEnded\n"); [self setActive:YES]; break; } } } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKDeviceModel.h ================================================ /* * IJKDeviceModel.h * * Copyright (c) 2015 Bilibili * Copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import #define kIJKDeviceRank_Baseline 10 #define kIJKDeviceRank_AppleA4Class 20 // Cortex-A8 class #define kIJKDeviceRank_AppleA5Class 30 // Cortex-A9 class #define kIJKDeviceRank_AppleA5RAClass 31 // Cortex-A9 class #define kIJKDeviceRank_AppleA5XClass 35 // Cortex-A9 class #define kIJKDeviceRank_AppleA6Class 40 // ARMv7s class #define kIJKDeviceRank_AppleA6XClass 41 // ARMv7s class #define kIJKDeviceRank_AppleA7Class 50 // ARM64 class #define kIJKDeviceRank_AppleA8LowClass 55 // ARM64 class #define kIJKDeviceRank_AppleA8Class 60 // ARM64 class #define kIJKDeviceRank_AppleA8XClass 61 // ARM64 class #define kIJKDeviceRank_AppleA9Class 70 // ARM64 class #define kIJKDeviceRank_AppleA9XClass 71 // ARM64 class #define kIJKDeviceRank_LatestUnknown 90 #define kIJKDeviceRank_Simulator 100 @interface IJKDeviceModel : NSObject @property(nonatomic) NSString *platform; @property(nonatomic) NSString *name; @property(nonatomic) NSInteger rank; + (instancetype)currentModel; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKDeviceModel.m ================================================ /* * IJKDeviceModel.m * * Copyright (c) 2015 Bilibili * Copyright (c) 2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKDeviceModel.h" #include @implementation IJKDeviceModel - (instancetype)initWithPlatform:(NSString *)platform withName:(NSString *)name withRank:(NSInteger)rank { self = [super init]; if (self) { _platform = platform; _name = name; _rank = rank; } return self; } inline static void IJKDeviceRegister(NSMutableDictionary *dict, NSString *platform, NSString *name, NSInteger rank) { IJKDeviceModel *model = [[IJKDeviceModel alloc] initWithPlatform:platform withName:name withRank:rank]; [dict setObject:model forKey:platform]; } + (instancetype)modelWithName:(NSString *)name { static IJKDeviceModel *sLatestModel = nil; static NSDictionary *sModelDictionary = nil; static dispatch_once_t sOnceToken = 0; dispatch_once(&sOnceToken, ^{ NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; // http://en.wikipedia.org/wiki/List_of_iOS_devices // http://www.everyiphone.com // Simulator IJKDeviceRegister(dict, @"i386", @"Simulator", kIJKDeviceRank_Simulator); IJKDeviceRegister(dict, @"x86_64", @"Simulator 64", kIJKDeviceRank_Simulator); // iPhone IJKDeviceRegister(dict, @"iPhone1,1", @"iPhone", kIJKDeviceRank_Baseline); IJKDeviceRegister(dict, @"iPhone1,2", @"iPhone 3G", kIJKDeviceRank_Baseline); IJKDeviceRegister(dict, @"iPhone2,1", @"iPhone 3GS", kIJKDeviceRank_Baseline); IJKDeviceRegister(dict, @"iPhone3,1", @"iPhone 4", kIJKDeviceRank_AppleA4Class); IJKDeviceRegister(dict, @"iPhone3,2", @"iPhone 4", kIJKDeviceRank_AppleA4Class); IJKDeviceRegister(dict, @"iPhone3,3", @"iPhone 4", kIJKDeviceRank_AppleA4Class); IJKDeviceRegister(dict, @"iPhone4,1", @"iPhone 4s", kIJKDeviceRank_AppleA5Class); IJKDeviceRegister(dict, @"iPhone5,1", @"iPhone 5", kIJKDeviceRank_AppleA6Class); IJKDeviceRegister(dict, @"iPhone5,2", @"iPhone 5", kIJKDeviceRank_AppleA6Class); IJKDeviceRegister(dict, @"iPhone5,3", @"iPhone 5c", kIJKDeviceRank_AppleA6Class); IJKDeviceRegister(dict, @"iPhone5,4", @"iPhone 5c", kIJKDeviceRank_AppleA6Class); IJKDeviceRegister(dict, @"iPhone6,1", @"iPhone 5s", kIJKDeviceRank_AppleA7Class); IJKDeviceRegister(dict, @"iPhone6,2", @"iPhone 5s", kIJKDeviceRank_AppleA7Class); IJKDeviceRegister(dict, @"iPhone7,1", @"iPhone 6 Plus", kIJKDeviceRank_AppleA8Class); IJKDeviceRegister(dict, @"iPhone7,2", @"iPhone 6", kIJKDeviceRank_AppleA8Class); IJKDeviceRegister(dict, @"iPhone8,1", @"iPhone 6S", kIJKDeviceRank_AppleA9Class); IJKDeviceRegister(dict, @"iPhone8,2", @"iPhone 6S Plus", kIJKDeviceRank_AppleA9Class); IJKDeviceRegister(dict, @"iPhone8,4", @"iPhone SE", kIJKDeviceRank_AppleA9Class); // iPod Touch IJKDeviceRegister(dict, @"iPod1,1", @"iPod Touch", kIJKDeviceRank_Baseline); IJKDeviceRegister(dict, @"iPod2,1", @"iPod Touch 2G", kIJKDeviceRank_Baseline); IJKDeviceRegister(dict, @"iPod3,1", @"iPod Touch 3G", kIJKDeviceRank_Baseline); IJKDeviceRegister(dict, @"iPod4,1", @"iPod Touch 4G", kIJKDeviceRank_AppleA4Class); IJKDeviceRegister(dict, @"iPod5,1", @"iPod Touch 5G", kIJKDeviceRank_AppleA5Class); IJKDeviceRegister(dict, @"iPod7,1", @"iPod Touch 6G", kIJKDeviceRank_AppleA8LowClass); // iPad / iPad mini IJKDeviceRegister(dict, @"iPad1,1", @"iPad", kIJKDeviceRank_AppleA4Class); IJKDeviceRegister(dict, @"iPad2,1", @"iPad 2", kIJKDeviceRank_AppleA5Class); IJKDeviceRegister(dict, @"iPad2,2", @"iPad 2", kIJKDeviceRank_AppleA5Class); IJKDeviceRegister(dict, @"iPad2,3", @"iPad 2", kIJKDeviceRank_AppleA5Class); IJKDeviceRegister(dict, @"iPad2,4", @"iPad 2", kIJKDeviceRank_AppleA5RAClass); IJKDeviceRegister(dict, @"iPad2,5", @"iPad mini", kIJKDeviceRank_AppleA5RAClass); IJKDeviceRegister(dict, @"iPad2,6", @"iPad mini", kIJKDeviceRank_AppleA5RAClass); IJKDeviceRegister(dict, @"iPad2,7", @"iPad mini", kIJKDeviceRank_AppleA5RAClass); IJKDeviceRegister(dict, @"iPad3,1", @"iPad 3G", kIJKDeviceRank_AppleA5XClass); IJKDeviceRegister(dict, @"iPad3,2", @"iPad 3G", kIJKDeviceRank_AppleA5XClass); IJKDeviceRegister(dict, @"iPad3,3", @"iPad 3G", kIJKDeviceRank_AppleA5XClass); IJKDeviceRegister(dict, @"iPad3,4", @"iPad 4G", kIJKDeviceRank_AppleA6XClass); IJKDeviceRegister(dict, @"iPad3,5", @"iPad 4G", kIJKDeviceRank_AppleA6XClass); IJKDeviceRegister(dict, @"iPad3,6", @"iPad 4G", kIJKDeviceRank_AppleA6XClass); IJKDeviceRegister(dict, @"iPad4,1", @"iPad Air", kIJKDeviceRank_AppleA7Class); IJKDeviceRegister(dict, @"iPad4,2", @"iPad Air", kIJKDeviceRank_AppleA7Class); IJKDeviceRegister(dict, @"iPad4,3", @"iPad Air", kIJKDeviceRank_AppleA7Class); IJKDeviceRegister(dict, @"iPad4,4", @"iPad mini 2G", kIJKDeviceRank_AppleA7Class); IJKDeviceRegister(dict, @"iPad4,5", @"iPad mini 2G", kIJKDeviceRank_AppleA7Class); IJKDeviceRegister(dict, @"iPad4,6", @"iPad mini 2G", kIJKDeviceRank_AppleA7Class); IJKDeviceRegister(dict, @"iPad4,7", @"iPad mini 3", kIJKDeviceRank_AppleA7Class); IJKDeviceRegister(dict, @"iPad4,8", @"iPad mini 3", kIJKDeviceRank_AppleA7Class); IJKDeviceRegister(dict, @"iPad4,9", @"iPad mini 3", kIJKDeviceRank_AppleA7Class); IJKDeviceRegister(dict, @"iPad5,1", @"iPad mini 4", kIJKDeviceRank_AppleA8XClass); IJKDeviceRegister(dict, @"iPad5,2", @"iPad mini 4", kIJKDeviceRank_AppleA8XClass); IJKDeviceRegister(dict, @"iPad5,3", @"iPad Air 2", kIJKDeviceRank_AppleA8XClass); IJKDeviceRegister(dict, @"iPad5,4", @"iPad Air 2", kIJKDeviceRank_AppleA8XClass); IJKDeviceRegister(dict, @"iPad6,3", @"iPad Pro", kIJKDeviceRank_AppleA9XClass); IJKDeviceRegister(dict, @"iPad6,4", @"iPad Pro", kIJKDeviceRank_AppleA9XClass); IJKDeviceRegister(dict, @"iPad6,7", @"iPad Pro", kIJKDeviceRank_AppleA9XClass); IJKDeviceRegister(dict, @"iPad6,8", @"iPad Pro", kIJKDeviceRank_AppleA9XClass); sModelDictionary = dict; sLatestModel = [[IJKDeviceModel alloc] initWithPlatform:name withName:name withRank:kIJKDeviceRank_LatestUnknown]; }); IJKDeviceModel *model = [sModelDictionary objectForKey:name]; if (model == nil) { if (model == nil) { model = sLatestModel; } NSArray *components = [name componentsSeparatedByString:@","]; if (components != nil && components.count > 0) { NSString *majorName = components[0]; if (majorName != nil) { majorName = [majorName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; model = [sModelDictionary objectForKey:majorName]; } } } return model; } + (NSString *)currentModelName { struct utsname systemInfo; uname(&systemInfo); return [NSString stringWithUTF8String:systemInfo.machine]; } + (instancetype)currentModel { return [IJKDeviceModel modelWithName:[IJKDeviceModel currentModelName]]; } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMonitor.h ================================================ /* * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import @interface IJKFFMonitor : NSObject - (instancetype)init; @property(nonatomic) NSDictionary *mediaMeta; @property(nonatomic) NSDictionary *videoMeta; @property(nonatomic) NSDictionary *audioMeta; @property(nonatomic, readonly) int64_t duration; // milliseconds @property(nonatomic, readonly) int64_t bitrate; // bit / sec @property(nonatomic, readonly) float fps; // frame / sec @property(nonatomic, readonly) int width; // width @property(nonatomic, readonly) int height; // height @property(nonatomic, readonly) NSString *vcodec; // video codec @property(nonatomic, readonly) NSString *acodec; // audio codec @property(nonatomic, readonly) int sampleRate; @property(nonatomic, readonly) int64_t channelLayout; @property(nonatomic) NSString *vdecoder; @property(nonatomic) int tcpError; @property(nonatomic) NSString *remoteIp; @property(nonatomic) int httpError; @property(nonatomic) NSString *httpUrl; @property(nonatomic) NSString *httpHost; @property(nonatomic) int httpCode; @property(nonatomic) int64_t httpOpenTick; @property(nonatomic) int64_t httpSeekTick; @property(nonatomic) int httpOpenCount; @property(nonatomic) int httpSeekCount; @property(nonatomic) int64_t lastHttpOpenDuration; @property(nonatomic) int64_t lastHttpSeekDuration; @property(nonatomic) int64_t filesize; @property(nonatomic) int64_t prepareStartTick; @property(nonatomic) int64_t prepareDuration; @property(nonatomic) int64_t firstVideoFrameLatency; @property(nonatomic) int64_t lastPrerollStartTick; @property(nonatomic) int64_t lastPrerollDuration; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMonitor.m ================================================ /* * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKFFMonitor.h" #include "ijksdl/ijksdl_timer.h" #include "ijkplayer/ijkmeta.h" #import "NSString+IJKMedia.h" #define IJK_FFM_SAMPLE_RANGE 2000 @implementation IJKFFMonitor { SDL_SpeedSampler2 _tcpSpeedSampler; } - (instancetype)init { self = [super init]; if (self) { SDL_SpeedSampler2Reset(&_tcpSpeedSampler, IJK_FFM_SAMPLE_RANGE); } return self; } - (float)fps { int fpsNum = [_videoMeta[@IJKM_KEY_FPS_NUM] intValue]; int fpsDen = [_videoMeta[@IJKM_KEY_FPS_DEN] intValue]; if (fpsNum <= 0 || fpsDen <= 0) return 0; return ((float)fpsNum) / fpsDen; } - (int64_t) duration {return [_mediaMeta[@IJKM_KEY_DURATION_US] longLongValue] / 1000;} - (int64_t) bitrate {return [_mediaMeta[@IJKM_KEY_BITRATE] longLongValue];} - (int) width {return [_videoMeta[@IJKM_KEY_WIDTH] intValue];} - (int) height {return [_videoMeta[@IJKM_KEY_HEIGHT] intValue];} - (NSString *) vcodec {return [NSString ijk_stringBeEmptyIfNil:_videoMeta[@IJKM_KEY_CODEC_NAME]];} - (NSString *) acodec {return [NSString ijk_stringBeEmptyIfNil:_audioMeta[@IJKM_KEY_CODEC_NAME]];} - (int) sampleRate {return [_audioMeta[@IJKM_KEY_SAMPLE_RATE] intValue];} - (int64_t) channelLayout {return [_audioMeta[@IJKM_KEY_CHANNEL_LAYOUT] longLongValue];} @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.h ================================================ /* * IJKFFMoviePlayerController.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKMediaPlayback.h" #import "IJKFFMonitor.h" #import "IJKFFOptions.h" #import "IJKSDLGLViewProtocol.h" // media meta #define k_IJKM_KEY_FORMAT @"format" #define k_IJKM_KEY_DURATION_US @"duration_us" #define k_IJKM_KEY_START_US @"start_us" #define k_IJKM_KEY_BITRATE @"bitrate" // stream meta #define k_IJKM_KEY_TYPE @"type" #define k_IJKM_VAL_TYPE__VIDEO @"video" #define k_IJKM_VAL_TYPE__AUDIO @"audio" #define k_IJKM_VAL_TYPE__UNKNOWN @"unknown" #define k_IJKM_KEY_CODEC_NAME @"codec_name" #define k_IJKM_KEY_CODEC_PROFILE @"codec_profile" #define k_IJKM_KEY_CODEC_LONG_NAME @"codec_long_name" // stream: video #define k_IJKM_KEY_WIDTH @"width" #define k_IJKM_KEY_HEIGHT @"height" #define k_IJKM_KEY_FPS_NUM @"fps_num" #define k_IJKM_KEY_FPS_DEN @"fps_den" #define k_IJKM_KEY_TBR_NUM @"tbr_num" #define k_IJKM_KEY_TBR_DEN @"tbr_den" #define k_IJKM_KEY_SAR_NUM @"sar_num" #define k_IJKM_KEY_SAR_DEN @"sar_den" // stream: audio #define k_IJKM_KEY_SAMPLE_RATE @"sample_rate" #define k_IJKM_KEY_CHANNEL_LAYOUT @"channel_layout" #define kk_IJKM_KEY_STREAMS @"streams" typedef enum IJKLogLevel { k_IJK_LOG_UNKNOWN = 0, k_IJK_LOG_DEFAULT = 1, k_IJK_LOG_VERBOSE = 2, k_IJK_LOG_DEBUG = 3, k_IJK_LOG_INFO = 4, k_IJK_LOG_WARN = 5, k_IJK_LOG_ERROR = 6, k_IJK_LOG_FATAL = 7, k_IJK_LOG_SILENT = 8, } IJKLogLevel; @interface IJKFFMoviePlayerController : NSObject - (id)initWithContentURL:(NSURL *)aUrl withOptions:(IJKFFOptions *)options; - (id)initWithContentURLString:(NSString *)aUrlString withOptions:(IJKFFOptions *)options; - (id)initWithMoreContent:(NSURL *)aUrl withOptions:(IJKFFOptions *)options withGLView:(UIView *)glView; - (id)initWithMoreContentString:(NSString *)aUrlString withOptions:(IJKFFOptions *)options withGLView:(UIView *)glView; - (void)prepareToPlay; - (void)play; - (void)pause; - (void)stop; - (BOOL)isPlaying; - (int64_t)trafficStatistic; - (float)dropFrameRate; - (void)setPauseInBackground:(BOOL)pause; - (BOOL)isVideoToolboxOpen; - (void)setHudValue:(NSString *)value forKey:(NSString *)key; + (void)setLogReport:(BOOL)preferLogReport; + (void)setLogLevel:(IJKLogLevel)logLevel; + (BOOL)checkIfFFmpegVersionMatch:(BOOL)showAlert; + (BOOL)checkIfPlayerVersionMatch:(BOOL)showAlert version:(NSString *)version; @property(nonatomic, readonly) CGFloat fpsInMeta; @property(nonatomic, readonly) CGFloat fpsAtOutput; @property(nonatomic) BOOL shouldShowHudView; - (void)setOptionValue:(NSString *)value forKey:(NSString *)key ofCategory:(IJKFFOptionCategory)category; - (void)setOptionIntValue:(int64_t)value forKey:(NSString *)key ofCategory:(IJKFFOptionCategory)category; - (void)setFormatOptionValue: (NSString *)value forKey:(NSString *)key; - (void)setCodecOptionValue: (NSString *)value forKey:(NSString *)key; - (void)setSwsOptionValue: (NSString *)value forKey:(NSString *)key; - (void)setPlayerOptionValue: (NSString *)value forKey:(NSString *)key; - (void)setFormatOptionIntValue: (int64_t)value forKey:(NSString *)key; - (void)setCodecOptionIntValue: (int64_t)value forKey:(NSString *)key; - (void)setSwsOptionIntValue: (int64_t)value forKey:(NSString *)key; - (void)setPlayerOptionIntValue: (int64_t)value forKey:(NSString *)key; @property (nonatomic, retain) id segmentOpenDelegate; @property (nonatomic, retain) id tcpOpenDelegate; @property (nonatomic, retain) id httpOpenDelegate; @property (nonatomic, retain) id liveOpenDelegate; @property (nonatomic, retain) id nativeInvokeDelegate; - (void)didShutdown; #pragma mark KVO properties @property (nonatomic, readonly) IJKFFMonitor *monitor; @end #define IJK_FF_IO_TYPE_READ (1) void IJKFFIOStatDebugCallback(const char *url, int type, int bytes); void IJKFFIOStatRegister(void (*cb)(const char *url, int type, int bytes)); void IJKFFIOStatCompleteDebugCallback(const char *url, int64_t read_bytes, int64_t total_size, int64_t elpased_time, int64_t total_duration); void IJKFFIOStatCompleteRegister(void (*cb)(const char *url, int64_t read_bytes, int64_t total_size, int64_t elpased_time, int64_t total_duration)); ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerController.m ================================================ /* * IJKFFMoviePlayerController.m * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKFFMoviePlayerController.h" #import #import "IJKSDLHudViewController.h" #import "IJKFFMoviePlayerDef.h" #import "IJKMediaPlayback.h" #import "IJKMediaModule.h" #import "IJKAudioKit.h" #import "IJKNotificationManager.h" #import "NSString+IJKMedia.h" #import "ijkioapplication.h" #include "string.h" static const char *kIJKFFRequiredFFmpegVersion = "ff4.0--ijk0.8.8--20201130--001"; // It means you didn't call shutdown if you found this object leaked. @interface IJKWeakHolder : NSObject @property (nonatomic, weak) id object; @end @implementation IJKWeakHolder @end @interface IJKFFMoviePlayerController() @end @implementation IJKFFMoviePlayerController { IjkMediaPlayer *_mediaPlayer; IJKSDLGLView *_glView; IJKFFMoviePlayerMessagePool *_msgPool; NSString *_urlString; NSInteger _videoWidth; NSInteger _videoHeight; NSInteger _sampleAspectRatioNumerator; NSInteger _sampleAspectRatioDenominator; BOOL _seeking; NSInteger _bufferingTime; NSInteger _bufferingPosition; BOOL _keepScreenOnWhilePlaying; BOOL _pauseInBackground; BOOL _isVideoToolboxOpen; BOOL _playingBeforeInterruption; IJKNotificationManager *_notificationManager; AVAppAsyncStatistic _asyncStat; IjkIOAppCacheStatistic _cacheStat; NSTimer *_hudTimer; IJKSDLHudViewController *_hudViewController; } @synthesize view = _view; @synthesize currentPlaybackTime; @synthesize duration; @synthesize playableDuration; @synthesize bufferingProgress = _bufferingProgress; @synthesize numberOfBytesTransferred = _numberOfBytesTransferred; @synthesize isPreparedToPlay = _isPreparedToPlay; @synthesize playbackState = _playbackState; @synthesize loadState = _loadState; @synthesize naturalSize = _naturalSize; @synthesize scalingMode = _scalingMode; @synthesize shouldAutoplay = _shouldAutoplay; @synthesize allowsMediaAirPlay = _allowsMediaAirPlay; @synthesize airPlayMediaActive = _airPlayMediaActive; @synthesize isDanmakuMediaAirPlay = _isDanmakuMediaAirPlay; @synthesize monitor = _monitor; @synthesize shouldShowHudView = _shouldShowHudView; @synthesize isSeekBuffering = _isSeekBuffering; @synthesize isAudioSync = _isAudioSync; @synthesize isVideoSync = _isVideoSync; #define FFP_IO_STAT_STEP (50 * 1024) // as an example void IJKFFIOStatDebugCallback(const char *url, int type, int bytes) { static int64_t s_ff_io_stat_check_points = 0; static int64_t s_ff_io_stat_bytes = 0; if (!url) return; if (type != IJKMP_IO_STAT_READ) return; if (!av_strstart(url, "http:", NULL)) return; s_ff_io_stat_bytes += bytes; if (s_ff_io_stat_bytes < s_ff_io_stat_check_points || s_ff_io_stat_bytes > s_ff_io_stat_check_points + FFP_IO_STAT_STEP) { s_ff_io_stat_check_points = s_ff_io_stat_bytes; NSLog(@"io-stat: %s, +%d = %"PRId64"\n", url, bytes, s_ff_io_stat_bytes); } } void IJKFFIOStatRegister(void (*cb)(const char *url, int type, int bytes)) { ijkmp_io_stat_register(cb); } void IJKFFIOStatCompleteDebugCallback(const char *url, int64_t read_bytes, int64_t total_size, int64_t elpased_time, int64_t total_duration) { if (!url) return; if (!av_strstart(url, "http:", NULL)) return; NSLog(@"io-stat-complete: %s, %"PRId64"/%"PRId64", %"PRId64"/%"PRId64"\n", url, read_bytes, total_size, elpased_time, total_duration); } void IJKFFIOStatCompleteRegister(void (*cb)(const char *url, int64_t read_bytes, int64_t total_size, int64_t elpased_time, int64_t total_duration)) { ijkmp_io_stat_complete_register(cb); } - (id)initWithContentURL:(NSURL *)aUrl withOptions:(IJKFFOptions *)options { if (aUrl == nil) return nil; // Detect if URL is file path and return proper string for it NSString *aUrlString = [aUrl isFileURL] ? [aUrl path] : [aUrl absoluteString]; return [self initWithContentURLString:aUrlString withOptions:options]; } - (void)setScreenOn: (BOOL)on { [IJKMediaModule sharedModule].mediaModuleIdleTimerDisabled = on; // [UIApplication sharedApplication].idleTimerDisabled = on; } - (id)initWithContentURLString:(NSString *)aUrlString withOptions:(IJKFFOptions *)options { if (aUrlString == nil) return nil; self = [super init]; if (self) { ijkmp_global_init(); ijkmp_global_set_inject_callback(ijkff_inject_callback); [IJKFFMoviePlayerController checkIfFFmpegVersionMatch:NO]; if (options == nil) options = [IJKFFOptions optionsByDefault]; // IJKFFIOStatRegister(IJKFFIOStatDebugCallback); // IJKFFIOStatCompleteRegister(IJKFFIOStatCompleteDebugCallback); // init fields _scalingMode = IJKMPMovieScalingModeAspectFit; _shouldAutoplay = YES; memset(&_asyncStat, 0, sizeof(_asyncStat)); memset(&_cacheStat, 0, sizeof(_cacheStat)); _monitor = [[IJKFFMonitor alloc] init]; // init media resource _urlString = aUrlString; // init player _mediaPlayer = ijkmp_ios_create(media_player_msg_loop); _msgPool = [[IJKFFMoviePlayerMessagePool alloc] init]; IJKWeakHolder *weakHolder = [IJKWeakHolder new]; weakHolder.object = self; ijkmp_set_weak_thiz(_mediaPlayer, (__bridge_retained void *) self); ijkmp_set_inject_opaque(_mediaPlayer, (__bridge_retained void *) weakHolder); ijkmp_set_ijkio_inject_opaque(_mediaPlayer, (__bridge_retained void *)weakHolder); ijkmp_set_option_int(_mediaPlayer, IJKMP_OPT_CATEGORY_PLAYER, "start-on-prepared", _shouldAutoplay ? 1 : 0); // init video sink _glView = [[IJKSDLGLView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; _glView.isThirdGLView = NO; _view = _glView; _hudViewController = [[IJKSDLHudViewController alloc] init]; [_hudViewController setRect:_glView.frame]; _shouldShowHudView = NO; _hudViewController.tableView.hidden = YES; [_view addSubview:_hudViewController.tableView]; [self setHudValue:nil forKey:@"scheme"]; [self setHudValue:nil forKey:@"host"]; [self setHudValue:nil forKey:@"path"]; [self setHudValue:nil forKey:@"ip"]; [self setHudValue:nil forKey:@"tcp-info"]; [self setHudValue:nil forKey:@"http"]; [self setHudValue:nil forKey:@"tcp-spd"]; [self setHudValue:nil forKey:@"t-prepared"]; [self setHudValue:nil forKey:@"t-render"]; [self setHudValue:nil forKey:@"t-preroll"]; [self setHudValue:nil forKey:@"t-http-open"]; [self setHudValue:nil forKey:@"t-http-seek"]; self.shouldShowHudView = options.showHudView; ijkmp_ios_set_glview(_mediaPlayer, _glView); ijkmp_set_option(_mediaPlayer, IJKMP_OPT_CATEGORY_PLAYER, "overlay-format", "fcc-_es2"); #ifdef DEBUG [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_DEBUG]; #else [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_SILENT]; #endif // init audio sink [[IJKAudioKit sharedInstance] setupAudioSession]; [options applyTo:_mediaPlayer]; _pauseInBackground = NO; // init extra _keepScreenOnWhilePlaying = YES; [self setScreenOn:YES]; _notificationManager = [[IJKNotificationManager alloc] init]; [self registerApplicationObservers]; } return self; } - (id)initWithMoreContent:(NSURL *)aUrl withOptions:(IJKFFOptions *)options withGLView:(UIView *)glView { if (aUrl == nil) return nil; // Detect if URL is file path and return proper string for it NSString *aUrlString = [aUrl isFileURL] ? [aUrl path] : [aUrl absoluteString]; return [self initWithMoreContentString:aUrlString withOptions:options withGLView:glView]; } - (id)initWithMoreContentString:(NSString *)aUrlString withOptions:(IJKFFOptions *)options withGLView:(UIView *)glView { if (aUrlString == nil || glView == nil) return nil; self = [super init]; if (self) { ijkmp_global_init(); ijkmp_global_set_inject_callback(ijkff_inject_callback); [IJKFFMoviePlayerController checkIfFFmpegVersionMatch:NO]; if (options == nil) options = [IJKFFOptions optionsByDefault]; // IJKFFIOStatRegister(IJKFFIOStatDebugCallback); // IJKFFIOStatCompleteRegister(IJKFFIOStatCompleteDebugCallback); // init fields _scalingMode = IJKMPMovieScalingModeAspectFit; _shouldAutoplay = YES; memset(&_asyncStat, 0, sizeof(_asyncStat)); memset(&_cacheStat, 0, sizeof(_cacheStat)); _monitor = [[IJKFFMonitor alloc] init]; // init media resource _urlString = aUrlString; // init player _mediaPlayer = ijkmp_ios_create(media_player_msg_loop); _msgPool = [[IJKFFMoviePlayerMessagePool alloc] init]; IJKWeakHolder *weakHolder = [IJKWeakHolder new]; weakHolder.object = self; ijkmp_set_weak_thiz(_mediaPlayer, (__bridge_retained void *) self); ijkmp_set_inject_opaque(_mediaPlayer, (__bridge_retained void *) weakHolder); ijkmp_set_ijkio_inject_opaque(_mediaPlayer, (__bridge_retained void *)weakHolder); ijkmp_set_option_int(_mediaPlayer, IJKMP_OPT_CATEGORY_PLAYER, "start-on-prepared", _shouldAutoplay ? 1 : 0); self.shouldShowHudView = options.showHudView; glView.isThirdGLView = YES; _view = _glView = (IJKSDLGLView *)glView; _hudViewController = [[IJKSDLHudViewController alloc] init]; [_hudViewController setRect:_glView.frame]; _shouldShowHudView = NO; _hudViewController.tableView.hidden = YES; [_view addSubview:_hudViewController.tableView]; [self setHudValue:nil forKey:@"scheme"]; [self setHudValue:nil forKey:@"host"]; [self setHudValue:nil forKey:@"path"]; [self setHudValue:nil forKey:@"ip"]; [self setHudValue:nil forKey:@"tcp-info"]; [self setHudValue:nil forKey:@"http"]; [self setHudValue:nil forKey:@"tcp-spd"]; [self setHudValue:nil forKey:@"t-prepared"]; [self setHudValue:nil forKey:@"t-render"]; [self setHudValue:nil forKey:@"t-preroll"]; [self setHudValue:nil forKey:@"t-http-open"]; [self setHudValue:nil forKey:@"t-http-seek"]; self.shouldShowHudView = options.showHudView; ijkmp_ios_set_glview(_mediaPlayer, _glView); ijkmp_set_option(_mediaPlayer, IJKMP_OPT_CATEGORY_PLAYER, "overlay-format", "fcc-_es2"); #ifdef DEBUG [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_DEBUG]; #else [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_SILENT]; #endif // init audio sink [[IJKAudioKit sharedInstance] setupAudioSession]; [options applyTo:_mediaPlayer]; _pauseInBackground = NO; // init extra _keepScreenOnWhilePlaying = YES; [self setScreenOn:YES]; _notificationManager = [[IJKNotificationManager alloc] init]; [self registerApplicationObservers]; } return self; } - (void)dealloc { // [self unregisterApplicationObservers]; } - (void)setShouldAutoplay:(BOOL)shouldAutoplay { _shouldAutoplay = shouldAutoplay; if (!_mediaPlayer) return; ijkmp_set_option_int(_mediaPlayer, IJKMP_OPT_CATEGORY_PLAYER, "start-on-prepared", _shouldAutoplay ? 1 : 0); } - (BOOL)shouldAutoplay { return _shouldAutoplay; } - (void)prepareToPlay { if (!_mediaPlayer) return; [self setScreenOn:_keepScreenOnWhilePlaying]; ijkmp_set_data_source(_mediaPlayer, [_urlString UTF8String]); ijkmp_set_option(_mediaPlayer, IJKMP_OPT_CATEGORY_FORMAT, "safe", "0"); // for concat demuxer _monitor.prepareStartTick = (int64_t)SDL_GetTickHR(); ijkmp_prepare_async(_mediaPlayer); } - (void)setHudUrl:(NSString *)urlString { if ([[NSThread currentThread] isMainThread]) { NSURL *url = [NSURL URLWithString:urlString]; [self setHudValue:url.scheme forKey:@"scheme"]; [self setHudValue:url.host forKey:@"host"]; [self setHudValue:url.path forKey:@"path"]; } else { dispatch_async(dispatch_get_main_queue(), ^{ [self setHudUrl:urlString]; }); } } - (void)play { if (!_mediaPlayer) return; [self setScreenOn:_keepScreenOnWhilePlaying]; [self startHudTimer]; ijkmp_start(_mediaPlayer); } - (void)pause { if (!_mediaPlayer) return; // [self stopHudTimer]; ijkmp_pause(_mediaPlayer); } - (void)stop { if (!_mediaPlayer) return; [self setScreenOn:NO]; [self stopHudTimer]; ijkmp_stop(_mediaPlayer); } - (BOOL)isPlaying { if (!_mediaPlayer) return NO; return ijkmp_is_playing(_mediaPlayer); } - (void)setPauseInBackground:(BOOL)pause { _pauseInBackground = pause; } - (BOOL)isVideoToolboxOpen { if (!_mediaPlayer) return NO; return _isVideoToolboxOpen; } inline static int getPlayerOption(IJKFFOptionCategory category) { int mp_category = -1; switch (category) { case kIJKFFOptionCategoryFormat: mp_category = IJKMP_OPT_CATEGORY_FORMAT; break; case kIJKFFOptionCategoryCodec: mp_category = IJKMP_OPT_CATEGORY_CODEC; break; case kIJKFFOptionCategorySws: mp_category = IJKMP_OPT_CATEGORY_SWS; break; case kIJKFFOptionCategoryPlayer: mp_category = IJKMP_OPT_CATEGORY_PLAYER; break; default: NSLog(@"unknown option category: %d\n", category); } return mp_category; } - (void)setOptionValue:(NSString *)value forKey:(NSString *)key ofCategory:(IJKFFOptionCategory)category { assert(_mediaPlayer); if (!_mediaPlayer) return; ijkmp_set_option(_mediaPlayer, getPlayerOption(category), [key UTF8String], [value UTF8String]); } - (void)setOptionIntValue:(int64_t)value forKey:(NSString *)key ofCategory:(IJKFFOptionCategory)category { assert(_mediaPlayer); if (!_mediaPlayer) return; ijkmp_set_option_int(_mediaPlayer, getPlayerOption(category), [key UTF8String], value); } + (void)setLogReport:(BOOL)preferLogReport { ijkmp_global_set_log_report(preferLogReport ? 1 : 0); } + (void)setLogLevel:(IJKLogLevel)logLevel { ijkmp_global_set_log_level(logLevel); } + (BOOL)checkIfFFmpegVersionMatch:(BOOL)showAlert; { const char *actualVersion = av_version_info(); const char *expectVersion = kIJKFFRequiredFFmpegVersion; if (0 == strcmp(actualVersion, expectVersion)) { return YES; } else { NSString *message = [NSString stringWithFormat:@"actual: %s\n expect: %s\n", actualVersion, expectVersion]; NSLog(@"\n!!!!!!!!!!\n%@\n!!!!!!!!!!\n", message); if (showAlert) { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Unexpected FFmpeg version" message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alertView show]; } return NO; } } + (BOOL)checkIfPlayerVersionMatch:(BOOL)showAlert version:(NSString *)version { const char *actualVersion = ijkmp_version(); const char *expectVersion = version.UTF8String; if (0 == strcmp(actualVersion, expectVersion)) { return YES; } else { if (showAlert) { NSString *message = [NSString stringWithFormat:@"actual: %s\n expect: %s\n", actualVersion, expectVersion]; UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Unexpected ijkplayer version" message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alertView show]; } return NO; } } - (void)shutdown { if (!_mediaPlayer) return; [self stopHudTimer]; [self unregisterApplicationObservers]; [self setScreenOn:NO]; [self performSelectorInBackground:@selector(shutdownWaitStop:) withObject:self]; } - (void)shutdownWaitStop:(IJKFFMoviePlayerController *) mySelf { if (!_mediaPlayer) return; ijkmp_stop(_mediaPlayer); ijkmp_shutdown(_mediaPlayer); [self performSelectorOnMainThread:@selector(shutdownClose:) withObject:self waitUntilDone:YES]; } - (void)shutdownClose:(IJKFFMoviePlayerController *) mySelf { if (!_mediaPlayer) return; _segmentOpenDelegate = nil; _tcpOpenDelegate = nil; _httpOpenDelegate = nil; _liveOpenDelegate = nil; _nativeInvokeDelegate = nil; __unused id weakPlayer = (__bridge_transfer IJKFFMoviePlayerController*)ijkmp_set_weak_thiz(_mediaPlayer, NULL); __unused id weakHolder = (__bridge_transfer IJKWeakHolder*)ijkmp_set_inject_opaque(_mediaPlayer, NULL); __unused id weakijkHolder = (__bridge_transfer IJKWeakHolder*)ijkmp_set_ijkio_inject_opaque(_mediaPlayer, NULL); ijkmp_dec_ref_p(&_mediaPlayer); [self didShutdown]; } - (void)didShutdown { } - (IJKMPMoviePlaybackState)playbackState { if (!_mediaPlayer) return NO; IJKMPMoviePlaybackState mpState = IJKMPMoviePlaybackStateStopped; int state = ijkmp_get_state(_mediaPlayer); switch (state) { case MP_STATE_STOPPED: case MP_STATE_COMPLETED: case MP_STATE_ERROR: case MP_STATE_END: mpState = IJKMPMoviePlaybackStateStopped; break; case MP_STATE_IDLE: case MP_STATE_INITIALIZED: case MP_STATE_ASYNC_PREPARING: case MP_STATE_PAUSED: mpState = IJKMPMoviePlaybackStatePaused; break; case MP_STATE_PREPARED: case MP_STATE_STARTED: { if (_seeking) mpState = IJKMPMoviePlaybackStateSeekingForward; else mpState = IJKMPMoviePlaybackStatePlaying; break; } } // IJKMPMoviePlaybackStatePlaying, // IJKMPMoviePlaybackStatePaused, // IJKMPMoviePlaybackStateStopped, // IJKMPMoviePlaybackStateInterrupted, // IJKMPMoviePlaybackStateSeekingForward, // IJKMPMoviePlaybackStateSeekingBackward return mpState; } - (void)setCurrentPlaybackTime:(NSTimeInterval)aCurrentPlaybackTime { if (!_mediaPlayer) return; _seeking = YES; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification object:self]; _bufferingPosition = 0; ijkmp_seek_to(_mediaPlayer, aCurrentPlaybackTime * 1000); } - (NSTimeInterval)currentPlaybackTime { if (!_mediaPlayer) return 0.0f; NSTimeInterval ret = ijkmp_get_current_position(_mediaPlayer); if (isnan(ret) || isinf(ret)) return -1; return ret / 1000; } - (NSTimeInterval)duration { if (!_mediaPlayer) return 0.0f; NSTimeInterval ret = ijkmp_get_duration(_mediaPlayer); if (isnan(ret) || isinf(ret)) return -1; return ret / 1000; } - (NSTimeInterval)playableDuration { if (!_mediaPlayer) return 0.0f; NSTimeInterval demux_cache = ((NSTimeInterval)ijkmp_get_playable_duration(_mediaPlayer)) / 1000; int64_t buf_forwards = _asyncStat.buf_forwards; int64_t bit_rate = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_BIT_RATE, 0); if (buf_forwards > 0 && bit_rate > 0) { NSTimeInterval io_cache = ((float)buf_forwards) * 8 / bit_rate; demux_cache += io_cache; } return demux_cache; } - (CGSize)naturalSize { return _naturalSize; } - (void)changeNaturalSize { [self willChangeValueForKey:@"naturalSize"]; if (_sampleAspectRatioNumerator > 0 && _sampleAspectRatioDenominator > 0) { self->_naturalSize = CGSizeMake(1.0f * _videoWidth * _sampleAspectRatioNumerator / _sampleAspectRatioDenominator, _videoHeight); } else { self->_naturalSize = CGSizeMake(_videoWidth, _videoHeight); } [self didChangeValueForKey:@"naturalSize"]; if (self->_naturalSize.width > 0 && self->_naturalSize.height > 0) { [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMovieNaturalSizeAvailableNotification object:self]; } } - (void)setScalingMode: (IJKMPMovieScalingMode) aScalingMode { IJKMPMovieScalingMode newScalingMode = aScalingMode; switch (aScalingMode) { case IJKMPMovieScalingModeNone: [_view setContentMode:UIViewContentModeCenter]; break; case IJKMPMovieScalingModeAspectFit: [_view setContentMode:UIViewContentModeScaleAspectFit]; break; case IJKMPMovieScalingModeAspectFill: [_view setContentMode:UIViewContentModeScaleAspectFill]; break; case IJKMPMovieScalingModeFill: [_view setContentMode:UIViewContentModeScaleToFill]; break; default: newScalingMode = _scalingMode; } _scalingMode = newScalingMode; } // deprecated, for MPMoviePlayerController compatiable - (UIImage *)thumbnailImageAtTime:(NSTimeInterval)playbackTime timeOption:(IJKMPMovieTimeOption)option { return nil; } - (UIImage *)thumbnailImageAtCurrentTime { if ([_view conformsToProtocol:@protocol(IJKSDLGLViewProtocol)]) { id glView = (id)_view; return [glView snapshot]; } return nil; } - (CGFloat)fpsAtOutput { return _glView.fps; } inline static NSString *formatedDurationMilli(int64_t duration) { if (duration >= 1000) { return [NSString stringWithFormat:@"%.2f sec", ((float)duration) / 1000]; } else { return [NSString stringWithFormat:@"%ld msec", (long)duration]; } } inline static NSString *formatedDurationBytesAndBitrate(int64_t bytes, int64_t bitRate) { if (bitRate <= 0) { return @"inf"; } return formatedDurationMilli(((float)bytes) * 8 * 1000 / bitRate); } inline static NSString *formatedSize(int64_t bytes) { if (bytes >= 100 * 1024) { return [NSString stringWithFormat:@"%.2f MB", ((float)bytes) / 1000 / 1024]; } else if (bytes >= 100) { return [NSString stringWithFormat:@"%.1f KB", ((float)bytes) / 1000]; } else { return [NSString stringWithFormat:@"%ld B", (long)bytes]; } } inline static NSString *formatedSpeed(int64_t bytes, int64_t elapsed_milli) { if (elapsed_milli <= 0) { return @"N/A"; } if (bytes <= 0) { return @"0"; } float bytes_per_sec = ((float)bytes) * 1000.f / elapsed_milli; if (bytes_per_sec >= 1000 * 1000) { return [NSString stringWithFormat:@"%.2f MB/s", ((float)bytes_per_sec) / 1000 / 1000]; } else if (bytes_per_sec >= 1000) { return [NSString stringWithFormat:@"%.1f KB/s", ((float)bytes_per_sec) / 1000]; } else { return [NSString stringWithFormat:@"%ld B/s", (long)bytes_per_sec]; } } - (void)refreshHudView { if (_mediaPlayer == nil) return; int64_t vdec = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_VIDEO_DECODER, FFP_PROPV_DECODER_UNKNOWN); float vdps = ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND, .0f); float vfps = ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND, .0f); switch (vdec) { case FFP_PROPV_DECODER_VIDEOTOOLBOX: [self setHudValue:@"VideoToolbox" forKey:@"vdec"]; break; case FFP_PROPV_DECODER_AVCODEC: [self setHudValue:[NSString stringWithFormat:@"avcodec %d.%d.%d", LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO] forKey:@"vdec"]; break; default: [self setHudValue:@"N/A" forKey:@"vdec"]; break; } [self setHudValue:[NSString stringWithFormat:@"%.2f / %.2f", vdps, vfps] forKey:@"fps"]; int64_t vcacheb = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_VIDEO_CACHED_BYTES, 0); int64_t acacheb = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_AUDIO_CACHED_BYTES, 0); int64_t vcached = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_VIDEO_CACHED_DURATION, 0); int64_t acached = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_AUDIO_CACHED_DURATION, 0); int64_t vcachep = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_VIDEO_CACHED_PACKETS, 0); int64_t acachep = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_AUDIO_CACHED_PACKETS, 0); [self setHudValue:[NSString stringWithFormat:@"%@, %@, %"PRId64" packets", formatedDurationMilli(vcached), formatedSize(vcacheb), vcachep] forKey:@"v-cache"]; [self setHudValue:[NSString stringWithFormat:@"%@, %@, %"PRId64" packets", formatedDurationMilli(acached), formatedSize(acacheb), acachep] forKey:@"a-cache"]; float avdelay = ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_AVDELAY, .0f); float avdiff = ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_AVDIFF, .0f); [self setHudValue:[NSString stringWithFormat:@"%.3f %.3f", avdelay, -avdiff] forKey:@"delay"]; int64_t bitRate = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_BIT_RATE, 0); [self setHudValue:[NSString stringWithFormat:@"-%@, %@", formatedSize(_cacheStat.cache_file_forwards), formatedDurationBytesAndBitrate(_cacheStat.cache_file_forwards, bitRate)] forKey:@"cache-forwards"]; [self setHudValue:formatedSize(_cacheStat.cache_physical_pos) forKey:@"cache-physical-pos"]; [self setHudValue:formatedSize(_cacheStat.cache_file_pos) forKey:@"cache-file-pos"]; [self setHudValue:formatedSize(_cacheStat.cache_count_bytes) forKey:@"cache-bytes"]; [self setHudValue:[NSString stringWithFormat:@"-%@, %@", formatedSize(_asyncStat.buf_backwards), formatedDurationBytesAndBitrate(_asyncStat.buf_backwards, bitRate)] forKey:@"async-backward"]; [self setHudValue:[NSString stringWithFormat:@"+%@, %@", formatedSize(_asyncStat.buf_forwards), formatedDurationBytesAndBitrate(_asyncStat.buf_forwards, bitRate)] forKey:@"async-forward"]; int64_t tcpSpeed = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_TCP_SPEED, 0); [self setHudValue:[NSString stringWithFormat:@"%@", formatedSpeed(tcpSpeed, 1000)] forKey:@"tcp-spd"]; [self setHudValue:formatedDurationMilli(_monitor.prepareDuration) forKey:@"t-prepared"]; [self setHudValue:formatedDurationMilli(_monitor.firstVideoFrameLatency) forKey:@"t-render"]; [self setHudValue:formatedDurationMilli(_monitor.lastPrerollDuration) forKey:@"t-preroll"]; [self setHudValue:[NSString stringWithFormat:@"%@ / %d", formatedDurationMilli(_monitor.lastHttpOpenDuration), _monitor.httpOpenCount] forKey:@"t-http-open"]; [self setHudValue:[NSString stringWithFormat:@"%@ / %d", formatedDurationMilli(_monitor.lastHttpSeekDuration), _monitor.httpSeekCount] forKey:@"t-http-seek"]; } - (void)startHudTimer { if (!_shouldShowHudView) return; if (_hudTimer != nil) return; if ([[NSThread currentThread] isMainThread]) { _hudViewController.tableView.hidden = NO; _hudTimer = [NSTimer scheduledTimerWithTimeInterval:.5f target:self selector:@selector(refreshHudView) userInfo:nil repeats:YES]; } else { dispatch_async(dispatch_get_main_queue(), ^{ [self startHudTimer]; }); } } - (void)stopHudTimer { if (_hudTimer == nil) return; if ([[NSThread currentThread] isMainThread]) { _hudViewController.tableView.hidden = YES; [_hudTimer invalidate]; _hudTimer = nil; } else { dispatch_async(dispatch_get_main_queue(), ^{ [self stopHudTimer]; }); } } - (void)setShouldShowHudView:(BOOL)shouldShowHudView { if (shouldShowHudView == _shouldShowHudView) { return; } _shouldShowHudView = shouldShowHudView; if (shouldShowHudView) [self startHudTimer]; else [self stopHudTimer]; } - (BOOL)shouldShowHudView { return _shouldShowHudView; } - (void)setPlaybackRate:(float)playbackRate { if (!_mediaPlayer) return; return ijkmp_set_playback_rate(_mediaPlayer, playbackRate); } - (float)playbackRate { if (!_mediaPlayer) return 0.0f; return ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_PLAYBACK_RATE, 0.0f); } - (void)setPlaybackVolume:(float)volume { if (!_mediaPlayer) return; return ijkmp_set_playback_volume(_mediaPlayer, volume); } - (float)playbackVolume { if (!_mediaPlayer) return 0.0f; return ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_PLAYBACK_VOLUME, 1.0f); } - (int64_t)getFileSize { if (!_mediaPlayer) return 0; return ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_LOGICAL_FILE_SIZE, 0); } - (int64_t)trafficStatistic { if (!_mediaPlayer) return 0; return ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_TRAFFIC_STATISTIC_BYTE_COUNT, 0); } - (float)dropFrameRate { if (!_mediaPlayer) return 0; return ijkmp_get_property_float(_mediaPlayer, FFP_PROP_FLOAT_DROP_FRAME_RATE, 0.0f); } inline static void fillMetaInternal(NSMutableDictionary *meta, IjkMediaMeta *rawMeta, const char *name, NSString *defaultValue) { if (!meta || !rawMeta || !name) return; NSString *key = [NSString stringWithUTF8String:name]; const char *value = ijkmeta_get_string_l(rawMeta, name); if (value) { [meta setObject:[NSString stringWithUTF8String:value] forKey:key]; } else if (defaultValue) { [meta setObject:defaultValue forKey:key]; } else { [meta removeObjectForKey:key]; } } - (void)postEvent: (IJKFFMoviePlayerMessage *)msg { if (!msg) return; AVMessage *avmsg = &msg->_msg; switch (avmsg->what) { case FFP_MSG_FLUSH: break; case FFP_MSG_ERROR: { NSLog(@"FFP_MSG_ERROR: %d\n", avmsg->arg1); [self setScreenOn:NO]; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification object:self]; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerPlaybackDidFinishNotification object:self userInfo:@{ IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey: @(IJKMPMovieFinishReasonPlaybackError), @"error": @(avmsg->arg1)}]; break; } case FFP_MSG_PREPARED: { NSLog(@"FFP_MSG_PREPARED:\n"); _monitor.prepareDuration = (int64_t)SDL_GetTickHR() - _monitor.prepareStartTick; int64_t vdec = ijkmp_get_property_int64(_mediaPlayer, FFP_PROP_INT64_VIDEO_DECODER, FFP_PROPV_DECODER_UNKNOWN); switch (vdec) { case FFP_PROPV_DECODER_VIDEOTOOLBOX: _monitor.vdecoder = @"VideoToolbox"; break; case FFP_PROPV_DECODER_AVCODEC: _monitor.vdecoder = [NSString stringWithFormat:@"avcodec %d.%d.%d", LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO]; break; default: _monitor.vdecoder = @"Unknown"; break; } IjkMediaMeta *rawMeta = ijkmp_get_meta_l(_mediaPlayer); if (rawMeta) { ijkmeta_lock(rawMeta); NSMutableDictionary *newMediaMeta = [[NSMutableDictionary alloc] init]; fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_FORMAT, nil); fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_DURATION_US, nil); fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_START_US, nil); fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_BITRATE, nil); fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_VIDEO_STREAM, nil); fillMetaInternal(newMediaMeta, rawMeta, IJKM_KEY_AUDIO_STREAM, nil); int64_t video_stream = ijkmeta_get_int64_l(rawMeta, IJKM_KEY_VIDEO_STREAM, -1); int64_t audio_stream = ijkmeta_get_int64_l(rawMeta, IJKM_KEY_AUDIO_STREAM, -1); NSMutableArray *streams = [[NSMutableArray alloc] init]; size_t count = ijkmeta_get_children_count_l(rawMeta); for(size_t i = 0; i < count; ++i) { IjkMediaMeta *streamRawMeta = ijkmeta_get_child_l(rawMeta, i); NSMutableDictionary *streamMeta = [[NSMutableDictionary alloc] init]; if (streamRawMeta) { fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_TYPE, k_IJKM_VAL_TYPE__UNKNOWN); const char *type = ijkmeta_get_string_l(streamRawMeta, IJKM_KEY_TYPE); if (type) { fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_CODEC_NAME, nil); fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_CODEC_PROFILE, nil); fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_CODEC_LONG_NAME, nil); fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_BITRATE, nil); if (0 == strcmp(type, IJKM_VAL_TYPE__VIDEO)) { fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_WIDTH, nil); fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_HEIGHT, nil); fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_FPS_NUM, nil); fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_FPS_DEN, nil); fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_TBR_NUM, nil); fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_TBR_DEN, nil); fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_SAR_NUM, nil); fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_SAR_DEN, nil); if (video_stream == i) { _monitor.videoMeta = streamMeta; int64_t fps_num = ijkmeta_get_int64_l(streamRawMeta, IJKM_KEY_FPS_NUM, 0); int64_t fps_den = ijkmeta_get_int64_l(streamRawMeta, IJKM_KEY_FPS_DEN, 0); if (fps_num > 0 && fps_den > 0) { _fpsInMeta = ((CGFloat)(fps_num)) / fps_den; NSLog(@"fps in meta %f\n", _fpsInMeta); } } } else if (0 == strcmp(type, IJKM_VAL_TYPE__AUDIO)) { fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_SAMPLE_RATE, nil); fillMetaInternal(streamMeta, streamRawMeta, IJKM_KEY_CHANNEL_LAYOUT, nil); if (audio_stream == i) { _monitor.audioMeta = streamMeta; } } } } [streams addObject:streamMeta]; } [newMediaMeta setObject:streams forKey:kk_IJKM_KEY_STREAMS]; ijkmeta_unlock(rawMeta); _monitor.mediaMeta = newMediaMeta; } ijkmp_set_playback_rate(_mediaPlayer, [self playbackRate]); ijkmp_set_playback_volume(_mediaPlayer, [self playbackVolume]); [self startHudTimer]; _isPreparedToPlay = YES; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification object:self]; _loadState = IJKMPMovieLoadStatePlayable | IJKMPMovieLoadStatePlaythroughOK; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerLoadStateDidChangeNotification object:self]; break; } case FFP_MSG_COMPLETED: { [self setScreenOn:NO]; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification object:self]; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerPlaybackDidFinishNotification object:self userInfo:@{IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey: @(IJKMPMovieFinishReasonPlaybackEnded)}]; break; } case FFP_MSG_VIDEO_SIZE_CHANGED: NSLog(@"FFP_MSG_VIDEO_SIZE_CHANGED: %d, %d\n", avmsg->arg1, avmsg->arg2); if (avmsg->arg1 > 0) _videoWidth = avmsg->arg1; if (avmsg->arg2 > 0) _videoHeight = avmsg->arg2; [self changeNaturalSize]; break; case FFP_MSG_SAR_CHANGED: NSLog(@"FFP_MSG_SAR_CHANGED: %d, %d\n", avmsg->arg1, avmsg->arg2); if (avmsg->arg1 > 0) _sampleAspectRatioNumerator = avmsg->arg1; if (avmsg->arg2 > 0) _sampleAspectRatioDenominator = avmsg->arg2; [self changeNaturalSize]; break; case FFP_MSG_BUFFERING_START: { NSLog(@"FFP_MSG_BUFFERING_START:\n"); _monitor.lastPrerollStartTick = (int64_t)SDL_GetTickHR(); _loadState = IJKMPMovieLoadStateStalled; _isSeekBuffering = avmsg->arg1; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerLoadStateDidChangeNotification object:self]; _isSeekBuffering = 0; break; } case FFP_MSG_BUFFERING_END: { NSLog(@"FFP_MSG_BUFFERING_END:\n"); _monitor.lastPrerollDuration = (int64_t)SDL_GetTickHR() - _monitor.lastPrerollStartTick; _loadState = IJKMPMovieLoadStatePlayable | IJKMPMovieLoadStatePlaythroughOK; _isSeekBuffering = avmsg->arg1; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerLoadStateDidChangeNotification object:self]; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification object:self]; _isSeekBuffering = 0; break; } case FFP_MSG_BUFFERING_UPDATE: _bufferingPosition = avmsg->arg1; _bufferingProgress = avmsg->arg2; // NSLog(@"FFP_MSG_BUFFERING_UPDATE: %d, %%%d\n", _bufferingPosition, _bufferingProgress); break; case FFP_MSG_BUFFERING_BYTES_UPDATE: // NSLog(@"FFP_MSG_BUFFERING_BYTES_UPDATE: %d\n", avmsg->arg1); break; case FFP_MSG_BUFFERING_TIME_UPDATE: _bufferingTime = avmsg->arg1; // NSLog(@"FFP_MSG_BUFFERING_TIME_UPDATE: %d\n", avmsg->arg1); break; case FFP_MSG_PLAYBACK_STATE_CHANGED: [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification object:self]; break; case FFP_MSG_SEEK_COMPLETE: { NSLog(@"FFP_MSG_SEEK_COMPLETE:\n"); [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerDidSeekCompleteNotification object:self userInfo:@{IJKMPMoviePlayerDidSeekCompleteTargetKey: @(avmsg->arg1), IJKMPMoviePlayerDidSeekCompleteErrorKey: @(avmsg->arg2)}]; _seeking = NO; break; } case FFP_MSG_VIDEO_DECODER_OPEN: { _isVideoToolboxOpen = avmsg->arg1; NSLog(@"FFP_MSG_VIDEO_DECODER_OPEN: %@\n", _isVideoToolboxOpen ? @"true" : @"false"); [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerVideoDecoderOpenNotification object:self]; break; } case FFP_MSG_VIDEO_RENDERING_START: { NSLog(@"FFP_MSG_VIDEO_RENDERING_START:\n"); _monitor.firstVideoFrameLatency = (int64_t)SDL_GetTickHR() - _monitor.prepareStartTick; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerFirstVideoFrameRenderedNotification object:self]; break; } case FFP_MSG_AUDIO_RENDERING_START: { NSLog(@"FFP_MSG_AUDIO_RENDERING_START:\n"); [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerFirstAudioFrameRenderedNotification object:self]; break; } case FFP_MSG_AUDIO_DECODED_START: { NSLog(@"FFP_MSG_AUDIO_DECODED_START:\n"); [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerFirstAudioFrameDecodedNotification object:self]; break; } case FFP_MSG_VIDEO_DECODED_START: { NSLog(@"FFP_MSG_VIDEO_DECODED_START:\n"); [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerFirstVideoFrameDecodedNotification object:self]; break; } case FFP_MSG_OPEN_INPUT: { NSLog(@"FFP_MSG_OPEN_INPUT:\n"); [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerOpenInputNotification object:self]; break; } case FFP_MSG_FIND_STREAM_INFO: { NSLog(@"FFP_MSG_FIND_STREAM_INFO:\n"); [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerFindStreamInfoNotification object:self]; break; } case FFP_MSG_COMPONENT_OPEN: { NSLog(@"FFP_MSG_COMPONENT_OPEN:\n"); [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerComponentOpenNotification object:self]; break; } case FFP_MSG_ACCURATE_SEEK_COMPLETE: { NSLog(@"FFP_MSG_ACCURATE_SEEK_COMPLETE:\n"); [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerAccurateSeekCompleteNotification object:self userInfo:@{IJKMPMoviePlayerDidAccurateSeekCompleteCurPos: @(avmsg->arg1)}]; break; } case FFP_MSG_VIDEO_SEEK_RENDERING_START: { NSLog(@"FFP_MSG_VIDEO_SEEK_RENDERING_START:\n"); _isVideoSync = avmsg->arg1; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerSeekVideoStartNotification object:self]; _isVideoSync = 0; break; } case FFP_MSG_AUDIO_SEEK_RENDERING_START: { NSLog(@"FFP_MSG_AUDIO_SEEK_RENDERING_START:\n"); _isAudioSync = avmsg->arg1; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerSeekAudioStartNotification object:self]; _isAudioSync = 0; break; } default: // NSLog(@"unknown FFP_MSG_xxx(%d)\n", avmsg->what); break; } [_msgPool recycle:msg]; } - (IJKFFMoviePlayerMessage *) obtainMessage { return [_msgPool obtain]; } inline static IJKFFMoviePlayerController *ffplayerRetain(void *arg) { return (__bridge_transfer IJKFFMoviePlayerController *) arg; } int media_player_msg_loop(void* arg) { @autoreleasepool { IjkMediaPlayer *mp = (IjkMediaPlayer*)arg; __weak IJKFFMoviePlayerController *ffpController = ffplayerRetain(ijkmp_set_weak_thiz(mp, NULL)); while (ffpController) { @autoreleasepool { IJKFFMoviePlayerMessage *msg = [ffpController obtainMessage]; if (!msg) break; int retval = ijkmp_get_msg(mp, &msg->_msg, 1); if (retval < 0) break; // block-get should never return 0 assert(retval > 0); [ffpController performSelectorOnMainThread:@selector(postEvent:) withObject:msg waitUntilDone:NO]; } } // retained in prepare_async, before SDL_CreateThreadEx ijkmp_dec_ref_p(&mp); return 0; } } #pragma mark av_format_control_message static int onInjectIOControl(IJKFFMoviePlayerController *mpc, id delegate, int type, void *data, size_t data_size) { AVAppIOControl *realData = data; assert(realData); assert(sizeof(AVAppIOControl) == data_size); realData->is_handled = NO; realData->is_url_changed = NO; if (delegate == nil) return 0; NSString *urlString = [NSString stringWithUTF8String:realData->url]; IJKMediaUrlOpenData *openData = [[IJKMediaUrlOpenData alloc] initWithUrl:urlString event:(IJKMediaEvent)type segmentIndex:realData->segment_index retryCounter:realData->retry_counter]; [delegate willOpenUrl:openData]; if (openData.error < 0) return -1; if (openData.isHandled) { realData->is_handled = YES; if (openData.isUrlChanged && openData.url != nil) { realData->is_url_changed = YES; const char *newUrlUTF8 = [openData.url UTF8String]; strlcpy(realData->url, newUrlUTF8, sizeof(realData->url)); realData->url[sizeof(realData->url) - 1] = 0; } } return 0; } static int onInjectTcpIOControl(IJKFFMoviePlayerController *mpc, id delegate, int type, void *data, size_t data_size) { AVAppTcpIOControl *realData = data; assert(realData); assert(sizeof(AVAppTcpIOControl) == data_size); switch (type) { case IJKMediaCtrl_WillTcpOpen: break; case IJKMediaCtrl_DidTcpOpen: mpc->_monitor.tcpError = realData->error; mpc->_monitor.remoteIp = [NSString stringWithUTF8String:realData->ip]; [mpc setHudValue: mpc->_monitor.remoteIp forKey:@"ip"]; break; default: assert(!"unexcepted type for tcp io control"); break; } if (delegate == nil) return 0; NSString *urlString = [NSString stringWithUTF8String:realData->ip]; IJKMediaUrlOpenData *openData = [[IJKMediaUrlOpenData alloc] initWithUrl:urlString event:(IJKMediaEvent)type segmentIndex:0 retryCounter:0]; openData.fd = realData->fd; [delegate willOpenUrl:openData]; if (openData.error < 0) return -1; [mpc setHudValue: [NSString stringWithFormat:@"fd:%d %@", openData.fd, openData.msg?:@"unknown"] forKey:@"tcp-info"]; return 0; } static int onInjectAsyncStatistic(IJKFFMoviePlayerController *mpc, int type, void *data, size_t data_size) { AVAppAsyncStatistic *realData = data; assert(realData); assert(sizeof(AVAppAsyncStatistic) == data_size); mpc->_asyncStat = *realData; return 0; } static int onInectIJKIOStatistic(IJKFFMoviePlayerController *mpc, int type, void *data, size_t data_size) { IjkIOAppCacheStatistic *realData = data; assert(realData); assert(sizeof(IjkIOAppCacheStatistic) == data_size); mpc->_cacheStat = *realData; return 0; } static int64_t calculateElapsed(int64_t begin, int64_t end) { if (begin <= 0) return -1; if (end < begin) return -1; return end - begin; } static int onInjectOnHttpEvent(IJKFFMoviePlayerController *mpc, int type, void *data, size_t data_size) { AVAppHttpEvent *realData = data; assert(realData); assert(sizeof(AVAppHttpEvent) == data_size); NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; NSURL *nsurl = nil; IJKFFMonitor *monitor = mpc->_monitor; NSString *url = monitor.httpUrl; NSString *host = monitor.httpHost; int64_t elapsed = 0; id delegate = mpc.nativeInvokeDelegate; switch (type) { case AVAPP_EVENT_WILL_HTTP_OPEN: url = [NSString stringWithUTF8String:realData->url]; nsurl = [NSURL URLWithString:url]; host = nsurl.host; monitor.httpUrl = url; monitor.httpHost = host; monitor.httpOpenTick = SDL_GetTickHR(); [mpc setHudUrl:url]; if (delegate != nil) { dict[IJKMediaEventAttrKey_host] = [NSString ijk_stringBeEmptyIfNil:host]; dict[IJKMediaEventAttrKey_url] = [NSString ijk_stringBeEmptyIfNil:monitor.httpUrl]; [delegate invoke:type attributes:dict]; } break; case AVAPP_EVENT_DID_HTTP_OPEN: elapsed = calculateElapsed(monitor.httpOpenTick, SDL_GetTickHR()); monitor.httpError = realData->error; monitor.httpCode = realData->http_code; monitor.filesize = realData->filesize; monitor.httpOpenCount++; monitor.httpOpenTick = 0; monitor.lastHttpOpenDuration = elapsed; [mpc setHudValue:@(realData->http_code).stringValue forKey:@"http"]; if (delegate != nil) { dict[IJKMediaEventAttrKey_time_of_event] = @(elapsed).stringValue; dict[IJKMediaEventAttrKey_url] = [NSString ijk_stringBeEmptyIfNil:monitor.httpUrl]; dict[IJKMediaEventAttrKey_host] = [NSString ijk_stringBeEmptyIfNil:host]; dict[IJKMediaEventAttrKey_error] = @(realData->error).stringValue; dict[IJKMediaEventAttrKey_http_code] = @(realData->http_code).stringValue; dict[IJKMediaEventAttrKey_file_size] = @(realData->filesize).stringValue; [delegate invoke:type attributes:dict]; } break; case AVAPP_EVENT_WILL_HTTP_SEEK: monitor.httpSeekTick = SDL_GetTickHR(); if (delegate != nil) { dict[IJKMediaEventAttrKey_host] = [NSString ijk_stringBeEmptyIfNil:host]; dict[IJKMediaEventAttrKey_offset] = @(realData->offset).stringValue; [delegate invoke:type attributes:dict]; } break; case AVAPP_EVENT_DID_HTTP_SEEK: elapsed = calculateElapsed(monitor.httpSeekTick, SDL_GetTickHR()); monitor.httpError = realData->error; monitor.httpCode = realData->http_code; monitor.httpSeekCount++; monitor.httpSeekTick = 0; monitor.lastHttpSeekDuration = elapsed; [mpc setHudValue:@(realData->http_code).stringValue forKey:@"http"]; if (delegate != nil) { dict[IJKMediaEventAttrKey_time_of_event] = @(elapsed).stringValue; dict[IJKMediaEventAttrKey_url] = [NSString ijk_stringBeEmptyIfNil:monitor.httpUrl]; dict[IJKMediaEventAttrKey_host] = [NSString ijk_stringBeEmptyIfNil:host]; dict[IJKMediaEventAttrKey_offset] = @(realData->offset).stringValue; dict[IJKMediaEventAttrKey_error] = @(realData->error).stringValue; dict[IJKMediaEventAttrKey_http_code] = @(realData->http_code).stringValue; [delegate invoke:type attributes:dict]; } break; } return 0; } // NOTE: could be called from multiple thread static int ijkff_inject_callback(void *opaque, int message, void *data, size_t data_size) { IJKWeakHolder *weakHolder = (__bridge IJKWeakHolder*)opaque; IJKFFMoviePlayerController *mpc = weakHolder.object; if (!mpc) return 0; switch (message) { case AVAPP_CTRL_WILL_CONCAT_SEGMENT_OPEN: return onInjectIOControl(mpc, mpc.segmentOpenDelegate, message, data, data_size); case AVAPP_CTRL_WILL_TCP_OPEN: return onInjectTcpIOControl(mpc, mpc.tcpOpenDelegate, message, data, data_size); case AVAPP_CTRL_WILL_HTTP_OPEN: return onInjectIOControl(mpc, mpc.httpOpenDelegate, message, data, data_size); case AVAPP_CTRL_WILL_LIVE_OPEN: return onInjectIOControl(mpc, mpc.liveOpenDelegate, message, data, data_size); case AVAPP_EVENT_ASYNC_STATISTIC: return onInjectAsyncStatistic(mpc, message, data, data_size); case IJKIOAPP_EVENT_CACHE_STATISTIC: return onInectIJKIOStatistic(mpc, message, data, data_size); case AVAPP_CTRL_DID_TCP_OPEN: return onInjectTcpIOControl(mpc, mpc.tcpOpenDelegate, message, data, data_size); case AVAPP_EVENT_WILL_HTTP_OPEN: case AVAPP_EVENT_DID_HTTP_OPEN: case AVAPP_EVENT_WILL_HTTP_SEEK: case AVAPP_EVENT_DID_HTTP_SEEK: return onInjectOnHttpEvent(mpc, message, data, data_size); default: { return 0; } } } #pragma mark Airplay -(BOOL)allowsMediaAirPlay { if (!self) return NO; return _allowsMediaAirPlay; } -(void)setAllowsMediaAirPlay:(BOOL)b { if (!self) return; _allowsMediaAirPlay = b; } -(BOOL)airPlayMediaActive { if (!self) return NO; if (_isDanmakuMediaAirPlay) { return YES; } return NO; } -(BOOL)isDanmakuMediaAirPlay { return _isDanmakuMediaAirPlay; } -(void)setIsDanmakuMediaAirPlay:(BOOL)isDanmakuMediaAirPlay { _isDanmakuMediaAirPlay = isDanmakuMediaAirPlay; if (_isDanmakuMediaAirPlay) { _glView.scaleFactor = 1.0f; } else { CGFloat scale = [[UIScreen mainScreen] scale]; if (scale < 0.1f) scale = 1.0f; _glView.scaleFactor = scale; } [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification object:nil userInfo:nil]; } #pragma mark Option Conventionce - (void)setFormatOptionValue:(NSString *)value forKey:(NSString *)key { [self setOptionValue:value forKey:key ofCategory:kIJKFFOptionCategoryFormat]; } - (void)setCodecOptionValue:(NSString *)value forKey:(NSString *)key { [self setOptionValue:value forKey:key ofCategory:kIJKFFOptionCategoryCodec]; } - (void)setSwsOptionValue:(NSString *)value forKey:(NSString *)key { [self setOptionValue:value forKey:key ofCategory:kIJKFFOptionCategorySws]; } - (void)setPlayerOptionValue:(NSString *)value forKey:(NSString *)key { [self setOptionValue:value forKey:key ofCategory:kIJKFFOptionCategoryPlayer]; } - (void)setFormatOptionIntValue:(int64_t)value forKey:(NSString *)key { [self setOptionIntValue:value forKey:key ofCategory:kIJKFFOptionCategoryFormat]; } - (void)setCodecOptionIntValue:(int64_t)value forKey:(NSString *)key { [self setOptionIntValue:value forKey:key ofCategory:kIJKFFOptionCategoryCodec]; } - (void)setSwsOptionIntValue:(int64_t)value forKey:(NSString *)key { [self setOptionIntValue:value forKey:key ofCategory:kIJKFFOptionCategorySws]; } - (void)setPlayerOptionIntValue:(int64_t)value forKey:(NSString *)key { [self setOptionIntValue:value forKey:key ofCategory:kIJKFFOptionCategoryPlayer]; } - (void)setMaxBufferSize:(int)maxBufferSize { [self setPlayerOptionIntValue:maxBufferSize forKey:@"max-buffer-size"]; } #pragma mark app state changed - (void)registerApplicationObservers { [_notificationManager addObserver:self selector:@selector(audioSessionInterrupt:) name:AVAudioSessionInterruptionNotification object:nil]; [_notificationManager addObserver:self selector:@selector(applicationWillEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil]; [_notificationManager addObserver:self selector:@selector(applicationDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil]; [_notificationManager addObserver:self selector:@selector(applicationWillResignActive) name:UIApplicationWillResignActiveNotification object:nil]; [_notificationManager addObserver:self selector:@selector(applicationDidEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil]; [_notificationManager addObserver:self selector:@selector(applicationWillTerminate) name:UIApplicationWillTerminateNotification object:nil]; } - (void)unregisterApplicationObservers { [_notificationManager removeAllObservers:self]; } - (void)audioSessionInterrupt:(NSNotification *)notification { int reason = [[[notification userInfo] valueForKey:AVAudioSessionInterruptionTypeKey] intValue]; switch (reason) { case AVAudioSessionInterruptionTypeBegan: { NSLog(@"IJKFFMoviePlayerController:audioSessionInterrupt: begin\n"); switch (self.playbackState) { case IJKMPMoviePlaybackStatePaused: case IJKMPMoviePlaybackStateStopped: _playingBeforeInterruption = NO; break; default: _playingBeforeInterruption = YES; break; } [self pause]; [[IJKAudioKit sharedInstance] setActive:NO]; break; } case AVAudioSessionInterruptionTypeEnded: { NSLog(@"IJKFFMoviePlayerController:audioSessionInterrupt: end\n"); [[IJKAudioKit sharedInstance] setActive:YES]; if (_playingBeforeInterruption) { [self play]; } break; } } } - (void)applicationWillEnterForeground { NSLog(@"IJKFFMoviePlayerController:applicationWillEnterForeground: %d", (int)[UIApplication sharedApplication].applicationState); } - (void)applicationDidBecomeActive { NSLog(@"IJKFFMoviePlayerController:applicationDidBecomeActive: %d", (int)[UIApplication sharedApplication].applicationState); } - (void)applicationWillResignActive { NSLog(@"IJKFFMoviePlayerController:applicationWillResignActive: %d", (int)[UIApplication sharedApplication].applicationState); dispatch_async(dispatch_get_main_queue(), ^{ if (_pauseInBackground) { [self pause]; } }); } - (void)applicationDidEnterBackground { NSLog(@"IJKFFMoviePlayerController:applicationDidEnterBackground: %d", (int)[UIApplication sharedApplication].applicationState); dispatch_async(dispatch_get_main_queue(), ^{ if (_pauseInBackground) { [self pause]; } }); } - (void)applicationWillTerminate { NSLog(@"IJKFFMoviePlayerController:applicationWillTerminate: %d", (int)[UIApplication sharedApplication].applicationState); dispatch_async(dispatch_get_main_queue(), ^{ if (_pauseInBackground) { [self pause]; } }); } #pragma mark IJKFFHudController - (void)setHudValue:(NSString *)value forKey:(NSString *)key { if ([[NSThread currentThread] isMainThread]) { [_hudViewController setHudValue:value forKey:key]; } else { dispatch_async(dispatch_get_main_queue(), ^{ [self setHudValue:value forKey:key]; }); } } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerDef.h ================================================ /* * IJKFFMoviePlayerDef.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import #include "ijkplayer/ios/ijkplayer_ios.h" #include "ijkplayer/ijkmeta.h" struct IJKSize { NSInteger width; NSInteger height; }; typedef struct IJKSize IJKSize; CG_INLINE IJKSize IJKSizeMake(NSInteger width, NSInteger height) { IJKSize size; size.width = width; size.height = height; return size; } struct IJKSampleAspectRatio { NSInteger numerator; NSInteger denominator; }; typedef struct IJKSampleAspectRatio IJKSampleAspectRatio; CG_INLINE IJKSampleAspectRatio IJKSampleAspectRatioMake(NSInteger numerator, NSInteger denominator) { IJKSampleAspectRatio sampleAspectRatio; sampleAspectRatio.numerator = numerator; sampleAspectRatio.denominator = denominator; return sampleAspectRatio; } @interface IJKFFMoviePlayerMessage : NSObject { @public AVMessage _msg; } @end @interface IJKFFMoviePlayerMessagePool : NSObject - (IJKFFMoviePlayerMessagePool *)init; - (IJKFFMoviePlayerMessage *) obtain; - (void) recycle:(IJKFFMoviePlayerMessage *)msg; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFMoviePlayerDef.m ================================================ /* * IJKFFMoviePlayerDef.m * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKFFMoviePlayerDef.h" @implementation IJKFFMoviePlayerMessage @end @implementation IJKFFMoviePlayerMessagePool{ NSMutableArray *_array; } - (IJKFFMoviePlayerMessagePool *)init { self = [super init]; if (self) { _array = [[NSMutableArray alloc] init]; } return self; } - (IJKFFMoviePlayerMessage *) obtain { IJKFFMoviePlayerMessage *msg = nil; @synchronized(self) { NSUInteger count = [_array count]; if (count > 0) { msg = [_array objectAtIndex:count - 1]; [_array removeLastObject]; } } if (!msg) msg = [[IJKFFMoviePlayerMessage alloc] init]; return msg; } - (void) recycle:(IJKFFMoviePlayerMessage *)msg { if (!msg) return; msg_free_res(&msg->_msg); @synchronized(self) { if ([_array count] <= 10) [_array addObject:msg]; } } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFOptions.h ================================================ /* * IJKFFOptions.h * * Copyright (c) 2013-2015 Bilibili * Copyright (c) 2013-2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import typedef enum IJKFFOptionCategory { kIJKFFOptionCategoryFormat = 1, kIJKFFOptionCategoryCodec = 2, kIJKFFOptionCategorySws = 3, kIJKFFOptionCategoryPlayer = 4, kIJKFFOptionCategorySwr = 5, } IJKFFOptionCategory; // for codec option 'skip_loop_filter' and 'skip_frame' typedef enum IJKAVDiscard { /* We leave some space between them for extensions (drop some * keyframes for intra-only or drop just some bidir frames). */ IJK_AVDISCARD_NONE =-16, ///< discard nothing IJK_AVDISCARD_DEFAULT = 0, ///< discard useless packets like 0 size packets in avi IJK_AVDISCARD_NONREF = 8, ///< discard all non reference IJK_AVDISCARD_BIDIR = 16, ///< discard all bidirectional frames IJK_AVDISCARD_NONKEY = 32, ///< discard all frames except keyframes IJK_AVDISCARD_ALL = 48, ///< discard all } IJKAVDiscard; struct IjkMediaPlayer; @interface IJKFFOptions : NSObject +(IJKFFOptions *)optionsByDefault; -(void)applyTo:(struct IjkMediaPlayer *)mediaPlayer; - (void)setOptionValue:(NSString *)value forKey:(NSString *)key ofCategory:(IJKFFOptionCategory)category; - (void)setOptionIntValue:(int64_t)value forKey:(NSString *)key ofCategory:(IJKFFOptionCategory)category; -(void)setFormatOptionValue: (NSString *)value forKey:(NSString *)key; -(void)setCodecOptionValue: (NSString *)value forKey:(NSString *)key; -(void)setSwsOptionValue: (NSString *)value forKey:(NSString *)key; -(void)setPlayerOptionValue: (NSString *)value forKey:(NSString *)key; -(void)setFormatOptionIntValue: (int64_t)value forKey:(NSString *)key; -(void)setCodecOptionIntValue: (int64_t)value forKey:(NSString *)key; -(void)setSwsOptionIntValue: (int64_t)value forKey:(NSString *)key; -(void)setPlayerOptionIntValue: (int64_t)value forKey:(NSString *)key; @property(nonatomic) BOOL showHudView; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKFFOptions.m ================================================ /* * IJKFFOptions.m * * Copyright (c) 2013-2015 Bilibili * Copyright (c) 2013-2015 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKFFOptions.h" #include "ijkplayer/ios/ijkplayer_ios.h" @implementation IJKFFOptions { NSMutableDictionary *_optionCategories; NSMutableDictionary *_playerOptions; NSMutableDictionary *_formatOptions; NSMutableDictionary *_codecOptions; NSMutableDictionary *_swsOptions; NSMutableDictionary *_swrOptions; } + (IJKFFOptions *)optionsByDefault { IJKFFOptions *options = [[IJKFFOptions alloc] init]; [options setPlayerOptionIntValue:30 forKey:@"max-fps"]; [options setPlayerOptionIntValue:0 forKey:@"framedrop"]; [options setPlayerOptionIntValue:3 forKey:@"video-pictq-size"]; [options setPlayerOptionIntValue:0 forKey:@"videotoolbox"]; [options setPlayerOptionIntValue:960 forKey:@"videotoolbox-max-frame-width"]; [options setFormatOptionIntValue:0 forKey:@"auto_convert"]; [options setFormatOptionIntValue:1 forKey:@"reconnect"]; [options setFormatOptionIntValue:30 * 1000 * 1000 forKey:@"timeout"]; [options setFormatOptionValue:@"ijkplayer" forKey:@"user-agent"]; options.showHudView = NO; return options; } - (id)init { self = [super init]; if (self) { _playerOptions = [[NSMutableDictionary alloc] init]; _formatOptions = [[NSMutableDictionary alloc] init]; _codecOptions = [[NSMutableDictionary alloc] init]; _swsOptions = [[NSMutableDictionary alloc] init]; _swrOptions = [[NSMutableDictionary alloc] init]; _optionCategories = [[NSMutableDictionary alloc] init]; _optionCategories[@(IJKMP_OPT_CATEGORY_PLAYER)] = _playerOptions; _optionCategories[@(IJKMP_OPT_CATEGORY_FORMAT)] = _formatOptions; _optionCategories[@(IJKMP_OPT_CATEGORY_CODEC)] = _codecOptions; _optionCategories[@(IJKMP_OPT_CATEGORY_SWS)] = _swsOptions; _optionCategories[@(IJKMP_OPT_CATEGORY_SWR)] = _swrOptions; } return self; } - (void)applyTo:(IjkMediaPlayer *)mediaPlayer { [_optionCategories enumerateKeysAndObjectsUsingBlock:^(id categoryKey, id categoryDict, BOOL *stopOuter) { [categoryDict enumerateKeysAndObjectsUsingBlock:^(id optKey, id optValue, BOOL *stop) { if ([optValue isKindOfClass:[NSNumber class]]) { ijkmp_set_option_int(mediaPlayer, (int)[categoryKey integerValue], [optKey UTF8String], [optValue longLongValue]); } else if ([optValue isKindOfClass:[NSString class]]) { ijkmp_set_option(mediaPlayer, (int)[categoryKey integerValue], [optKey UTF8String], [optValue UTF8String]); } }]; }]; } - (void)setOptionValue:(NSString *)value forKey:(NSString *)key ofCategory:(IJKFFOptionCategory)category { if (!key) return; NSMutableDictionary *options = [_optionCategories objectForKey:@(category)]; if (options) { if (value) { [options setObject:value forKey:key]; } else { [options removeObjectForKey:key]; } } } - (void)setOptionIntValue:(int64_t)value forKey:(NSString *)key ofCategory:(IJKFFOptionCategory)category { if (!key) return; NSMutableDictionary *options = [_optionCategories objectForKey:@(category)]; if (options) { [options setObject:@(value) forKey:key]; } } #pragma mark Common Helper -(void)setFormatOptionValue:(NSString *)value forKey:(NSString *)key { [self setOptionValue:value forKey:key ofCategory:kIJKFFOptionCategoryFormat]; } -(void)setCodecOptionValue:(NSString *)value forKey:(NSString *)key { [self setOptionValue:value forKey:key ofCategory:kIJKFFOptionCategoryCodec]; } -(void)setSwsOptionValue:(NSString *)value forKey:(NSString *)key { [self setOptionValue:value forKey:key ofCategory:kIJKFFOptionCategorySws]; } -(void)setPlayerOptionValue:(NSString *)value forKey:(NSString *)key { [self setOptionValue:value forKey:key ofCategory:kIJKFFOptionCategoryPlayer]; } -(void)setFormatOptionIntValue:(int64_t)value forKey:(NSString *)key { [self setOptionIntValue:value forKey:key ofCategory:kIJKFFOptionCategoryFormat]; } -(void)setCodecOptionIntValue:(int64_t)value forKey:(NSString *)key { [self setOptionIntValue:value forKey:key ofCategory:kIJKFFOptionCategoryCodec]; } -(void)setSwsOptionIntValue:(int64_t)value forKey:(NSString *)key { [self setOptionIntValue:value forKey:key ofCategory:kIJKFFOptionCategorySws]; } -(void)setPlayerOptionIntValue:(int64_t)value forKey:(NSString *)key { [self setOptionIntValue:value forKey:key ofCategory:kIJKFFOptionCategoryPlayer]; } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKKVOController.h ================================================ /* * IJKKVOController.h * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import @interface IJKKVOController : NSObject - (id)initWithTarget:(NSObject *)target; - (void)safelyAddObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context; - (void)safelyRemoveObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath; - (void)safelyRemoveAllObservers; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKKVOController.m ================================================ /* * IJKKVOController.m * * Copyright (c) 2014 Bilibili * Copyright (c) 2014 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKKVOController.h" @interface IJKKVOEntry : NSObject @property(nonatomic, weak) NSObject *observer; @property(nonatomic, strong) NSString *keyPath; @end @implementation IJKKVOEntry @synthesize observer; @synthesize keyPath; @end @implementation IJKKVOController { __weak NSObject *_target; NSMutableArray *_observerArray; } - (id)initWithTarget:(NSObject *)target { self = [super init]; if (self) { _target = target; _observerArray = [[NSMutableArray alloc] init]; } return self; } - (void)safelyAddObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context { NSObject *target = _target; if (target == nil) return; BOOL removed = [self removeEntryOfObserver:observer forKeyPath:keyPath]; if (removed) { // duplicated register NSLog(@"duplicated observer"); } @try { [target addObserver:observer forKeyPath:keyPath options:options context:context]; IJKKVOEntry *entry = [[IJKKVOEntry alloc] init]; entry.observer = observer; entry.keyPath = keyPath; [_observerArray addObject:entry]; } @catch (NSException *e) { NSLog(@"IJKKVO: failed to add observer for %@\n", keyPath); } } - (void)safelyRemoveObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath { NSObject *target = _target; if (target == nil) return; BOOL removed = [self removeEntryOfObserver:observer forKeyPath:keyPath]; if (removed) { // duplicated register NSLog(@"duplicated observer"); } @try { if (removed) { [target removeObserver:observer forKeyPath:keyPath]; } } @catch (NSException *e) { NSLog(@"IJKKVO: failed to remove observer for %@\n", keyPath); } } - (void)safelyRemoveAllObservers { __block NSObject *target = _target; if (target == nil) return; [_observerArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { IJKKVOEntry *entry = obj; if (entry == nil) return; NSObject *observer = entry.observer; if (observer == nil) return; @try { [target removeObserver:observer forKeyPath:entry.keyPath]; } @catch (NSException *e) { NSLog(@"IJKKVO: failed to remove observer for %@\n", entry.keyPath); } }]; [_observerArray removeAllObjects]; } - (BOOL)removeEntryOfObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath { __block NSInteger foundIndex = -1; [_observerArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { IJKKVOEntry *entry = (IJKKVOEntry *)obj; if (entry.observer == observer && [entry.keyPath isEqualToString:keyPath]) { foundIndex = idx; *stop = YES; } }]; if (foundIndex >= 0) { [_observerArray removeObjectAtIndex:foundIndex]; return YES; } return NO; } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKMPMoviePlayerController.h ================================================ /* * IJKMPMoviePlayerController.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKMediaPlayback.h" #import @interface IJKMPMoviePlayerController : MPMoviePlayerController - (id)initWithContentURL:(NSURL *)aUrl; - (id)initWithContentURLString:(NSString *)aUrl; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKMPMoviePlayerController.m ================================================ /* * IJKMPMoviePlayerController.m * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKMPMoviePlayerController.h" #import "IJKAudioKit.h" #import "IJKNotificationManager.h" @implementation IJKMPMoviePlayerController { IJKNotificationManager *_notificationManager; } @dynamic view; @dynamic currentPlaybackTime; @dynamic duration; @dynamic playableDuration; @synthesize bufferingProgress = _bufferingProgress; @dynamic isPreparedToPlay; @dynamic playbackState; @dynamic loadState; @dynamic naturalSize; @dynamic scalingMode; @dynamic shouldAutoplay; @synthesize isDanmakuMediaAirPlay = _isDanmakuMediaAirPlay; @synthesize numberOfBytesTransferred = _numberOfBytesTransferred; - (id)initWithContentURL:(NSURL *)aUrl { self = [super initWithContentURL:aUrl]; if (self) { self.scalingMode = MPMovieScalingModeAspectFit; self.shouldAutoplay = YES; _notificationManager = [[IJKNotificationManager alloc] init]; [self IJK_installMovieNotificationObservers]; [[IJKAudioKit sharedInstance] setupAudioSession]; _bufferingProgress = -1; } return self; } - (id)initWithContentURLString:(NSString *)aUrl { NSURL *url; if ([aUrl rangeOfString:@"/"].location == 0) { //本地 url = [NSURL fileURLWithPath:aUrl]; } else { url = [NSURL URLWithString:aUrl]; } self = [self initWithContentURL:url]; if (self) { } return self; } - (void)dealloc { [self IJK_removeMovieNotificationObservers]; } - (BOOL)isPlaying { switch (self.playbackState) { case MPMoviePlaybackStatePlaying: return YES; default: return NO; } } - (void)shutdown { // do nothing } -(int64_t)numberOfBytesTransferred { NSArray *events = self.accessLog.events; if (events.count>0) { MPMovieAccessLogEvent *currentEvent = [events objectAtIndex:events.count -1]; return currentEvent.numberOfBytesTransferred; } return 0; } - (UIImage *)thumbnailImageAtCurrentTime { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" return [super thumbnailImageAtTime:self.currentPlaybackTime timeOption:MPMovieTimeOptionExact]; #pragma clang diagnostic pop } -(BOOL)allowsMediaAirPlay { if (!self) return NO; return [self allowsAirPlay]; } -(void)setAllowsMediaAirPlay:(BOOL)b { if (!self) return; [self setAllowsAirPlay:b]; } -(BOOL)airPlayMediaActive { if (!self) return NO; return self.airPlayVideoActive || self.isDanmakuMediaAirPlay; } -(BOOL)isDanmakuMediaAirPlay { return _isDanmakuMediaAirPlay; } -(void)setIsDanmakuMediaAirPlay:(BOOL)isDanmakuMediaAirPlay { _isDanmakuMediaAirPlay = isDanmakuMediaAirPlay; [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification object:nil userInfo:nil]; } -(void)setPlaybackRate:(float)playbackRate { NSLog(@"[MPMoviePlayerController setPlaybackRate] is not supported\n"); } -(float)playbackRate { return 1.0f; } -(void)setPlaybackVolume:(float)playbackVolume { NSLog(@"[MPMoviePlayerController setPlaybackVolume] is not supported\n"); } -(float)playbackVolume { return 1.0f; } #pragma mark Movie Notification Handlers /* Register observers for the various movie object notifications. */ -(void)IJK_installMovieNotificationObservers { [_notificationManager addObserver:self selector:@selector(IJK_dispatchMPMediaPlaybackIsPreparedToPlayDidChangeNotification:) name:MPMediaPlaybackIsPreparedToPlayDidChangeNotification object:self]; [_notificationManager addObserver:self selector:@selector(IJK_dispatchMPMoviePlayerLoadStateDidChangeNotification:) name:MPMoviePlayerLoadStateDidChangeNotification object:self]; [_notificationManager addObserver:self selector:@selector(IJK_dispatchMPMoviePlayerPlaybackDidFinishNotification:) name:MPMoviePlayerPlaybackDidFinishNotification object:self]; [_notificationManager addObserver:self selector:@selector(IJK_dispatchMPMoviePlayerPlaybackStateDidChangeNotification:) name:MPMoviePlayerPlaybackStateDidChangeNotification object:self]; [_notificationManager addObserver:self selector:@selector(IJK_dispatchMoviePlayerIsAirPlayVideoActiveDidChangeNotification:) name:MPMoviePlayerIsAirPlayVideoActiveDidChangeNotification object:self]; [_notificationManager addObserver:self selector:@selector(IJK_dispatchMoviePlayerNaturalSizeAvailableNotification:) name:MPMovieNaturalSizeAvailableNotification object:self]; } - (void)IJK_removeMovieNotificationObservers { [_notificationManager removeAllObservers:self]; } - (void)IJK_dispatchMPMediaPlaybackIsPreparedToPlayDidChangeNotification:(NSNotification*)notification { [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification object:notification.object userInfo:notification.userInfo]; } - (void)IJK_dispatchMPMoviePlayerLoadStateDidChangeNotification:(NSNotification*)notification { [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerLoadStateDidChangeNotification object:notification.object userInfo:notification.userInfo]; } - (void)IJK_dispatchMPMoviePlayerPlaybackDidFinishNotification:(NSNotification*)notification { [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerPlaybackDidFinishNotification object:notification.object userInfo:notification.userInfo]; } - (void)IJK_dispatchMPMoviePlayerPlaybackStateDidChangeNotification:(NSNotification*)notification { [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerPlaybackStateDidChangeNotification object:notification.object userInfo:notification.userInfo]; } - (void)IJK_dispatchMoviePlayerIsAirPlayVideoActiveDidChangeNotification:(NSNotification*)notification { [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification object:notification.object userInfo:notification.userInfo]; } - (void)IJK_dispatchMoviePlayerNaturalSizeAvailableNotification:(NSNotification*)notification { [[NSNotificationCenter defaultCenter] postNotificationName:IJKMPMovieNaturalSizeAvailableNotification object:notification.object userInfo:notification.userInfo]; } - (void)setPauseInBackground:(BOOL)pause { //mpPlayer还未找到方法实现 } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaModule.h ================================================ /* * IJKMediaModule.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import @interface IJKMediaModule : NSObject + (IJKMediaModule *)sharedModule; @property(atomic, getter=isAppIdleTimerDisabled) BOOL appIdleTimerDisabled; @property(atomic, getter=isMediaModuleIdleTimerDisabled) BOOL mediaModuleIdleTimerDisabled; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaModule.m ================================================ /* * IJKMediaModule.m * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKMediaModule.h" #import @implementation IJKMediaModule @synthesize appIdleTimerDisabled = _appIdleTimerDisabled; @synthesize mediaModuleIdleTimerDisabled = _mediaModuleIdleTimerDisabled; + (IJKMediaModule *)sharedModule { static IJKMediaModule *obj = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ obj = [[IJKMediaModule alloc] init]; }); return obj; } - (void)setAppIdleTimerDisabled:(BOOL) idleTimerDisabled { _appIdleTimerDisabled = idleTimerDisabled; [self updateIdleTimer]; } - (BOOL)isAppIdleTimerDisabled { return _appIdleTimerDisabled; } - (void)setMediaModuleIdleTimerDisabled:(BOOL) idleTimerDisabled { _mediaModuleIdleTimerDisabled = idleTimerDisabled; [self updateIdleTimer]; } - (BOOL)isMediaModuleIdleTimerDisabled { return _mediaModuleIdleTimerDisabled; } - (void)updateIdleTimer { if (self.appIdleTimerDisabled || self.mediaModuleIdleTimerDisabled) { [UIApplication sharedApplication].idleTimerDisabled = YES; } else { [UIApplication sharedApplication].idleTimerDisabled = NO; } } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.h ================================================ /* * IJKMediaPlayback.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import #import typedef NS_ENUM(NSInteger, IJKMPMovieScalingMode) { IJKMPMovieScalingModeNone, // No scaling IJKMPMovieScalingModeAspectFit, // Uniform scale until one dimension fits IJKMPMovieScalingModeAspectFill, // Uniform scale until the movie fills the visible bounds. One dimension may have clipped contents IJKMPMovieScalingModeFill // Non-uniform scale. Both render dimensions will exactly match the visible bounds }; typedef NS_ENUM(NSInteger, IJKMPMoviePlaybackState) { IJKMPMoviePlaybackStateStopped, IJKMPMoviePlaybackStatePlaying, IJKMPMoviePlaybackStatePaused, IJKMPMoviePlaybackStateInterrupted, IJKMPMoviePlaybackStateSeekingForward, IJKMPMoviePlaybackStateSeekingBackward }; typedef NS_OPTIONS(NSUInteger, IJKMPMovieLoadState) { IJKMPMovieLoadStateUnknown = 0, IJKMPMovieLoadStatePlayable = 1 << 0, IJKMPMovieLoadStatePlaythroughOK = 1 << 1, // Playback will be automatically started in this state when shouldAutoplay is YES IJKMPMovieLoadStateStalled = 1 << 2, // Playback will be automatically paused in this state, if started }; typedef NS_ENUM(NSInteger, IJKMPMovieFinishReason) { IJKMPMovieFinishReasonPlaybackEnded, IJKMPMovieFinishReasonPlaybackError, IJKMPMovieFinishReasonUserExited }; // ----------------------------------------------------------------------------- // Thumbnails typedef NS_ENUM(NSInteger, IJKMPMovieTimeOption) { IJKMPMovieTimeOptionNearestKeyFrame, IJKMPMovieTimeOptionExact }; @protocol IJKMediaPlayback; #pragma mark IJKMediaPlayback @protocol IJKMediaPlayback - (void)prepareToPlay; - (void)play; - (void)pause; - (void)stop; - (BOOL)isPlaying; - (void)shutdown; - (void)setPauseInBackground:(BOOL)pause; @property(nonatomic, readonly) UIView *view; @property(nonatomic) NSTimeInterval currentPlaybackTime; @property(nonatomic, readonly) NSTimeInterval duration; @property(nonatomic, readonly) NSTimeInterval playableDuration; @property(nonatomic, readonly) NSInteger bufferingProgress; @property(nonatomic, readonly) BOOL isPreparedToPlay; @property(nonatomic, readonly) IJKMPMoviePlaybackState playbackState; @property(nonatomic, readonly) IJKMPMovieLoadState loadState; @property(nonatomic, readonly) int isSeekBuffering; @property(nonatomic, readonly) int isAudioSync; @property(nonatomic, readonly) int isVideoSync; @property(nonatomic, readonly) int64_t numberOfBytesTransferred; @property(nonatomic, readonly) CGSize naturalSize; @property(nonatomic) IJKMPMovieScalingMode scalingMode; @property(nonatomic) BOOL shouldAutoplay; @property (nonatomic) BOOL allowsMediaAirPlay; @property (nonatomic) BOOL isDanmakuMediaAirPlay; @property (nonatomic, readonly) BOOL airPlayMediaActive; @property (nonatomic) float playbackRate; @property (nonatomic) float playbackVolume; - (UIImage *)thumbnailImageAtCurrentTime; #pragma mark Notifications #ifdef __cplusplus #define IJK_EXTERN extern "C" __attribute__((visibility ("default"))) #else #define IJK_EXTERN extern __attribute__((visibility ("default"))) #endif // ----------------------------------------------------------------------------- // MPMediaPlayback.h // Posted when the prepared state changes of an object conforming to the MPMediaPlayback protocol changes. // This supersedes MPMoviePlayerContentPreloadDidFinishNotification. IJK_EXTERN NSString *const IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification; // ----------------------------------------------------------------------------- // MPMoviePlayerController.h // Movie Player Notifications // Posted when the scaling mode changes. IJK_EXTERN NSString* const IJKMPMoviePlayerScalingModeDidChangeNotification; // Posted when movie playback ends or a user exits playback. IJK_EXTERN NSString* const IJKMPMoviePlayerPlaybackDidFinishNotification; IJK_EXTERN NSString* const IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey; // NSNumber (IJKMPMovieFinishReason) // Posted when the playback state changes, either programatically or by the user. IJK_EXTERN NSString* const IJKMPMoviePlayerPlaybackStateDidChangeNotification; // Posted when the network load state changes. IJK_EXTERN NSString* const IJKMPMoviePlayerLoadStateDidChangeNotification; // Posted when the movie player begins or ends playing video via AirPlay. IJK_EXTERN NSString* const IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification; // ----------------------------------------------------------------------------- // Movie Property Notifications // Calling -prepareToPlay on the movie player will begin determining movie properties asynchronously. // These notifications are posted when the associated movie property becomes available. IJK_EXTERN NSString* const IJKMPMovieNaturalSizeAvailableNotification; // ----------------------------------------------------------------------------- // Extend Notifications IJK_EXTERN NSString *const IJKMPMoviePlayerVideoDecoderOpenNotification; IJK_EXTERN NSString *const IJKMPMoviePlayerFirstVideoFrameRenderedNotification; IJK_EXTERN NSString *const IJKMPMoviePlayerFirstAudioFrameRenderedNotification; IJK_EXTERN NSString *const IJKMPMoviePlayerFirstAudioFrameDecodedNotification; IJK_EXTERN NSString *const IJKMPMoviePlayerFirstVideoFrameDecodedNotification; IJK_EXTERN NSString *const IJKMPMoviePlayerOpenInputNotification; IJK_EXTERN NSString *const IJKMPMoviePlayerFindStreamInfoNotification; IJK_EXTERN NSString *const IJKMPMoviePlayerComponentOpenNotification; IJK_EXTERN NSString *const IJKMPMoviePlayerDidSeekCompleteNotification; IJK_EXTERN NSString *const IJKMPMoviePlayerDidSeekCompleteTargetKey; IJK_EXTERN NSString *const IJKMPMoviePlayerDidSeekCompleteErrorKey; IJK_EXTERN NSString *const IJKMPMoviePlayerDidAccurateSeekCompleteCurPos; IJK_EXTERN NSString *const IJKMPMoviePlayerAccurateSeekCompleteNotification; IJK_EXTERN NSString *const IJKMPMoviePlayerSeekAudioStartNotification; IJK_EXTERN NSString *const IJKMPMoviePlayerSeekVideoStartNotification; @end #pragma mark IJKMediaUrlOpenDelegate // Must equal to the defination in ijkavformat/ijkavformat.h typedef NS_ENUM(NSInteger, IJKMediaEvent) { // Notify Events IJKMediaEvent_WillHttpOpen = 1, // attr: url IJKMediaEvent_DidHttpOpen = 2, // attr: url, error, http_code IJKMediaEvent_WillHttpSeek = 3, // attr: url, offset IJKMediaEvent_DidHttpSeek = 4, // attr: url, offset, error, http_code // Control Message IJKMediaCtrl_WillTcpOpen = 0x20001, // IJKMediaUrlOpenData: no args IJKMediaCtrl_DidTcpOpen = 0x20002, // IJKMediaUrlOpenData: error, family, ip, port, fd IJKMediaCtrl_WillHttpOpen = 0x20003, // IJKMediaUrlOpenData: url, segmentIndex, retryCounter IJKMediaCtrl_WillLiveOpen = 0x20005, // IJKMediaUrlOpenData: url, retryCounter IJKMediaCtrl_WillConcatSegmentOpen = 0x20007, // IJKMediaUrlOpenData: url, segmentIndex, retryCounter }; #define IJKMediaEventAttrKey_url @"url" #define IJKMediaEventAttrKey_host @"host" #define IJKMediaEventAttrKey_error @"error" #define IJKMediaEventAttrKey_time_of_event @"time_of_event" #define IJKMediaEventAttrKey_http_code @"http_code" #define IJKMediaEventAttrKey_offset @"offset" #define IJKMediaEventAttrKey_file_size @"file_size" // event of IJKMediaUrlOpenEvent_xxx @interface IJKMediaUrlOpenData: NSObject - (id)initWithUrl:(NSString *)url event:(IJKMediaEvent)event segmentIndex:(int)segmentIndex retryCounter:(int)retryCounter; @property(nonatomic, readonly) IJKMediaEvent event; @property(nonatomic, readonly) int segmentIndex; @property(nonatomic, readonly) int retryCounter; @property(nonatomic, retain) NSString *url; @property(nonatomic, assign) int fd; @property(nonatomic, strong) NSString *msg; @property(nonatomic) int error; // set a negative value to indicate an error has occured. @property(nonatomic, getter=isHandled) BOOL handled; // auto set to YES if url changed @property(nonatomic, getter=isUrlChanged) BOOL urlChanged; // auto set to YES by url changed @end @protocol IJKMediaUrlOpenDelegate - (void)willOpenUrl:(IJKMediaUrlOpenData*) urlOpenData; @end @protocol IJKMediaNativeInvokeDelegate - (int)invoke:(IJKMediaEvent)event attributes:(NSDictionary *)attributes; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayback.m ================================================ /* * IJKMediaPlayback.m * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKMediaPlayback.h" NSString *const IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification = @"IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification"; NSString *const IJKMPMoviePlayerPlaybackDidFinishNotification = @"IJKMPMoviePlayerPlaybackDidFinishNotification"; NSString *const IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey = @"IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey"; NSString *const IJKMPMoviePlayerPlaybackStateDidChangeNotification = @"IJKMPMoviePlayerPlaybackStateDidChangeNotification"; NSString *const IJKMPMoviePlayerLoadStateDidChangeNotification = @"IJKMPMoviePlayerLoadStateDidChangeNotification"; NSString *const IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification = @"IJKMPMoviePlayerIsAirPlayVideoActiveDidChangeNotification"; NSString *const IJKMPMovieNaturalSizeAvailableNotification = @"IJKMPMovieNaturalSizeAvailableNotification"; NSString *const IJKMPMoviePlayerVideoDecoderOpenNotification = @"IJKMPMoviePlayerVideoDecoderOpenNotification"; NSString *const IJKMPMoviePlayerFirstVideoFrameRenderedNotification = @"IJKMPMoviePlayerFirstVideoFrameRenderedNotification"; NSString *const IJKMPMoviePlayerFirstAudioFrameRenderedNotification = @"IJKMPMoviePlayerFirstAudioFrameRenderedNotification"; NSString *const IJKMPMoviePlayerFirstAudioFrameDecodedNotification = @"IJKMPMoviePlayerFirstAudioFrameDecodedNotification"; NSString *const IJKMPMoviePlayerFirstVideoFrameDecodedNotification = @"IJKMPMoviePlayerFirstVideoFrameDecodedNotification"; NSString *const IJKMPMoviePlayerOpenInputNotification = @"IJKMPMoviePlayerOpenInputNotification"; NSString *const IJKMPMoviePlayerFindStreamInfoNotification = @"IJKMPMoviePlayerFindStreamInfoNotification"; NSString *const IJKMPMoviePlayerComponentOpenNotification = @"IJKMPMoviePlayerComponentOpenNotification"; NSString *const IJKMPMoviePlayerAccurateSeekCompleteNotification = @"IJKMPMoviePlayerAccurateSeekCompleteNotification"; NSString *const IJKMPMoviePlayerDidSeekCompleteNotification = @"IJKMPMoviePlayerDidSeekCompleteNotification"; NSString *const IJKMPMoviePlayerDidSeekCompleteTargetKey = @"IJKMPMoviePlayerDidSeekCompleteTargetKey"; NSString *const IJKMPMoviePlayerDidSeekCompleteErrorKey = @"IJKMPMoviePlayerDidSeekCompleteErrorKey"; NSString *const IJKMPMoviePlayerDidAccurateSeekCompleteCurPos = @"IJKMPMoviePlayerDidAccurateSeekCompleteCurPos"; NSString *const IJKMPMoviePlayerSeekAudioStartNotification = @"IJKMPMoviePlayerSeekAudioStartNotification"; NSString *const IJKMPMoviePlayerSeekVideoStartNotification = @"IJKMPMoviePlayerSeekVideoStartNotification"; @implementation IJKMediaUrlOpenData { NSString *_url; BOOL _handled; BOOL _urlChanged; } - (id)initWithUrl:(NSString *)url event:(IJKMediaEvent)event segmentIndex:(int)segmentIndex retryCounter:(int)retryCounter { self = [super init]; if (self) { self->_url = url; self->_event = event; self->_segmentIndex = segmentIndex; self->_retryCounter = retryCounter; self->_error = 0; self->_handled = NO; self->_urlChanged = NO; } return self; } - (void)setHandled:(BOOL)handled { _handled = handled; } - (BOOL)isHandled { return _handled; } - (BOOL)isUrlChanged { return _urlChanged; } - (NSString *)url { return _url; } - (void)setUrl:(NSString *)url { assert(url); _handled = YES; if (![self.url isEqualToString:url]) { _urlChanged = YES; _url = url; } } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayer-Prefix.pch ================================================ // // Prefix header for all source files of the 'IJKMediaPlayer' target in the 'IJKMediaPlayer' project // #ifdef __OBJC__ #import #import #import #import #import #import #import #import #import #endif ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaPlayer.h ================================================ /* * IJKMediaPlayer.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKMediaPlayback.h" #import "IJKMPMoviePlayerController.h" #import "IJKFFOptions.h" #import "IJKFFMoviePlayerController.h" #import "IJKAVMoviePlayerController.h" #import "IJKMediaModule.h" ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaUtils.h ================================================ /* * IJKMediaUtils.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import @interface IJKMediaUtils : NSObject + (NSError*)createErrorWithDomain: (NSString*)domain code: (NSInteger)code description: (NSString*)description reason: (NSString*)reason; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKMediaUtils.m ================================================ /* * IJKMediaUtils.m * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKMediaUtils.h" @implementation IJKMediaUtils + (NSError*)createErrorWithDomain: (NSString*)domain code: (NSInteger)code description: (NSString*)description reason: (NSString*)reason { /* Generate an error describing the failure. */ if (description == nil) description = @""; if (reason == nil) reason = @""; NSString *localizedDescription = NSLocalizedString(description, description); NSString *localizedFailureReason = NSLocalizedString(reason, reason); NSDictionary *errorDict = [NSDictionary dictionaryWithObjectsAndKeys: localizedDescription, NSLocalizedDescriptionKey, localizedFailureReason, NSLocalizedFailureReasonErrorKey, nil]; NSError *error = [NSError errorWithDomain:domain code:0 userInfo:errorDict]; return error; } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKNotificationManager.h ================================================ /* * IJKNotificationManager.h * * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import @interface IJKNotificationManager : NSObject - (nullable instancetype)init; - (void)addObserver:(nonnull id)observer selector:(nonnull SEL)aSelector name:(nullable NSString *)aName object:(nullable id)anObject; - (void)removeAllObservers:(nonnull id)observer; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKNotificationManager.m ================================================ /* * IJKNotificationManager.m * * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKNotificationManager.h" @implementation IJKNotificationManager { NSMutableDictionary *_registeredNotifications; } - (instancetype)init { self = [super init]; if (self) { _registeredNotifications = [[NSMutableDictionary alloc] init]; } return self; } - (void)addObserver:(nonnull id)observer selector:(nonnull SEL)aSelector name:(nullable NSString *)aName object:(nullable id)anObject { [[NSNotificationCenter defaultCenter] addObserver:observer selector:aSelector name:aName object:anObject]; [_registeredNotifications setValue:aName forKey:aName]; } - (void)removeAllObservers:(nonnull id)observer { for (NSString *name in [_registeredNotifications allKeys]) { [[NSNotificationCenter defaultCenter] removeObserver:observer name:name object:nil]; } } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/IJKSDLGLViewProtocol.h ================================================ /* * IJKSDLGLViewProtocol.h * * Copyright (c) 2017 Bilibili * Copyright (c) 2017 raymond * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKSDLGLViewProtocol_h #define IJKSDLGLViewProtocol_h #import typedef struct IJKOverlay IJKOverlay; struct IJKOverlay { int w; int h; UInt32 format; int planes; UInt16 *pitches; UInt8 **pixels; int sar_num; int sar_den; CVPixelBufferRef pixel_buffer; }; @protocol IJKSDLGLViewProtocol - (UIImage*) snapshot; @property(nonatomic, readonly) CGFloat fps; @property(nonatomic) CGFloat scaleFactor; @property(nonatomic) BOOL isThirdGLView; - (void) display_pixels: (IJKOverlay *) overlay; @end #endif /* IJKSDLGLViewProtocol_h */ ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/NSString+IJKMedia.h ================================================ /* * NSString+IJKMedia.h * * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import @interface NSString (IJKMedia) + (NSString *) ijk_stringBeEmptyIfNil:(NSString *)src; - (BOOL) ijk_isIpv4; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/NSString+IJKMedia.m ================================================ /* * NSString+IJKMedia.m * * Copyright (c) 2016 Bilibili * Copyright (c) 2016 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "NSString+IJKMedia.h" @implementation NSString (IJKMedia) - (BOOL) ijk_isIpv4 { NSString *regexp = @"^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$"; NSRange range = [self rangeOfString:regexp options:NSRegularExpressionSearch]; return range.location != NSNotFound; } + (NSString *) ijk_stringBeEmptyIfNil:(NSString *)src { if (src == nil) return @""; return src; } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/ijkplayer_ios.h ================================================ /* * ijkplayer_ios.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijkplayer/ijkplayer.h" #import "IJKSDLGLView.h" // ref_count is 1 after open IjkMediaPlayer *ijkmp_ios_create(int (*msg_loop)(void*)); void ijkmp_ios_set_glview(IjkMediaPlayer *mp, IJKSDLGLView *glView); bool ijkmp_ios_is_videotoolbox_open(IjkMediaPlayer *mp); ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/ijkplayer_ios.m ================================================ /* * ijkplayer_ios.c * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "ijkplayer_ios.h" #import "ijksdl/ios/ijksdl_ios.h" #include #include #include "ijkplayer/ff_fferror.h" #include "ijkplayer/ff_ffplay.h" #include "ijkplayer/ijkplayer_internal.h" #include "ijkplayer/pipeline/ffpipeline_ffplay.h" #include "pipeline/ffpipeline_ios.h" IjkMediaPlayer *ijkmp_ios_create(int (*msg_loop)(void*)) { IjkMediaPlayer *mp = ijkmp_create(msg_loop); if (!mp) goto fail; mp->ffplayer->vout = SDL_VoutIos_CreateForGLES2(); if (!mp->ffplayer->vout) goto fail; mp->ffplayer->pipeline = ffpipeline_create_from_ios(mp->ffplayer); if (!mp->ffplayer->pipeline) goto fail; return mp; fail: ijkmp_dec_ref_p(&mp); return NULL; } void ijkmp_ios_set_glview_l(IjkMediaPlayer *mp, IJKSDLGLView *glView) { assert(mp); assert(mp->ffplayer); assert(mp->ffplayer->vout); SDL_VoutIos_SetGLView(mp->ffplayer->vout, glView); } void ijkmp_ios_set_glview(IjkMediaPlayer *mp, IJKSDLGLView *glView) { assert(mp); MPTRACE("ijkmp_ios_set_view(glView=%p)\n", (void*)glView); pthread_mutex_lock(&mp->mutex); ijkmp_ios_set_glview_l(mp, glView); pthread_mutex_unlock(&mp->mutex); MPTRACE("ijkmp_ios_set_view(glView=%p)=void\n", (void*)glView); } bool ijkmp_ios_is_videotoolbox_open_l(IjkMediaPlayer *mp) { assert(mp); assert(mp->ffplayer); return false; } bool ijkmp_ios_is_videotoolbox_open(IjkMediaPlayer *mp) { assert(mp); MPTRACE("%s()\n", __func__); pthread_mutex_lock(&mp->mutex); bool ret = ijkmp_ios_is_videotoolbox_open_l(mp); pthread_mutex_unlock(&mp->mutex); MPTRACE("%s()=%d\n", __func__, ret ? 1 : 0); return ret; } ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBox.h ================================================ /***************************************************************************** * IJKVideoToolBox.h ***************************************************************************** * * copyright (c) 2014 Zhou Quan * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKMediaPlayer_videotoolbox_h #define IJKMediaPlayer_videotoolbox_h #include "ff_ffplay.h" typedef struct Ijk_VideoToolBox_Opaque Ijk_VideoToolBox_Opaque; typedef struct Ijk_VideoToolBox Ijk_VideoToolBox; struct Ijk_VideoToolBox { Ijk_VideoToolBox_Opaque *opaque; int (*decode_frame)(Ijk_VideoToolBox_Opaque *opaque); void (*free)(Ijk_VideoToolBox_Opaque *opaque); }; Ijk_VideoToolBox *Ijk_VideoToolbox_Async_Create(FFPlayer* ffp, AVCodecContext* ic); Ijk_VideoToolBox *Ijk_VideoToolbox_Sync_Create(FFPlayer* ffp, AVCodecContext* ic); #endif ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBox.m ================================================ /***************************************************************************** * IJKVideoToolBox.m ***************************************************************************** * * copyright (c) 2014 Zhou Quan * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "IJKVideoToolBox.h" #include "ijksdl/ijksdl_inc_internal.h" #include "IJKVideoToolBoxAsync.h" #include "IJKVideoToolBoxSync.h" inline static Ijk_VideoToolBox *Ijk_VideoToolbox_CreateInternal(int async, FFPlayer* ffp, AVCodecContext* ic) { Ijk_VideoToolBox *vtb = (Ijk_VideoToolBox*) mallocz(sizeof(Ijk_VideoToolBox)); if (!vtb) return NULL; if (async) { vtb->opaque = videotoolbox_async_create(ffp, ic); vtb->decode_frame = videotoolbox_async_decode_frame; vtb->free = videotoolbox_async_free; } else { vtb->opaque = videotoolbox_sync_create(ffp, ic); vtb->decode_frame = videotoolbox_sync_decode_frame; vtb->free = videotoolbox_sync_free; } if (!vtb->opaque) { freep((void **)&vtb); return NULL; } return vtb; } Ijk_VideoToolBox *Ijk_VideoToolbox_Async_Create(FFPlayer* ffp, AVCodecContext* ic) { return Ijk_VideoToolbox_CreateInternal(1, ffp, ic); } Ijk_VideoToolBox *Ijk_VideoToolbox_Sync_Create(FFPlayer* ffp, AVCodecContext* ic) { return Ijk_VideoToolbox_CreateInternal(0, ffp, ic); } ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBoxAsync.h ================================================ /***************************************************************************** * IJKVideoToolBox.h ***************************************************************************** * * copyright (c) 2014 Zhou Quan * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKMediaPlayer_videotoolbox_async_h #define IJKMediaPlayer_videotoolbox_async_h #include "ff_ffplay.h" typedef struct Ijk_VideoToolBox_Opaque Ijk_VideoToolBox_Opaque; Ijk_VideoToolBox_Opaque* videotoolbox_async_create(FFPlayer* ffp, AVCodecContext* ic); int videotoolbox_async_decode_frame(Ijk_VideoToolBox_Opaque* opaque); void videotoolbox_async_free(Ijk_VideoToolBox_Opaque* opaque); #endif ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBoxAsync.m ================================================ /***************************************************************************** * IJKVideoToolBox.m ***************************************************************************** * * copyright (c) 2014 Zhou Quan * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "IJKVideoToolBoxAsync.h" #include "ijksdl_vout_overlay_videotoolbox.h" #include "ffpipeline_ios.h" #include #include "libavformat/avc.h" #include "ijksdl_vout_ios_gles2.h" #include "h264_sps_parser.h" #include "ijkplayer/ff_ffplay_debug.h" #import #import #import #import #import "IJKDeviceModel.h" #include #import #include "ff_ffinc.h" #include "ff_fferror.h" #include "ff_ffmsg.h" #include "ijksdl/ios/ijksdl_vout_overlay_videotoolbox.h" #define IJK_VTB_FCC_AVCC SDL_FOURCC('C', 'c', 'v', 'a') #define MAX_PKT_QUEUE_DEEP 350 #define VTB_MAX_DECODING_SAMPLES 3 typedef struct sample_info { int sample_id; double sort; double dts; double pts; int serial; int sar_num; int sar_den; volatile int is_decoding; } sample_info; typedef struct sort_queue { AVFrame pic; int serial; int64_t sort; volatile struct sort_queue *nextframe; } sort_queue; typedef struct VTBFormatDesc { CMFormatDescriptionRef fmt_desc; int32_t max_ref_frames; bool convert_bytestream; bool convert_3byteTo4byteNALSize; } VTBFormatDesc; struct Ijk_VideoToolBox_Opaque { FFPlayer *ffp; volatile bool refresh_request; volatile bool new_seg_flag; volatile bool idr_based_identified; volatile bool refresh_session; volatile bool recovery_drop_packet; AVCodecParameters *codecpar; VTBFormatDesc fmt_desc; VTDecompressionSessionRef vt_session; pthread_mutex_t m_queue_mutex; volatile sort_queue *m_sort_queue; volatile int32_t m_queue_depth; int serial; bool dealloced; int m_buffer_deep; AVPacket m_buffer_packet[MAX_PKT_QUEUE_DEEP]; SDL_mutex *sample_info_mutex; SDL_cond *sample_info_cond; sample_info sample_info_array[VTB_MAX_DECODING_SAMPLES]; volatile int sample_info_index; volatile int sample_info_id_generator; volatile int sample_infos_in_decoding; SDL_SpeedSampler sampler; }; static void vtbformat_destroy(VTBFormatDesc *fmt_desc); static int vtbformat_init(VTBFormatDesc *fmt_desc, AVCodecParameters *codecpar); static const char *vtb_get_error_string(OSStatus status) { switch (status) { case kVTInvalidSessionErr: return "kVTInvalidSessionErr"; case kVTVideoDecoderBadDataErr: return "kVTVideoDecoderBadDataErr"; case kVTVideoDecoderUnsupportedDataFormatErr: return "kVTVideoDecoderUnsupportedDataFormatErr"; case kVTVideoDecoderMalfunctionErr: return "kVTVideoDecoderMalfunctionErr"; default: return "UNKNOWN"; } } static void SortQueuePop(Ijk_VideoToolBox_Opaque* context) { if (!context->m_sort_queue || context->m_queue_depth == 0) { return; } pthread_mutex_lock(&context->m_queue_mutex); volatile sort_queue *top_frame = context->m_sort_queue; context->m_sort_queue = context->m_sort_queue->nextframe; context->m_queue_depth--; pthread_mutex_unlock(&context->m_queue_mutex); CVBufferRelease(top_frame->pic.opaque); free((void*)top_frame); } static void CFDictionarySetSInt32(CFMutableDictionaryRef dictionary, CFStringRef key, SInt32 numberSInt32) { CFNumberRef number; number = CFNumberCreate(NULL, kCFNumberSInt32Type, &numberSInt32); CFDictionarySetValue(dictionary, key, number); CFRelease(number); } static void CFDictionarySetBoolean(CFMutableDictionaryRef dictionary, CFStringRef key, BOOL value) { CFDictionarySetValue(dictionary, key, value ? kCFBooleanTrue : kCFBooleanFalse); } inline static void sample_info_flush(Ijk_VideoToolBox_Opaque* context, int wait_ms) { int total_wait = 0; SDL_LockMutex(context->sample_info_mutex); while (wait_ms < 0 || total_wait < wait_ms) { if (context->sample_infos_in_decoding <= 0) break; int wait_step = 10; SDL_CondWaitTimeout(context->sample_info_cond, context->sample_info_mutex, wait_step); total_wait += wait_step; } SDL_UnlockMutex(context->sample_info_mutex); } inline static sample_info* sample_info_peek(Ijk_VideoToolBox_Opaque* context) { FFPlayer *ffp = context->ffp; VideoState *is = ffp->is; SDL_LockMutex(context->sample_info_mutex); sample_info *sample_info = &context->sample_info_array[context->sample_info_index]; while (sample_info->is_decoding) { if (is->videoq.abort_request) { sample_info = NULL; goto abort; } SDL_CondWaitTimeout(context->sample_info_cond, context->sample_info_mutex, 10); } abort: SDL_UnlockMutex(context->sample_info_mutex); return sample_info; } inline static void sample_info_push(Ijk_VideoToolBox_Opaque* context) { FFPlayer *ffp = context->ffp; VideoState *is = ffp->is; SDL_LockMutex(context->sample_info_mutex); sample_info *sample_info = &context->sample_info_array[context->sample_info_index]; while (sample_info->is_decoding) { if (is->videoq.abort_request) goto abort; SDL_CondWaitTimeout(context->sample_info_cond, context->sample_info_mutex, 10); } if (sample_info->is_decoding) { ALOGW("%s, reallocate sample in decoding %d -> %d /%d\n", __FUNCTION__, sample_info->sample_id, context->sample_info_id_generator, context->sample_infos_in_decoding); } else { sample_info->is_decoding = 1; context->sample_infos_in_decoding++; } sample_info->sample_id = context->sample_info_id_generator++; context->sample_info_index++; context->sample_info_index %= VTB_MAX_DECODING_SAMPLES; abort: SDL_UnlockMutex(context->sample_info_mutex); } inline static void sample_info_drop_last_push(Ijk_VideoToolBox_Opaque* context) { SDL_LockMutex(context->sample_info_mutex); int last_index = context->sample_info_index + VTB_MAX_DECODING_SAMPLES - 1; last_index %= VTB_MAX_DECODING_SAMPLES; sample_info *sample_info = &context->sample_info_array[last_index]; if (sample_info->is_decoding) { sample_info->is_decoding = 0; context->sample_infos_in_decoding--; } SDL_UnlockMutex(context->sample_info_mutex); } inline static void sample_info_recycle(Ijk_VideoToolBox_Opaque* context, sample_info *sample_info) { SDL_LockMutex(context->sample_info_mutex); if (sample_info->is_decoding) { sample_info->is_decoding = 0; if (context->sample_infos_in_decoding > 0) context->sample_infos_in_decoding--; } else { ALOGW("%s, multiple frames in same sample %d / %d\n", __FUNCTION__, sample_info->sample_id, context->sample_info_id_generator); } SDL_CondSignal(context->sample_info_cond); SDL_UnlockMutex(context->sample_info_mutex); } static CMSampleBufferRef CreateSampleBufferFrom(CMFormatDescriptionRef fmt_desc, void *demux_buff, size_t demux_size) { OSStatus status; CMBlockBufferRef newBBufOut = NULL; CMSampleBufferRef sBufOut = NULL; status = CMBlockBufferCreateWithMemoryBlock( NULL, demux_buff, demux_size, kCFAllocatorNull, NULL, 0, demux_size, FALSE, &newBBufOut); if (!status) { status = CMSampleBufferCreate( NULL, newBBufOut, TRUE, 0, 0, fmt_desc, 1, 0, NULL, 0, NULL, &sBufOut); } if (newBBufOut) CFRelease(newBBufOut); if (status == 0) { return sBufOut; } else { return NULL; } } static bool GetVTBPicture(Ijk_VideoToolBox_Opaque* context, AVFrame* pVTBPicture) { if (context->m_sort_queue == NULL) { return false; } pthread_mutex_lock(&context->m_queue_mutex); volatile sort_queue *sort_queue = context->m_sort_queue; *pVTBPicture = sort_queue->pic; pVTBPicture->opaque = CVBufferRetain(sort_queue->pic.opaque); pthread_mutex_unlock(&context->m_queue_mutex); return true; } static void QueuePicture(Ijk_VideoToolBox_Opaque* ctx) { AVFrame picture = {0}; if (true == GetVTBPicture(ctx, &picture)) { AVRational tb = ctx->ffp->is->video_st->time_base; AVRational frame_rate = av_guess_frame_rate(ctx->ffp->is->ic, ctx->ffp->is->video_st, NULL); double duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational) {frame_rate.den, frame_rate.num}) : 0); double pts = (picture.pts == AV_NOPTS_VALUE) ? NAN : picture.pts * av_q2d(tb); picture.format = IJK_AV_PIX_FMT__VIDEO_TOOLBOX; ffp_queue_picture(ctx->ffp, &picture, pts, duration, 0, ctx->ffp->is->viddec.pkt_serial); CVBufferRelease(picture.opaque); SortQueuePop(ctx); } else { ALOGI("Get Picture failure!!!\n"); } } static void VTDecoderCallback(void *decompressionOutputRefCon, void *sourceFrameRefCon, OSStatus status, VTDecodeInfoFlags infoFlags, CVImageBufferRef imageBuffer, CMTime presentationTimeStamp, CMTime presentationDuration) { @autoreleasepool { Ijk_VideoToolBox_Opaque *ctx = (Ijk_VideoToolBox_Opaque*)decompressionOutputRefCon; if (!ctx) return; FFPlayer *ffp = ctx->ffp; VideoState *is = ffp->is; sort_queue *newFrame = NULL; sample_info *sample_info = sourceFrameRefCon; if (!sample_info->is_decoding) { ALOGD("VTB: frame out of date: id=%d\n", sample_info->sample_id); goto failed; } newFrame = (sort_queue *)mallocz(sizeof(sort_queue)); if (!newFrame) { ALOGE("VTB: create new frame fail: out of memory\n"); goto failed; } newFrame->pic.pts = sample_info->pts; newFrame->pic.pkt_dts = sample_info->dts; newFrame->pic.sample_aspect_ratio.num = sample_info->sar_num; newFrame->pic.sample_aspect_ratio.den = sample_info->sar_den; newFrame->serial = sample_info->serial; newFrame->nextframe = NULL; if (newFrame->pic.pts != AV_NOPTS_VALUE) { newFrame->sort = newFrame->pic.pts; } else { newFrame->sort = newFrame->pic.pkt_dts; newFrame->pic.pts = newFrame->pic.pkt_dts; } if (ctx->dealloced || is->abort_request || is->viddec.queue->abort_request) goto failed; if (status != 0) { ALOGE("decode callback %d %s\n", (int)status, vtb_get_error_string(status)); goto failed; } if (ctx->refresh_session) { goto failed; } if (newFrame->serial != ctx->serial) { goto failed; } if (imageBuffer == NULL) { ALOGI("imageBuffer null\n"); goto failed; } ffp->stat.vdps = SDL_SpeedSamplerAdd(&ctx->sampler, FFP_SHOW_VDPS_VIDEOTOOLBOX, "vdps[VideoToolbox]"); #ifdef FFP_VTB_DISABLE_OUTPUT goto failed; #endif OSType format_type = CVPixelBufferGetPixelFormatType(imageBuffer); if (format_type != kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) { ALOGI("format_type error \n"); goto failed; } if (kVTDecodeInfo_FrameDropped & infoFlags) { ALOGI("droped\n"); goto failed; } if (ctx->new_seg_flag) { ALOGI("new seg process!!!!"); while (ctx->m_queue_depth > 0) { QueuePicture(ctx); } ctx->new_seg_flag = false; } if (ctx->m_sort_queue && newFrame->pic.pts < ctx->m_sort_queue->pic.pts) { goto failed; } // FIXME: duplicated code { double dpts = NAN; if (newFrame->pic.pts != AV_NOPTS_VALUE) dpts = av_q2d(is->video_st->time_base) * newFrame->pic.pts; if (ffp->framedrop>0 || (ffp->framedrop && ffp_get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) { ffp->stat.decode_frame_count++; if (newFrame->pic.pts != AV_NOPTS_VALUE) { double diff = dpts - ffp_get_master_clock(is); if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD && diff - is->frame_last_filter_delay < 0 && is->viddec.pkt_serial == is->vidclk.serial && is->videoq.nb_packets) { is->frame_drops_early++; is->continuous_frame_drops_early++; if (is->continuous_frame_drops_early > ffp->framedrop) { is->continuous_frame_drops_early = 0; } else { ffp->stat.drop_frame_count++; ffp->stat.drop_frame_rate = (float)(ffp->stat.drop_frame_count) / (float)(ffp->stat.decode_frame_count); // drop too late frame goto failed; } } } } } if (CVPixelBufferIsPlanar(imageBuffer)) { newFrame->pic.width = (int)CVPixelBufferGetWidthOfPlane(imageBuffer, 0); newFrame->pic.height = (int)CVPixelBufferGetHeightOfPlane(imageBuffer, 0); } else { newFrame->pic.width = (int)CVPixelBufferGetWidth(imageBuffer); newFrame->pic.height = (int)CVPixelBufferGetHeight(imageBuffer); } newFrame->pic.opaque = CVBufferRetain(imageBuffer); pthread_mutex_lock(&ctx->m_queue_mutex); volatile sort_queue *queueWalker = ctx->m_sort_queue; if (!queueWalker || (newFrame->sort < queueWalker->sort)) { newFrame->nextframe = queueWalker; ctx->m_sort_queue = newFrame; } else { bool frameInserted = false; volatile sort_queue *nextFrame = NULL; while (!frameInserted) { nextFrame = queueWalker->nextframe; if (!nextFrame || (newFrame->sort < nextFrame->sort)) { newFrame->nextframe = nextFrame; queueWalker->nextframe = newFrame; frameInserted = true; } queueWalker = nextFrame; } } ctx->m_queue_depth++; pthread_mutex_unlock(&ctx->m_queue_mutex); //ALOGI("%lf %lf %lf \n", newFrame->sort,newFrame->pts, newFrame->dts); //ALOGI("display queue deep %d\n", ctx->m_queue_depth); if (ctx->ffp->is == NULL || ctx->ffp->is->abort_request || ctx->ffp->is->viddec.queue->abort_request) { while (ctx->m_queue_depth > 0) { SortQueuePop(ctx); } goto successed; } //ALOGI("depth %d %d\n", ctx->m_queue_depth, ctx->m_max_ref_frames); if ((ctx->m_queue_depth > ctx->fmt_desc.max_ref_frames)) { QueuePicture(ctx); } successed: sample_info_recycle(ctx, sample_info); return; failed: sample_info_recycle(ctx, sample_info); if (newFrame) { free(newFrame); } return; } } static void vtbsession_destroy(Ijk_VideoToolBox_Opaque *context) { if (!context) return; vtbformat_destroy(&context->fmt_desc); if (context->vt_session) { VTDecompressionSessionWaitForAsynchronousFrames(context->vt_session); VTDecompressionSessionInvalidate(context->vt_session); CFRelease(context->vt_session); context->vt_session = NULL; } } static VTDecompressionSessionRef vtbsession_create(Ijk_VideoToolBox_Opaque* context) { FFPlayer *ffp = context->ffp; int ret = 0; int width = context->codecpar->width; int height = context->codecpar->height; VTDecompressionSessionRef vt_session = NULL; CFMutableDictionaryRef destinationPixelBufferAttributes; VTDecompressionOutputCallbackRecord outputCallback; OSStatus status; ret = vtbformat_init(&context->fmt_desc, context->codecpar); if (ffp->vtb_max_frame_width > 0 && width > ffp->vtb_max_frame_width) { double w_scaler = (float)ffp->vtb_max_frame_width / width; width = ffp->vtb_max_frame_width; height = height * w_scaler; } ALOGI("after scale width %d height %d \n", width, height); destinationPixelBufferAttributes = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetSInt32(destinationPixelBufferAttributes, kCVPixelBufferPixelFormatTypeKey, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange); CFDictionarySetSInt32(destinationPixelBufferAttributes, kCVPixelBufferWidthKey, width); CFDictionarySetSInt32(destinationPixelBufferAttributes, kCVPixelBufferHeightKey, height); CFDictionarySetBoolean(destinationPixelBufferAttributes, kCVPixelBufferOpenGLESCompatibilityKey, YES); outputCallback.decompressionOutputCallback = VTDecoderCallback; outputCallback.decompressionOutputRefCon = context ; status = VTDecompressionSessionCreate( kCFAllocatorDefault, context->fmt_desc.fmt_desc, NULL, destinationPixelBufferAttributes, &outputCallback, &vt_session); if (status != noErr) { NSError* error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; NSLog(@"Error %@", [error description]); ALOGI("%s - failed with status = (%d)", __FUNCTION__, (int)status); } CFRelease(destinationPixelBufferAttributes); memset(context->sample_info_array, 0, sizeof(context->sample_info_array)); context->sample_infos_in_decoding = 0; return vt_session; } static int decode_video_internal(Ijk_VideoToolBox_Opaque* context, AVCodecContext *avctx, const AVPacket *avpkt, int* got_picture_ptr) { FFPlayer *ffp = context->ffp; OSStatus status = 0; uint32_t decoder_flags = 0; sample_info *sample_info = NULL; CMSampleBufferRef sample_buff = NULL; AVIOContext *pb = NULL; int demux_size = 0; uint8_t *demux_buff = NULL; uint8_t *pData = avpkt->data; int iSize = avpkt->size; double pts = avpkt->pts; double dts = avpkt->dts; if (!context) { goto failed; } if (ffp->vtb_async) { decoder_flags |= kVTDecodeFrame_EnableAsynchronousDecompression; } if (context->refresh_session) { decoder_flags |= kVTDecodeFrame_DoNotOutputFrame; // ALOGI("flag :%d flag %d \n", decoderFlags,avpkt->flags); } if (context->refresh_request) { while (context->m_queue_depth > 0) { SortQueuePop(context); } sample_info_flush(context, 1000); vtbsession_destroy(context); memset(context->sample_info_array, 0, sizeof(context->sample_info_array)); context->sample_infos_in_decoding = 0; context->vt_session = vtbsession_create(context); if (!context->vt_session) goto failed; context->refresh_request = false; } if (pts == AV_NOPTS_VALUE) { pts = dts; } if (context->fmt_desc.convert_bytestream) { // ALOGI("the buffer should m_convert_byte\n"); if(avio_open_dyn_buf(&pb) < 0) { goto failed; } ff_avc_parse_nal_units(pb, pData, iSize); demux_size = avio_close_dyn_buf(pb, &demux_buff); // ALOGI("demux_size:%d\n", demux_size); if (demux_size == 0) { goto failed; } sample_buff = CreateSampleBufferFrom(context->fmt_desc.fmt_desc, demux_buff, demux_size); } else if (context->fmt_desc.convert_3byteTo4byteNALSize) { // ALOGI("3byteto4byte\n"); if (avio_open_dyn_buf(&pb) < 0) { goto failed; } uint32_t nal_size; uint8_t *end = avpkt->data + avpkt->size; uint8_t *nal_start = pData; while (nal_start < end) { nal_size = AV_RB24(nal_start); avio_wb32(pb, nal_size); nal_start += 3; avio_write(pb, nal_start, nal_size); nal_start += nal_size; } demux_size = avio_close_dyn_buf(pb, &demux_buff); sample_buff = CreateSampleBufferFrom(context->fmt_desc.fmt_desc, demux_buff, demux_size); } else { sample_buff = CreateSampleBufferFrom(context->fmt_desc.fmt_desc, pData, iSize); } if (!sample_buff) { if (demux_size) { av_free(demux_buff); } ALOGI("%s - CreateSampleBufferFrom failed", __FUNCTION__); goto failed; } if (avpkt->flags & AV_PKT_FLAG_NEW_SEG) { context->new_seg_flag = true; } sample_info = sample_info_peek(context); if (!sample_info) { ALOGE("%s, failed to peek frame_info\n", __FUNCTION__); goto failed; } sample_info->pts = pts; sample_info->dts = dts; sample_info->serial = context->serial; sample_info->sar_num = avctx->sample_aspect_ratio.num; sample_info->sar_den = avctx->sample_aspect_ratio.den; sample_info_push(context); status = VTDecompressionSessionDecodeFrame(context->vt_session, sample_buff, decoder_flags, (void*)sample_info, 0); if (status == noErr) { if (context->ffp->is->videoq.abort_request) goto failed; // Wait for delayed frames even if kVTDecodeInfo_Asynchronous is not set. if (ffp->vtb_wait_async) { status = VTDecompressionSessionWaitForAsynchronousFrames(context->vt_session); } } if (status != 0) { sample_info_drop_last_push(context); ALOGE("decodeFrame %d %s\n", (int)status, vtb_get_error_string(status)); if (status == kVTInvalidSessionErr) { context->refresh_session = true; } if (status == kVTVideoDecoderMalfunctionErr) { context->recovery_drop_packet = true; context->refresh_session = true; } goto failed; } if (sample_buff) { CFRelease(sample_buff); } if (demux_size) { av_free(demux_buff); } *got_picture_ptr = 1; return 0; failed: if (sample_buff) { CFRelease(sample_buff); } if (demux_size) { av_free(demux_buff); } *got_picture_ptr = 0; return -1; } static inline void ResetPktBuffer(Ijk_VideoToolBox_Opaque* context) { for (int i = 0 ; i < context->m_buffer_deep; i++) { av_packet_unref(&context->m_buffer_packet[i]); } context->m_buffer_deep = 0; memset(context->m_buffer_packet, 0, sizeof(context->m_buffer_packet)); } static inline void DuplicatePkt(Ijk_VideoToolBox_Opaque* context, const AVPacket* pkt) { if (context->m_buffer_deep >= MAX_PKT_QUEUE_DEEP) { context->idr_based_identified = false; ResetPktBuffer(context); } AVPacket* avpkt = &context->m_buffer_packet[context->m_buffer_deep]; av_copy_packet(avpkt, pkt); context->m_buffer_deep++; } static int decode_video(Ijk_VideoToolBox_Opaque* context, AVCodecContext *avctx, AVPacket *avpkt, int* got_picture_ptr) { int ret = 0; uint8_t *size_data = NULL; int size_data_size = 0; if (!avpkt || !avpkt->data) { return 0; } if (context->ffp->vtb_handle_resolution_change && context->codecpar->codec_id == AV_CODEC_ID_H264) { size_data = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &size_data_size); // minimum avcC(sps,pps) = 7 if (size_data && size_data_size > 7) { int got_picture = 0; AVFrame *frame = av_frame_alloc(); AVDictionary *codec_opts = NULL; AVCodecContext *new_avctx = avcodec_alloc_context3(avctx->codec); if (!new_avctx) return AVERROR(ENOMEM); avcodec_parameters_to_context(new_avctx, context->codecpar); av_freep(&new_avctx->extradata); new_avctx->extradata = av_mallocz(size_data_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!new_avctx->extradata) return AVERROR(ENOMEM); memcpy(new_avctx->extradata, size_data, size_data_size); new_avctx->extradata_size = size_data_size; av_dict_set(&codec_opts, "threads", "1", 0); ret = avcodec_open2(new_avctx, avctx->codec, &codec_opts); av_dict_free(&codec_opts); if (ret < 0) { avcodec_free_context(&new_avctx); return ret; } ret = avcodec_decode_video2(new_avctx, frame, &got_picture, avpkt); if (ret < 0) { avcodec_free_context(&new_avctx); return ret; } else { if (context->codecpar->width != new_avctx->width && context->codecpar->height != new_avctx->height) { avcodec_parameters_from_context(context->codecpar, new_avctx); context->refresh_request = true; } } av_frame_unref(frame); avcodec_free_context(&new_avctx); } } else { if (ff_avpacket_is_idr(avpkt) == true) { context->idr_based_identified = true; } if (ff_avpacket_i_or_idr(avpkt, context->idr_based_identified) == true) { ResetPktBuffer(context); context->recovery_drop_packet = false; } if (context->recovery_drop_packet == true) { return -1; } } DuplicatePkt(context, avpkt); if (context->refresh_session) { ret = 0; sample_info_flush(context, 1000); vtbsession_destroy(context); memset(context->sample_info_array, 0, sizeof(context->sample_info_array)); context->sample_infos_in_decoding = 0; context->vt_session = vtbsession_create(context); if (!context->vt_session) return -1; if ((context->m_buffer_deep > 0) && ff_avpacket_i_or_idr(&context->m_buffer_packet[0], context->idr_based_identified) == true ) { for (int i = 0; i < context->m_buffer_deep; i++) { AVPacket* pkt = &context->m_buffer_packet[i]; ret = decode_video_internal(context, avctx, pkt, got_picture_ptr); } } else { context->recovery_drop_packet = true; ret = -1; ALOGE("recovery error!!!!\n"); } context->refresh_session = false; return ret; } return decode_video_internal(context, avctx, avpkt, got_picture_ptr); } static void dict_set_string(CFMutableDictionaryRef dict, CFStringRef key, const char * value) { CFStringRef string; string = CFStringCreateWithCString(NULL, value, kCFStringEncodingASCII); CFDictionarySetValue(dict, key, string); CFRelease(string); } static void dict_set_boolean(CFMutableDictionaryRef dict, CFStringRef key, BOOL value) { CFDictionarySetValue(dict, key, value ? kCFBooleanTrue: kCFBooleanFalse); } static void dict_set_object(CFMutableDictionaryRef dict, CFStringRef key, CFTypeRef *value) { CFDictionarySetValue(dict, key, value); } static void dict_set_data(CFMutableDictionaryRef dict, CFStringRef key, uint8_t * value, uint64_t length) { CFDataRef data; data = CFDataCreate(NULL, value, (CFIndex)length); CFDictionarySetValue(dict, key, data); CFRelease(data); } static void dict_set_i32(CFMutableDictionaryRef dict, CFStringRef key, int32_t value) { CFNumberRef number; number = CFNumberCreate(NULL, kCFNumberSInt32Type, &value); CFDictionarySetValue(dict, key, number); CFRelease(number); } static CMFormatDescriptionRef CreateFormatDescriptionFromCodecData(CMVideoCodecType format_id, int width, int height, const uint8_t *extradata, int extradata_size, uint32_t atom) { CMFormatDescriptionRef fmt_desc = NULL; OSStatus status; CFMutableDictionaryRef par = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks); CFMutableDictionaryRef atoms = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks); CFMutableDictionaryRef extensions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); /* CVPixelAspectRatio dict */ dict_set_i32(par, CFSTR ("HorizontalSpacing"), 0); dict_set_i32(par, CFSTR ("VerticalSpacing"), 0); /* SampleDescriptionExtensionAtoms dict */ switch (format_id) { case kCMVideoCodecType_H264: dict_set_data(atoms, CFSTR ("avcC"), (uint8_t *)extradata, extradata_size); break; case kCMVideoCodecType_HEVC: dict_set_data(atoms, CFSTR ("hvcC"), (uint8_t *)extradata, extradata_size); break; default: break; } /* Extensions dict */ dict_set_string(extensions, CFSTR ("CVImageBufferChromaLocationBottomField"), "left"); dict_set_string(extensions, CFSTR ("CVImageBufferChromaLocationTopField"), "left"); dict_set_boolean(extensions, CFSTR("FullRangeVideo"), FALSE); dict_set_object(extensions, CFSTR ("CVPixelAspectRatio"), (CFTypeRef *) par); dict_set_object(extensions, CFSTR ("SampleDescriptionExtensionAtoms"), (CFTypeRef *) atoms); status = CMVideoFormatDescriptionCreate(NULL, format_id, width, height, extensions, &fmt_desc); CFRelease(extensions); CFRelease(atoms); CFRelease(par); if (status == 0) return fmt_desc; else return NULL; } void videotoolbox_async_free(Ijk_VideoToolBox_Opaque* context) { context->dealloced = true; while (context && context->m_queue_depth > 0) { SortQueuePop(context); } sample_info_flush(context, 3000); vtbsession_destroy(context); if (context) { ResetPktBuffer(context); SDL_DestroyCondP(&context->sample_info_cond); SDL_DestroyMutexP(&context->sample_info_mutex); } vtbformat_destroy(&context->fmt_desc); avcodec_parameters_free(&context->codecpar); } int videotoolbox_async_decode_frame(Ijk_VideoToolBox_Opaque* context) { FFPlayer *ffp = context->ffp; VideoState *is = ffp->is; Decoder *d = &is->viddec; int got_frame = 0; do { int ret = -1; if (is->abort_request || d->queue->abort_request) { return -1; } if (!d->packet_pending || d->queue->serial != d->pkt_serial) { AVPacket pkt; do { if (d->queue->nb_packets == 0) SDL_CondSignal(d->empty_queue_cond); ffp_video_statistic_l(ffp); if (ffp_packet_queue_get_or_buffering(ffp, d->queue, &pkt, &d->pkt_serial, &d->finished) < 0) return -1; if (ffp_is_flush_packet(&pkt)) { avcodec_flush_buffers(d->avctx); context->refresh_request = true; context->serial += 1; d->finished = 0; ALOGI("flushed last keyframe pts %lld \n",d->pkt.pts); d->next_pts = d->start_pts; d->next_pts_tb = d->start_pts_tb; } } while (ffp_is_flush_packet(&pkt) || d->queue->serial != d->pkt_serial); av_packet_split_side_data(&pkt); av_packet_unref(&d->pkt); d->pkt_temp = d->pkt = pkt; d->packet_pending = 1; } ret = decode_video(context, d->avctx, &d->pkt_temp, &got_frame); if (ret < 0) { d->packet_pending = 0; } else { d->pkt_temp.dts = d->pkt_temp.pts = AV_NOPTS_VALUE; if (d->pkt_temp.data) { if (d->avctx->codec_type != AVMEDIA_TYPE_AUDIO) ret = d->pkt_temp.size; d->pkt_temp.data += ret; d->pkt_temp.size -= ret; if (d->pkt_temp.size <= 0) d->packet_pending = 0; } else { if (!got_frame) { d->packet_pending = 0; d->finished = d->pkt_serial; } } } } while (!got_frame && !d->finished); return got_frame; } static void vtbformat_destroy(VTBFormatDesc *fmt_desc) { if (!fmt_desc || !fmt_desc->fmt_desc) return; CFRelease(fmt_desc->fmt_desc); fmt_desc->fmt_desc = NULL; } static int vtbformat_init(VTBFormatDesc *fmt_desc, AVCodecParameters *codecpar) { int width = codecpar->width; int height = codecpar->height; int level = codecpar->level; int profile = codecpar->profile; int sps_level = 0; int sps_profile = 0; int extrasize = codecpar->extradata_size; int codec = codecpar->codec_id; uint8_t* extradata = codecpar->extradata; bool isHevcSupported = false; CMVideoCodecType format_id = 0; #if 0 switch (profile) { case FF_PROFILE_H264_HIGH_10: if ([IJKDeviceModel currentModel].rank >= kIJKDeviceRank_AppleA7Class) { // Apple A7 SoC // Hi10p can be decoded into NV12 ('420v') break; } case FF_PROFILE_H264_HIGH_10_INTRA: case FF_PROFILE_H264_HIGH_422: case FF_PROFILE_H264_HIGH_422_INTRA: case FF_PROFILE_H264_HIGH_444_PREDICTIVE: case FF_PROFILE_H264_HIGH_444_INTRA: case FF_PROFILE_H264_CAVLC_444: goto failed; } #endif if (width < 0 || height < 0) { goto fail; } if (extrasize < 7 || extradata == NULL) { ALOGI("%s - avcC or hvcC atom data too small or missing", __FUNCTION__); goto fail; } switch (codec) { case AV_CODEC_ID_HEVC: format_id = kCMVideoCodecType_HEVC; if (@available(iOS 11.0, *)) { isHevcSupported = VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC); } else { // Fallback on earlier versions isHevcSupported = false; } if (!isHevcSupported) { goto fail; } break; case AV_CODEC_ID_H264: format_id = kCMVideoCodecType_H264; break; default: goto fail; } if (extradata[0] == 1) { // if (!validate_avcC_spc(extradata, extrasize, &fmt_desc->max_ref_frames, &sps_level, &sps_profile)) { //goto failed; // } if (level == 0 && sps_level > 0) level = sps_level; if (profile == 0 && sps_profile > 0) profile = sps_profile; if (profile == FF_PROFILE_H264_MAIN && level == 32 && fmt_desc->max_ref_frames > 4) { ALOGE("%s - Main@L3.2 detected, VTB cannot decode with %d ref frames", __FUNCTION__, fmt_desc->max_ref_frames); goto fail; } if (extradata[4] == 0xFE) { extradata[4] = 0xFF; fmt_desc->convert_3byteTo4byteNALSize = true; } fmt_desc->fmt_desc = CreateFormatDescriptionFromCodecData(format_id, width, height, extradata, extrasize, IJK_VTB_FCC_AVCC); if (fmt_desc->fmt_desc == NULL) { goto fail; } ALOGI("%s - using avcC atom of size(%d), ref_frames(%d)", __FUNCTION__, extrasize, fmt_desc->max_ref_frames); } else { if ((extradata[0] == 0 && extradata[1] == 0 && extradata[2] == 0 && extradata[3] == 1) || (extradata[0] == 0 && extradata[1] == 0 && extradata[2] == 1)) { AVIOContext *pb; if (avio_open_dyn_buf(&pb) < 0) { goto fail; } fmt_desc->convert_bytestream = true; ff_isom_write_avcc(pb, extradata, extrasize); extradata = NULL; extrasize = avio_close_dyn_buf(pb, &extradata); if (!validate_avcC_spc(extradata, extrasize, &fmt_desc->max_ref_frames, &sps_level, &sps_profile)) { av_free(extradata); goto fail; } fmt_desc->fmt_desc = CreateFormatDescriptionFromCodecData(format_id, width, height, extradata, extrasize, IJK_VTB_FCC_AVCC); if (fmt_desc->fmt_desc == NULL) { goto fail; } av_free(extradata); } else { ALOGI("%s - invalid avcC atom data", __FUNCTION__); goto fail; } } fmt_desc->max_ref_frames = FFMAX(fmt_desc->max_ref_frames, 2); fmt_desc->max_ref_frames = FFMIN(fmt_desc->max_ref_frames, 5); ALOGI("m_max_ref_frames %d \n", fmt_desc->max_ref_frames); return 0; fail: vtbformat_destroy(fmt_desc); return -1; } Ijk_VideoToolBox_Opaque* videotoolbox_async_create(FFPlayer* ffp, AVCodecContext* avctx) { int ret = 0; if (ret) { ALOGW("%s - videotoolbox can not exists twice at the same time", __FUNCTION__); return NULL; } Ijk_VideoToolBox_Opaque *context_vtb = (Ijk_VideoToolBox_Opaque *)mallocz(sizeof(Ijk_VideoToolBox_Opaque)); context_vtb->sample_info_mutex = SDL_CreateMutex(); context_vtb->sample_info_cond = SDL_CreateCond(); if (!context_vtb) { goto fail; } context_vtb->codecpar = avcodec_parameters_alloc(); if (!context_vtb->codecpar) goto fail; ret = avcodec_parameters_from_context(context_vtb->codecpar, avctx); if (ret) goto fail; context_vtb->ffp = ffp; context_vtb->idr_based_identified = true; ret = vtbformat_init(&context_vtb->fmt_desc, context_vtb->codecpar); if (ret) goto fail; assert(context_vtb->fmt_desc.fmt_desc); vtbformat_destroy(&context_vtb->fmt_desc); context_vtb->vt_session = vtbsession_create(context_vtb); if (context_vtb->vt_session == NULL) goto fail; context_vtb->m_sort_queue = 0; context_vtb->m_queue_depth = 0; SDL_SpeedSamplerReset(&context_vtb->sampler); return context_vtb; fail: videotoolbox_async_free(context_vtb); return NULL; } ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBoxSync.h ================================================ /***************************************************************************** * IJKVideoToolBox.h ***************************************************************************** * * copyright (c) 2014 Zhou Quan * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKMediaPlayer_videotoolbox_sync_h #define IJKMediaPlayer_videotoolbox_sync_h #include "ff_ffplay.h" typedef struct Ijk_VideoToolBox_Opaque Ijk_VideoToolBox_Opaque; Ijk_VideoToolBox_Opaque* videotoolbox_sync_create(FFPlayer* ffp, AVCodecContext* ic); int videotoolbox_sync_decode_frame(Ijk_VideoToolBox_Opaque* opaque); void videotoolbox_sync_free(Ijk_VideoToolBox_Opaque* opaque); #endif ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBoxSync.m ================================================ /***************************************************************************** * IJKVideoToolBox.m ***************************************************************************** * * copyright (c) 2014 Zhou Quan * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "IJKVideoToolBoxSync.h" #include "ijksdl_vout_overlay_videotoolbox.h" #include "ffpipeline_ios.h" #include #include "libavformat/avc.h" #include "ijksdl_vout_ios_gles2.h" #include "h264_sps_parser.h" #include "ijkplayer/ff_ffplay_debug.h" #import #import #import #import #import "IJKDeviceModel.h" #include #import #include "ff_ffinc.h" #include "ff_fferror.h" #include "ff_ffmsg.h" #include "ijksdl/ios/ijksdl_vout_overlay_videotoolbox.h" #define IJK_VTB_FCC_AVCC SDL_FOURCC('C', 'c', 'v', 'a') #define MAX_PKT_QUEUE_DEEP 350 typedef struct sample_info { double sort; double dts; double pts; int serial; int sar_num; int sar_den; } sample_info; typedef struct sort_queue { AVFrame pic; int serial; int64_t sort; volatile struct sort_queue *nextframe; } sort_queue; typedef struct VTBFormatDesc { CMFormatDescriptionRef fmt_desc; int32_t max_ref_frames; bool convert_bytestream; bool convert_3byteTo4byteNALSize; } VTBFormatDesc; struct Ijk_VideoToolBox_Opaque { FFPlayer *ffp; VTDecompressionSessionRef vt_session; AVCodecParameters *codecpar; VTBFormatDesc fmt_desc; volatile bool refresh_request; volatile bool new_seg_flag; volatile bool idr_based_identified; volatile bool refresh_session; volatile bool recovery_drop_packet; pthread_mutex_t m_queue_mutex; volatile sort_queue *m_sort_queue; volatile int32_t m_queue_depth; int m_buffer_deep; AVPacket m_buffer_packet[MAX_PKT_QUEUE_DEEP]; sample_info sample_info; SDL_SpeedSampler sampler; int serial; bool dealloced; }; static void vtbformat_destroy(VTBFormatDesc *fmt_desc); static int vtbformat_init(VTBFormatDesc *fmt_desc, AVCodecParameters *codecpar); static const char *vtb_get_error_string(OSStatus status) { switch (status) { case kVTInvalidSessionErr: return "kVTInvalidSessionErr"; case kVTVideoDecoderBadDataErr: return "kVTVideoDecoderBadDataErr"; case kVTVideoDecoderUnsupportedDataFormatErr: return "kVTVideoDecoderUnsupportedDataFormatErr"; case kVTVideoDecoderMalfunctionErr: return "kVTVideoDecoderMalfunctionErr"; default: return "UNKNOWN"; } } static void SortQueuePop(Ijk_VideoToolBox_Opaque* context) { if (!context->m_sort_queue || context->m_queue_depth == 0) { return; } pthread_mutex_lock(&context->m_queue_mutex); volatile sort_queue *top_frame = context->m_sort_queue; context->m_sort_queue = context->m_sort_queue->nextframe; context->m_queue_depth--; pthread_mutex_unlock(&context->m_queue_mutex); CVBufferRelease(top_frame->pic.opaque); free((void*)top_frame); } static void SortQueuePush(Ijk_VideoToolBox_Opaque *ctx, sort_queue *newFrame) { pthread_mutex_lock(&ctx->m_queue_mutex); volatile sort_queue *queueWalker = ctx->m_sort_queue; if (!queueWalker || (newFrame->sort < queueWalker->sort)) { newFrame->nextframe = queueWalker; ctx->m_sort_queue = newFrame; } else { bool frameInserted = false; volatile sort_queue *nextFrame = NULL; while (!frameInserted) { nextFrame = queueWalker->nextframe; if (!nextFrame || (newFrame->sort < nextFrame->sort)) { newFrame->nextframe = nextFrame; queueWalker->nextframe = newFrame; frameInserted = true; } queueWalker = nextFrame; } } ctx->m_queue_depth++; pthread_mutex_unlock(&ctx->m_queue_mutex); } static void CFDictionarySetSInt32(CFMutableDictionaryRef dictionary, CFStringRef key, SInt32 numberSInt32) { CFNumberRef number; number = CFNumberCreate(NULL, kCFNumberSInt32Type, &numberSInt32); CFDictionarySetValue(dictionary, key, number); CFRelease(number); } static void CFDictionarySetBoolean(CFMutableDictionaryRef dictionary, CFStringRef key, BOOL value) { CFDictionarySetValue(dictionary, key, value ? kCFBooleanTrue : kCFBooleanFalse); } static CMSampleBufferRef CreateSampleBufferFrom(CMFormatDescriptionRef fmt_desc, void *demux_buff, size_t demux_size) { OSStatus status; CMBlockBufferRef newBBufOut = NULL; CMSampleBufferRef sBufOut = NULL; status = CMBlockBufferCreateWithMemoryBlock( NULL, demux_buff, demux_size, kCFAllocatorNull, NULL, 0, demux_size, FALSE, &newBBufOut); if (!status) { status = CMSampleBufferCreate( NULL, newBBufOut, TRUE, 0, 0, fmt_desc, 1, 0, NULL, 0, NULL, &sBufOut); } if (newBBufOut) CFRelease(newBBufOut); if (status == 0) { return sBufOut; } else { return NULL; } } static bool GetVTBPicture(Ijk_VideoToolBox_Opaque* context, AVFrame* pVTBPicture) { if (context->m_sort_queue == NULL) { return false; } pthread_mutex_lock(&context->m_queue_mutex); volatile sort_queue *sort_queue = context->m_sort_queue; *pVTBPicture = sort_queue->pic; pVTBPicture->opaque = CVBufferRetain(sort_queue->pic.opaque); pthread_mutex_unlock(&context->m_queue_mutex); return true; } static void QueuePicture(Ijk_VideoToolBox_Opaque* ctx) { AVFrame picture = {0}; if (true == GetVTBPicture(ctx, &picture)) { AVRational tb = ctx->ffp->is->video_st->time_base; AVRational frame_rate = av_guess_frame_rate(ctx->ffp->is->ic, ctx->ffp->is->video_st, NULL); double duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational) {frame_rate.den, frame_rate.num}) : 0); double pts = (picture.pts == AV_NOPTS_VALUE) ? NAN : picture.pts * av_q2d(tb); picture.format = IJK_AV_PIX_FMT__VIDEO_TOOLBOX; ffp_queue_picture(ctx->ffp, &picture, pts, duration, 0, ctx->ffp->is->viddec.pkt_serial); CVBufferRelease(picture.opaque); SortQueuePop(ctx); } else { ALOGI("Get Picture failure!!!\n"); } } static void VTDecoderCallback(void *decompressionOutputRefCon, void *sourceFrameRefCon, OSStatus status, VTDecodeInfoFlags infoFlags, CVImageBufferRef imageBuffer, CMTime presentationTimeStamp, CMTime presentationDuration) { @autoreleasepool { Ijk_VideoToolBox_Opaque *ctx = (Ijk_VideoToolBox_Opaque*)decompressionOutputRefCon; if (!ctx) return; FFPlayer *ffp = ctx->ffp; VideoState *is = ffp->is; sort_queue *newFrame = NULL; sample_info *sample_info = &ctx->sample_info; newFrame = (sort_queue *)mallocz(sizeof(sort_queue)); if (!newFrame) { ALOGE("VTB: create new frame fail: out of memory\n"); goto failed; } newFrame->pic.pts = sample_info->pts; newFrame->pic.pkt_dts = sample_info->dts; newFrame->pic.sample_aspect_ratio.num = sample_info->sar_num; newFrame->pic.sample_aspect_ratio.den = sample_info->sar_den; newFrame->serial = sample_info->serial; newFrame->nextframe = NULL; if (newFrame->pic.pts != AV_NOPTS_VALUE) { newFrame->sort = newFrame->pic.pts; } else { newFrame->sort = newFrame->pic.pkt_dts; newFrame->pic.pts = newFrame->pic.pkt_dts; } if (ctx->dealloced || is->abort_request || is->viddec.queue->abort_request) goto failed; if (status != 0) { ALOGE("decode callback %d %s\n", (int)status, vtb_get_error_string(status)); goto failed; } if (ctx->refresh_session) { goto failed; } if (newFrame->serial != ctx->serial) { goto failed; } if (imageBuffer == NULL) { ALOGI("imageBuffer null\n"); goto failed; } ffp->stat.vdps = SDL_SpeedSamplerAdd(&ctx->sampler, FFP_SHOW_VDPS_VIDEOTOOLBOX, "vdps[VideoToolbox]"); #ifdef FFP_VTB_DISABLE_OUTPUT goto failed; #endif OSType format_type = CVPixelBufferGetPixelFormatType(imageBuffer); if (format_type != kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) { ALOGI("format_type error \n"); goto failed; } if (kVTDecodeInfo_FrameDropped & infoFlags) { ALOGI("droped\n"); goto failed; } if (ctx->new_seg_flag) { ALOGI("new seg process!!!!"); while (ctx->m_queue_depth > 0) { QueuePicture(ctx); } ctx->new_seg_flag = false; } if (ctx->m_sort_queue && newFrame->pic.pts < ctx->m_sort_queue->pic.pts) { goto failed; } // FIXME: duplicated code { double dpts = NAN; if (newFrame->pic.pts != AV_NOPTS_VALUE) dpts = av_q2d(is->video_st->time_base) * newFrame->pic.pts; if (ffp->framedrop>0 || (ffp->framedrop && ffp_get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) { ffp->stat.decode_frame_count++; if (newFrame->pic.pts != AV_NOPTS_VALUE) { double diff = dpts - ffp_get_master_clock(is); if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD && diff - is->frame_last_filter_delay < 0 && is->viddec.pkt_serial == is->vidclk.serial && is->videoq.nb_packets) { is->frame_drops_early++; is->continuous_frame_drops_early++; if (is->continuous_frame_drops_early > ffp->framedrop) { is->continuous_frame_drops_early = 0; } else { ffp->stat.drop_frame_count++; ffp->stat.drop_frame_rate = (float)(ffp->stat.drop_frame_count) / (float)(ffp->stat.decode_frame_count); // drop too late frame goto failed; } } } } } if (CVPixelBufferIsPlanar(imageBuffer)) { newFrame->pic.width = (int)CVPixelBufferGetWidthOfPlane(imageBuffer, 0); newFrame->pic.height = (int)CVPixelBufferGetHeightOfPlane(imageBuffer, 0); } else { newFrame->pic.width = (int)CVPixelBufferGetWidth(imageBuffer); newFrame->pic.height = (int)CVPixelBufferGetHeight(imageBuffer); } newFrame->pic.opaque = CVBufferRetain(imageBuffer); SortQueuePush(ctx, newFrame); if (ctx->ffp->is == NULL || ctx->ffp->is->abort_request || ctx->ffp->is->viddec.queue->abort_request) { while (ctx->m_queue_depth > 0) { SortQueuePop(ctx); } goto successed; } if ((ctx->m_queue_depth > ctx->fmt_desc.max_ref_frames)) { QueuePicture(ctx); } successed: return; failed: if (newFrame) { free(newFrame); } return; } } static void vtbsession_destroy(Ijk_VideoToolBox_Opaque *context) { if (!context) return; vtbformat_destroy(&context->fmt_desc); if (context->vt_session) { VTDecompressionSessionWaitForAsynchronousFrames(context->vt_session); VTDecompressionSessionInvalidate(context->vt_session); CFRelease(context->vt_session); context->vt_session = NULL; } } static VTDecompressionSessionRef vtbsession_create(Ijk_VideoToolBox_Opaque* context) { FFPlayer *ffp = context->ffp; int ret = 0; int width = context->codecpar->width; int height = context->codecpar->height; VTDecompressionSessionRef vt_session = NULL; CFMutableDictionaryRef destinationPixelBufferAttributes; VTDecompressionOutputCallbackRecord outputCallback; OSStatus status; ret = vtbformat_init(&context->fmt_desc, context->codecpar); if (ffp->vtb_max_frame_width > 0 && width > ffp->vtb_max_frame_width) { double w_scaler = (float)ffp->vtb_max_frame_width / width; width = ffp->vtb_max_frame_width; height = height * w_scaler; } ALOGI("after scale width %d height %d \n", width, height); destinationPixelBufferAttributes = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetSInt32(destinationPixelBufferAttributes, kCVPixelBufferPixelFormatTypeKey, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange); CFDictionarySetSInt32(destinationPixelBufferAttributes, kCVPixelBufferWidthKey, width); CFDictionarySetSInt32(destinationPixelBufferAttributes, kCVPixelBufferHeightKey, height); CFDictionarySetBoolean(destinationPixelBufferAttributes, kCVPixelBufferOpenGLESCompatibilityKey, YES); outputCallback.decompressionOutputCallback = VTDecoderCallback; outputCallback.decompressionOutputRefCon = context ; status = VTDecompressionSessionCreate( kCFAllocatorDefault, context->fmt_desc.fmt_desc, NULL, destinationPixelBufferAttributes, &outputCallback, &vt_session); if (status != noErr) { NSError* error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; NSLog(@"Error %@", [error description]); ALOGI("%s - failed with status = (%d)", __FUNCTION__, (int)status); } CFRelease(destinationPixelBufferAttributes); memset(&context->sample_info, 0, sizeof(struct sample_info)); return vt_session; } static int decode_video_internal(Ijk_VideoToolBox_Opaque* context, AVCodecContext *avctx, const AVPacket *avpkt, int* got_picture_ptr) { FFPlayer *ffp = context->ffp; OSStatus status = 0; uint32_t decoder_flags = 0; sample_info *sample_info = NULL; CMSampleBufferRef sample_buff = NULL; AVIOContext *pb = NULL; int demux_size = 0; uint8_t *demux_buff = NULL; uint8_t *pData = avpkt->data; int iSize = avpkt->size; double pts = avpkt->pts; double dts = avpkt->dts; if (!context) { goto failed; } if (context->refresh_session) { decoder_flags |= kVTDecodeFrame_DoNotOutputFrame; // ALOGI("flag :%d flag %d \n", decoderFlags,avpkt->flags); } if (context->refresh_request) { while (context->m_queue_depth > 0) { SortQueuePop(context); } vtbsession_destroy(context); memset(&context->sample_info, 0, sizeof(struct sample_info)); context->vt_session = vtbsession_create(context); if (!context->vt_session) goto failed; context->refresh_request = false; } if (pts == AV_NOPTS_VALUE) { pts = dts; } if (context->fmt_desc.convert_bytestream) { // ALOGI("the buffer should m_convert_byte\n"); if(avio_open_dyn_buf(&pb) < 0) { goto failed; } ff_avc_parse_nal_units(pb, pData, iSize); demux_size = avio_close_dyn_buf(pb, &demux_buff); // ALOGI("demux_size:%d\n", demux_size); if (demux_size == 0) { goto failed; } sample_buff = CreateSampleBufferFrom(context->fmt_desc.fmt_desc, demux_buff, demux_size); } else if (context->fmt_desc.convert_3byteTo4byteNALSize) { // ALOGI("3byteto4byte\n"); if (avio_open_dyn_buf(&pb) < 0) { goto failed; } uint32_t nal_size; uint8_t *end = avpkt->data + avpkt->size; uint8_t *nal_start = pData; while (nal_start < end) { nal_size = AV_RB24(nal_start); avio_wb32(pb, nal_size); nal_start += 3; avio_write(pb, nal_start, nal_size); nal_start += nal_size; } demux_size = avio_close_dyn_buf(pb, &demux_buff); sample_buff = CreateSampleBufferFrom(context->fmt_desc.fmt_desc, demux_buff, demux_size); } else { sample_buff = CreateSampleBufferFrom(context->fmt_desc.fmt_desc, pData, iSize); } if (!sample_buff) { if (demux_size) { av_free(demux_buff); } ALOGI("%s - CreateSampleBufferFrom failed", __FUNCTION__); goto failed; } if (avpkt->flags & AV_PKT_FLAG_NEW_SEG) { context->new_seg_flag = true; } sample_info = &context->sample_info; if (!sample_info) { ALOGE("%s, failed to peek frame_info\n", __FUNCTION__); goto failed; } sample_info->pts = pts; sample_info->dts = dts; sample_info->serial = context->serial; sample_info->sar_num = avctx->sample_aspect_ratio.num; sample_info->sar_den = avctx->sample_aspect_ratio.den; status = VTDecompressionSessionDecodeFrame(context->vt_session, sample_buff, decoder_flags, (void*)sample_info, 0); if (status == noErr) { if (ffp->is->videoq.abort_request) goto failed; } if (status != 0) { ALOGE("decodeFrame %d %s\n", (int)status, vtb_get_error_string(status)); if (status == kVTInvalidSessionErr) { context->refresh_session = true; } if (status == kVTVideoDecoderMalfunctionErr) { context->recovery_drop_packet = true; context->refresh_session = true; } goto failed; } if (sample_buff) { CFRelease(sample_buff); } if (demux_size) { av_free(demux_buff); } *got_picture_ptr = 1; return 0; failed: if (sample_buff) { CFRelease(sample_buff); } if (demux_size) { av_free(demux_buff); } *got_picture_ptr = 0; return -1; } static inline void ResetPktBuffer(Ijk_VideoToolBox_Opaque* context) { for (int i = 0 ; i < context->m_buffer_deep; i++) { av_packet_unref(&context->m_buffer_packet[i]); } context->m_buffer_deep = 0; memset(context->m_buffer_packet, 0, sizeof(context->m_buffer_packet)); } static inline void DuplicatePkt(Ijk_VideoToolBox_Opaque* context, const AVPacket* pkt) { if (context->m_buffer_deep >= MAX_PKT_QUEUE_DEEP) { context->idr_based_identified = false; ResetPktBuffer(context); } AVPacket* avpkt = &context->m_buffer_packet[context->m_buffer_deep]; av_copy_packet(avpkt, pkt); context->m_buffer_deep++; } static int decode_video(Ijk_VideoToolBox_Opaque* context, AVCodecContext *avctx, AVPacket *avpkt, int* got_picture_ptr) { int ret = 0; uint8_t *size_data = NULL; int size_data_size = 0; if (!avpkt || !avpkt->data) { return 0; } if (context->ffp->vtb_handle_resolution_change && context->codecpar->codec_id == AV_CODEC_ID_H264) { size_data = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &size_data_size); // minimum avcC(sps,pps) = 7 if (size_data && size_data_size > 7) { int got_picture = 0; AVFrame *frame = av_frame_alloc(); AVDictionary *codec_opts = NULL; AVCodecContext *new_avctx = avcodec_alloc_context3(avctx->codec); if (!new_avctx) return AVERROR(ENOMEM); avcodec_parameters_to_context(new_avctx, context->codecpar); av_freep(&new_avctx->extradata); new_avctx->extradata = av_mallocz(size_data_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!new_avctx->extradata) return AVERROR(ENOMEM); memcpy(new_avctx->extradata, size_data, size_data_size); new_avctx->extradata_size = size_data_size; av_dict_set(&codec_opts, "threads", "1", 0); ret = avcodec_open2(new_avctx, avctx->codec, &codec_opts); av_dict_free(&codec_opts); if (ret < 0) { avcodec_free_context(&new_avctx); return ret; } ret = avcodec_decode_video2(new_avctx, frame, &got_picture, avpkt); if (ret < 0) { avcodec_free_context(&new_avctx); return ret; } else { if (context->codecpar->width != new_avctx->width && context->codecpar->height != new_avctx->height) { avcodec_parameters_from_context(context->codecpar, new_avctx); context->refresh_request = true; } } av_frame_unref(frame); avcodec_free_context(&new_avctx); } } else { if (ff_avpacket_is_idr(avpkt) == true) { context->idr_based_identified = true; } if (ff_avpacket_i_or_idr(avpkt, context->idr_based_identified) == true) { ResetPktBuffer(context); context->recovery_drop_packet = false; } if (context->recovery_drop_packet == true) { return -1; } } DuplicatePkt(context, avpkt); if (context->refresh_session) { ret = 0; vtbsession_destroy(context); memset(&context->sample_info, 0, sizeof(struct sample_info)); context->vt_session = vtbsession_create(context); if (!context->vt_session) return -1; if ((context->m_buffer_deep > 0) && ff_avpacket_i_or_idr(&context->m_buffer_packet[0], context->idr_based_identified) == true ) { for (int i = 0; i < context->m_buffer_deep; i++) { AVPacket* pkt = &context->m_buffer_packet[i]; ret = decode_video_internal(context, avctx, pkt, got_picture_ptr); } } else { context->recovery_drop_packet = true; ret = -1; ALOGE("recovery error!!!!\n"); } context->refresh_session = false; return ret; } return decode_video_internal(context, avctx, avpkt, got_picture_ptr); } static void dict_set_string(CFMutableDictionaryRef dict, CFStringRef key, const char * value) { CFStringRef string; string = CFStringCreateWithCString(NULL, value, kCFStringEncodingASCII); CFDictionarySetValue(dict, key, string); CFRelease(string); } static void dict_set_boolean(CFMutableDictionaryRef dict, CFStringRef key, BOOL value) { CFDictionarySetValue(dict, key, value ? kCFBooleanTrue: kCFBooleanFalse); } static void dict_set_object(CFMutableDictionaryRef dict, CFStringRef key, CFTypeRef *value) { CFDictionarySetValue(dict, key, value); } static void dict_set_data(CFMutableDictionaryRef dict, CFStringRef key, uint8_t * value, uint64_t length) { CFDataRef data; data = CFDataCreate(NULL, value, (CFIndex)length); CFDictionarySetValue(dict, key, data); CFRelease(data); } static void dict_set_i32(CFMutableDictionaryRef dict, CFStringRef key, int32_t value) { CFNumberRef number; number = CFNumberCreate(NULL, kCFNumberSInt32Type, &value); CFDictionarySetValue(dict, key, number); CFRelease(number); } static CMFormatDescriptionRef CreateFormatDescriptionFromCodecData(CMVideoCodecType format_id, int width, int height, const uint8_t *extradata, int extradata_size, uint32_t atom) { CMFormatDescriptionRef fmt_desc = NULL; OSStatus status; CFMutableDictionaryRef par = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks); CFMutableDictionaryRef atoms = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks); CFMutableDictionaryRef extensions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); /* CVPixelAspectRatio dict */ dict_set_i32(par, CFSTR ("HorizontalSpacing"), 0); dict_set_i32(par, CFSTR ("VerticalSpacing"), 0); /* SampleDescriptionExtensionAtoms dict */ switch (format_id) { case kCMVideoCodecType_H264: dict_set_data(atoms, CFSTR ("avcC"), (uint8_t *)extradata, extradata_size); break; case kCMVideoCodecType_HEVC: dict_set_data(atoms, CFSTR ("hvcC"), (uint8_t *)extradata, extradata_size); break; default: break; } /* Extensions dict */ dict_set_string(extensions, CFSTR ("CVImageBufferChromaLocationBottomField"), "left"); dict_set_string(extensions, CFSTR ("CVImageBufferChromaLocationTopField"), "left"); dict_set_boolean(extensions, CFSTR("FullRangeVideo"), FALSE); dict_set_object(extensions, CFSTR ("CVPixelAspectRatio"), (CFTypeRef *) par); dict_set_object(extensions, CFSTR ("SampleDescriptionExtensionAtoms"), (CFTypeRef *) atoms); status = CMVideoFormatDescriptionCreate(NULL, format_id, width, height, extensions, &fmt_desc); CFRelease(extensions); CFRelease(atoms); CFRelease(par); if (status == 0) return fmt_desc; else return NULL; } void videotoolbox_sync_free(Ijk_VideoToolBox_Opaque* context) { context->dealloced = true; while (context && context->m_queue_depth > 0) { SortQueuePop(context); } vtbsession_destroy(context); if (context) { ResetPktBuffer(context); } vtbformat_destroy(&context->fmt_desc); avcodec_parameters_free(&context->codecpar); } int videotoolbox_sync_decode_frame(Ijk_VideoToolBox_Opaque* context) { FFPlayer *ffp = context->ffp; VideoState *is = ffp->is; Decoder *d = &is->viddec; int got_frame = 0; do { int ret = -1; if (is->abort_request || d->queue->abort_request) { return -1; } if (!d->packet_pending || d->queue->serial != d->pkt_serial) { AVPacket pkt; do { if (d->queue->nb_packets == 0) SDL_CondSignal(d->empty_queue_cond); ffp_video_statistic_l(ffp); if (ffp_packet_queue_get_or_buffering(ffp, d->queue, &pkt, &d->pkt_serial, &d->finished) < 0) return -1; if (ffp_is_flush_packet(&pkt)) { avcodec_flush_buffers(d->avctx); context->refresh_request = true; context->serial += 1; d->finished = 0; ALOGI("flushed last keyframe pts %lld \n",d->pkt.pts); d->next_pts = d->start_pts; d->next_pts_tb = d->start_pts_tb; } } while (ffp_is_flush_packet(&pkt) || d->queue->serial != d->pkt_serial); av_packet_split_side_data(&pkt); av_packet_unref(&d->pkt); d->pkt_temp = d->pkt = pkt; d->packet_pending = 1; } ret = decode_video(context, d->avctx, &d->pkt_temp, &got_frame); if (ret < 0) { d->packet_pending = 0; } else { d->pkt_temp.dts = d->pkt_temp.pts = AV_NOPTS_VALUE; if (d->pkt_temp.data) { if (d->avctx->codec_type != AVMEDIA_TYPE_AUDIO) ret = d->pkt_temp.size; d->pkt_temp.data += ret; d->pkt_temp.size -= ret; if (d->pkt_temp.size <= 0) d->packet_pending = 0; } else { if (!got_frame) { d->packet_pending = 0; d->finished = d->pkt_serial; } } } } while (!got_frame && !d->finished); return got_frame; } static void vtbformat_destroy(VTBFormatDesc *fmt_desc) { if (!fmt_desc || !fmt_desc->fmt_desc) return; CFRelease(fmt_desc->fmt_desc); fmt_desc->fmt_desc = NULL; } static int vtbformat_init(VTBFormatDesc *fmt_desc, AVCodecParameters *codecpar) { int width = codecpar->width; int height = codecpar->height; int level = codecpar->level; int profile = codecpar->profile; int sps_level = 0; int sps_profile = 0; int extrasize = codecpar->extradata_size; int codec = codecpar->codec_id; uint8_t* extradata = codecpar->extradata; bool isHevcSupported = false; CMVideoCodecType format_id = 0; #if 0 switch (profile) { case FF_PROFILE_H264_HIGH_10: if ([IJKDeviceModel currentModel].rank >= kIJKDeviceRank_AppleA7Class) { // Apple A7 SoC // Hi10p can be decoded into NV12 ('420v') break; } case FF_PROFILE_H264_HIGH_10_INTRA: case FF_PROFILE_H264_HIGH_422: case FF_PROFILE_H264_HIGH_422_INTRA: case FF_PROFILE_H264_HIGH_444_PREDICTIVE: case FF_PROFILE_H264_HIGH_444_INTRA: case FF_PROFILE_H264_CAVLC_444: goto failed; } #endif if (width < 0 || height < 0) { goto fail; } if (extrasize < 7 || extradata == NULL) { ALOGI("%s - avcC or hvcC atom data too small or missing", __FUNCTION__); goto fail; } switch (codec) { case AV_CODEC_ID_HEVC: format_id = kCMVideoCodecType_HEVC; if (@available(iOS 11.0, *)) { isHevcSupported = VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC); } else { // Fallback on earlier versions isHevcSupported = false; } if (!isHevcSupported) { goto fail; } break; case AV_CODEC_ID_H264: format_id = kCMVideoCodecType_H264; break; default: goto fail; } if (extradata[0] == 1) { // if (!validate_avcC_spc(extradata, extrasize, &fmt_desc->max_ref_frames, &sps_level, &sps_profile)) { //goto failed; // } if (level == 0 && sps_level > 0) level = sps_level; if (profile == 0 && sps_profile > 0) profile = sps_profile; if (profile == FF_PROFILE_H264_MAIN && level == 32 && fmt_desc->max_ref_frames > 4) { ALOGE("%s - Main@L3.2 detected, VTB cannot decode with %d ref frames", __FUNCTION__, fmt_desc->max_ref_frames); goto fail; } if (extradata[4] == 0xFE) { extradata[4] = 0xFF; fmt_desc->convert_3byteTo4byteNALSize = true; } fmt_desc->fmt_desc = CreateFormatDescriptionFromCodecData(format_id, width, height, extradata, extrasize, IJK_VTB_FCC_AVCC); if (fmt_desc->fmt_desc == NULL) { goto fail; } ALOGI("%s - using avcC atom of size(%d), ref_frames(%d)", __FUNCTION__, extrasize, fmt_desc->max_ref_frames); } else { if ((extradata[0] == 0 && extradata[1] == 0 && extradata[2] == 0 && extradata[3] == 1) || (extradata[0] == 0 && extradata[1] == 0 && extradata[2] == 1)) { AVIOContext *pb; if (avio_open_dyn_buf(&pb) < 0) { goto fail; } fmt_desc->convert_bytestream = true; ff_isom_write_avcc(pb, extradata, extrasize); extradata = NULL; extrasize = avio_close_dyn_buf(pb, &extradata); if (!validate_avcC_spc(extradata, extrasize, &fmt_desc->max_ref_frames, &sps_level, &sps_profile)) { av_free(extradata); goto fail; } fmt_desc->fmt_desc = CreateFormatDescriptionFromCodecData(format_id, width, height, extradata, extrasize, IJK_VTB_FCC_AVCC); if (fmt_desc->fmt_desc == NULL) { goto fail; } av_free(extradata); } else { ALOGI("%s - invalid avcC atom data", __FUNCTION__); goto fail; } } fmt_desc->max_ref_frames = FFMAX(fmt_desc->max_ref_frames, 2); fmt_desc->max_ref_frames = FFMIN(fmt_desc->max_ref_frames, 5); ALOGI("m_max_ref_frames %d \n", fmt_desc->max_ref_frames); return 0; fail: vtbformat_destroy(fmt_desc); return -1; } Ijk_VideoToolBox_Opaque* videotoolbox_sync_create(FFPlayer* ffp, AVCodecContext* avctx) { int ret = 0; if (ret) { ALOGW("%s - videotoolbox can not exists twice at the same time", __FUNCTION__); return NULL; } Ijk_VideoToolBox_Opaque *context_vtb = (Ijk_VideoToolBox_Opaque *)mallocz(sizeof(Ijk_VideoToolBox_Opaque)); if (!context_vtb) { goto fail; } context_vtb->codecpar = avcodec_parameters_alloc(); if (!context_vtb->codecpar) goto fail; ret = avcodec_parameters_from_context(context_vtb->codecpar, avctx); if (ret) goto fail; context_vtb->ffp = ffp; context_vtb->idr_based_identified = true; ret = vtbformat_init(&context_vtb->fmt_desc, context_vtb->codecpar); if (ret) goto fail; assert(context_vtb->fmt_desc.fmt_desc); vtbformat_destroy(&context_vtb->fmt_desc); context_vtb->vt_session = vtbsession_create(context_vtb); if (context_vtb->vt_session == NULL) goto fail; context_vtb->m_sort_queue = 0; context_vtb->m_queue_depth = 0; SDL_SpeedSamplerReset(&context_vtb->sampler); return context_vtb; fail: videotoolbox_sync_free(context_vtb); return NULL; } ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/ffpipeline_ios.c ================================================ /* * ffpipeline_ios.c * * Copyright (c) 2014 Zhou Quan * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ffpipeline_ios.h" #include "ffpipenode_ios_videotoolbox_vdec.h" #include "ffpipenode_ffplay_vdec.h" #include "ff_ffplay.h" #import "ijksdl/ios/ijksdl_aout_ios_audiounit.h" struct IJKFF_Pipeline_Opaque { FFPlayer *ffp; bool is_videotoolbox_open; }; static void func_destroy(IJKFF_Pipeline *pipeline) { } static IJKFF_Pipenode *func_open_video_decoder(IJKFF_Pipeline *pipeline, FFPlayer *ffp) { IJKFF_Pipenode* node = NULL; IJKFF_Pipeline_Opaque *opaque = pipeline->opaque; if (ffp->videotoolbox) { node = ffpipenode_create_video_decoder_from_ios_videotoolbox(ffp); if (!node) ALOGE("vtb fail!!! switch to ffmpeg decode!!!! \n"); } if (node == NULL) { node = ffpipenode_create_video_decoder_from_ffplay(ffp); ffp->stat.vdec_type = FFP_PROPV_DECODER_AVCODEC; opaque->is_videotoolbox_open = false; } else { ffp->stat.vdec_type = FFP_PROPV_DECODER_VIDEOTOOLBOX; opaque->is_videotoolbox_open = true; } ffp_notify_msg2(ffp, FFP_MSG_VIDEO_DECODER_OPEN, opaque->is_videotoolbox_open); return node; } static SDL_Aout *func_open_audio_output(IJKFF_Pipeline *pipeline, FFPlayer *ffp) { return SDL_AoutIos_CreateForAudioUnit(); } static SDL_Class g_pipeline_class = { .name = "ffpipeline_ios", }; IJKFF_Pipeline *ffpipeline_create_from_ios(FFPlayer *ffp) { IJKFF_Pipeline *pipeline = ffpipeline_alloc(&g_pipeline_class, sizeof(IJKFF_Pipeline_Opaque)); if (!pipeline) return pipeline; IJKFF_Pipeline_Opaque *opaque = pipeline->opaque; opaque->ffp = ffp; pipeline->func_destroy = func_destroy; pipeline->func_open_video_decoder = func_open_video_decoder; pipeline->func_open_audio_output = func_open_audio_output; return pipeline; } ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/ffpipeline_ios.h ================================================ /* * ffpipeline_ios.h * * Copyright (c) 2014 Zhou Quan * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__FF_FFPIPELINE_IOS_H #define FFPLAY__FF_FFPIPELINE_IOS_H #include "ijkplayer/ff_ffpipeline.h" struct FFPlayer; IJKFF_Pipeline *ffpipeline_create_from_ios(struct FFPlayer *ffp); #endif ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/ffpipenode_ios_videotoolbox_vdec.h ================================================ /* * ffpipenode_ios_videotoolbox_vdec.h * * Copyright (c) 2014 Zhou Quan * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFPLAY__FF_FFPIPENODE_IOS_VIDEOTOOLBOX_DEC_H #define FFPLAY__FF_FFPIPENODE_IOS_VIDEOTOOLBOX_DEC_H #include "ijkplayer/ff_ffpipenode.h" struct FFPlayer; IJKFF_Pipenode *ffpipenode_create_video_decoder_from_ios_videotoolbox(struct FFPlayer *ffp); #endif ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/ffpipenode_ios_videotoolbox_vdec.m ================================================ /* * ffpipenode_ios_videotoolbox_vdec.m * * Copyright (c) 2014 Zhou Quan * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ffpipenode_ios_videotoolbox_vdec.h" #include "IJKVideoToolBox.h" #include "ijksdl_vout_overlay_videotoolbox.h" #include "ijkplayer/ff_ffpipeline.h" #include "ijkplayer/ff_ffpipenode.h" #include "ijkplayer/ff_ffplay.h" #include "ijksdl_mutex.h" #include "ijksdl_vout_ios_gles2.h" #import struct IJKFF_Pipenode_Opaque { IJKFF_Pipeline *pipeline; FFPlayer *ffp; Decoder *decoder; Ijk_VideoToolBox *context; AVCodecContext *avctx; // not own SDL_Thread* video_fill_thread; SDL_Thread _video_fill_thread; }; int videotoolbox_video_thread(void *arg) { IJKFF_Pipenode_Opaque* opaque = (IJKFF_Pipenode_Opaque*) arg; FFPlayer *ffp = opaque->ffp; VideoState *is = ffp->is; Decoder *d = &is->viddec; int ret = 0; for (;;) { if (is->abort_request || d->queue->abort_request) { return -1; } @autoreleasepool { ret = opaque->context->decode_frame(opaque->context->opaque); } if (ret < 0) goto the_end; if (!ret) continue; if (ret < 0) goto the_end; } the_end: return 0; } static void func_destroy(IJKFF_Pipenode *node) { // do nothing } static int func_run_sync(IJKFF_Pipenode *node) { IJKFF_Pipenode_Opaque *opaque = node->opaque; int ret = videotoolbox_video_thread(opaque); if (opaque->context) { opaque->context->free(opaque->context->opaque); free(opaque->context); opaque->context = NULL; } return ret; } IJKFF_Pipenode *ffpipenode_create_video_decoder_from_ios_videotoolbox(FFPlayer *ffp) { if (!ffp || !ffp->is) return NULL; if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0){ return NULL; } IJKFF_Pipenode *node = ffpipenode_alloc(sizeof(IJKFF_Pipenode_Opaque)); if (!node) return node; memset(node, sizeof(IJKFF_Pipenode), 0); VideoState *is = ffp->is; IJKFF_Pipenode_Opaque *opaque = node->opaque; node->func_destroy = func_destroy; node->func_run_sync = func_run_sync; opaque->ffp = ffp; opaque->decoder = &is->viddec; opaque->avctx = opaque->decoder->avctx; switch (opaque->avctx->codec_id) { case AV_CODEC_ID_H264: case AV_CODEC_ID_HEVC: if (ffp->vtb_async) opaque->context = Ijk_VideoToolbox_Async_Create(ffp, opaque->avctx); else opaque->context = Ijk_VideoToolbox_Sync_Create(ffp, opaque->avctx); break; default: ALOGI("Videotoolbox-pipeline:open_video_decoder: not H264 or H265\n"); goto fail; } if (opaque->context == NULL) { ALOGE("could not init video tool box decoder !!!"); goto fail; } return node; fail: ffpipenode_free_p(&node); return NULL; } ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijkplayer/ios/pipeline/h264_sps_parser.h ================================================ /* * h264_sps_parser.h * * Copyright (c) 2014 Zhou Quan * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IJKMediaPlayer_h264_sps_parser_h #define IJKMediaPlayer_h264_sps_parser_h #define AV_RB16(x) \ ((((const uint8_t*)(x))[0] << 8) | \ ((const uint8_t*)(x)) [1]) #define AV_RB24(x) \ ((((const uint8_t*)(x))[0] << 16) | \ (((const uint8_t*)(x))[1] << 8) | \ ((const uint8_t*)(x))[2]) #define AV_RB32(x) \ ((((const uint8_t*)(x))[0] << 24) | \ (((const uint8_t*)(x))[1] << 16) | \ (((const uint8_t*)(x))[2] << 8) | \ ((const uint8_t*)(x))[3]) /* NAL unit types */ enum { NAL_SLICE = 1, NAL_DPA = 2, NAL_DPB = 3, NAL_DPC = 4, NAL_IDR_SLICE = 5, NAL_SEI = 6, NAL_SPS = 7, NAL_PPS = 8, NAL_AUD = 9, NAL_END_SEQUENCE = 10, NAL_END_STREAM = 11, NAL_FILLER_DATA = 12, NAL_SPS_EXT = 13, NAL_AUXILIARY_SLICE = 19, NAL_FF_IGNORE = 0xff0f001, }; typedef struct { const uint8_t *data; const uint8_t *end; int head; uint64_t cache; } nal_bitstream; static void nal_bs_init(nal_bitstream *bs, const uint8_t *data, size_t size) { bs->data = data; bs->end = data + size; bs->head = 0; // fill with something other than 0 to detect // emulation prevention bytes bs->cache = 0xffffffff; } static uint64_t nal_bs_read(nal_bitstream *bs, int n) { uint64_t res = 0; int shift; if (n == 0) return res; // fill up the cache if we need to while (bs->head < n) { uint8_t a_byte; bool check_three_byte; check_three_byte = true; next_byte: if (bs->data >= bs->end) { // we're at the end, can't produce more than head number of bits n = bs->head; break; } // get the byte, this can be an emulation_prevention_three_byte that we need // to ignore. a_byte = *bs->data++; if (check_three_byte && a_byte == 0x03 && ((bs->cache & 0xffff) == 0)) { // next byte goes unconditionally to the cache, even if it's 0x03 check_three_byte = false; goto next_byte; } // shift bytes in cache, moving the head bits of the cache left bs->cache = (bs->cache << 8) | a_byte; bs->head += 8; } // bring the required bits down and truncate if ((shift = bs->head - n) > 0) res = bs->cache >> shift; else res = bs->cache; // mask out required bits if (n < 32) res &= (1 << n) - 1; bs->head = shift; return res; } static bool nal_bs_eos(nal_bitstream *bs) { return (bs->data >= bs->end) && (bs->head == 0); } // read unsigned Exp-Golomb code static int64_t nal_bs_read_ue(nal_bitstream *bs) { int i = 0; while (nal_bs_read(bs, 1) == 0 && !nal_bs_eos(bs) && i < 32) i++; return ((1 << i) - 1 + nal_bs_read(bs, i)); } typedef struct { uint64_t profile_idc; uint64_t level_idc; uint64_t sps_id; uint64_t chroma_format_idc; uint64_t separate_colour_plane_flag; uint64_t bit_depth_luma_minus8; uint64_t bit_depth_chroma_minus8; uint64_t qpprime_y_zero_transform_bypass_flag; uint64_t seq_scaling_matrix_present_flag; uint64_t log2_max_frame_num_minus4; uint64_t pic_order_cnt_type; uint64_t log2_max_pic_order_cnt_lsb_minus4; uint64_t max_num_ref_frames; uint64_t gaps_in_frame_num_value_allowed_flag; uint64_t pic_width_in_mbs_minus1; uint64_t pic_height_in_map_units_minus1; uint64_t frame_mbs_only_flag; uint64_t mb_adaptive_frame_field_flag; uint64_t direct_8x8_inference_flag; uint64_t frame_cropping_flag; uint64_t frame_crop_left_offset; uint64_t frame_crop_right_offset; uint64_t frame_crop_top_offset; uint64_t frame_crop_bottom_offset; } sps_info_struct; static void parseh264_sps(uint8_t *sps, uint32_t sps_size, int *level, int *profile, bool *interlaced, int32_t *max_ref_frames) { nal_bitstream bs; sps_info_struct sps_info = {0}; nal_bs_init(&bs, sps, sps_size); sps_info.profile_idc = nal_bs_read(&bs, 8); nal_bs_read(&bs, 1); // constraint_set0_flag nal_bs_read(&bs, 1); // constraint_set1_flag nal_bs_read(&bs, 1); // constraint_set2_flag nal_bs_read(&bs, 1); // constraint_set3_flag nal_bs_read(&bs, 4); // reserved sps_info.level_idc = nal_bs_read(&bs, 8); sps_info.sps_id = nal_bs_read_ue(&bs); if (sps_info.profile_idc == 100 || sps_info.profile_idc == 110 || sps_info.profile_idc == 122 || sps_info.profile_idc == 244 || sps_info.profile_idc == 44 || sps_info.profile_idc == 83 || sps_info.profile_idc == 86) { sps_info.chroma_format_idc = nal_bs_read_ue(&bs); if (sps_info.chroma_format_idc == 3) sps_info.separate_colour_plane_flag = nal_bs_read(&bs, 1); sps_info.bit_depth_luma_minus8 = nal_bs_read_ue(&bs); sps_info.bit_depth_chroma_minus8 = nal_bs_read_ue(&bs); sps_info.qpprime_y_zero_transform_bypass_flag = nal_bs_read(&bs, 1); sps_info.seq_scaling_matrix_present_flag = nal_bs_read (&bs, 1); if (sps_info.seq_scaling_matrix_present_flag) { /* TODO: unfinished */ } } sps_info.log2_max_frame_num_minus4 = nal_bs_read_ue(&bs); if (sps_info.log2_max_frame_num_minus4 > 12) { // must be between 0 and 12 // don't early return here - the bits we are using (profile/level/interlaced/ref frames) // might still be valid - let the parser go on and pray. //return; } sps_info.pic_order_cnt_type = nal_bs_read_ue(&bs); if (sps_info.pic_order_cnt_type == 0) { sps_info.log2_max_pic_order_cnt_lsb_minus4 = nal_bs_read_ue(&bs); } else if (sps_info.pic_order_cnt_type == 1) { // TODO: unfinished /* delta_pic_order_always_zero_flag = gst_nal_bs_read (bs, 1); offset_for_non_ref_pic = gst_nal_bs_read_se (bs); offset_for_top_to_bottom_field = gst_nal_bs_read_se (bs); num_ref_frames_in_pic_order_cnt_cycle = gst_nal_bs_read_ue (bs); for( i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ ) offset_for_ref_frame[i] = gst_nal_bs_read_se (bs); */ } sps_info.max_num_ref_frames = nal_bs_read_ue(&bs); sps_info.gaps_in_frame_num_value_allowed_flag = nal_bs_read(&bs, 1); sps_info.pic_width_in_mbs_minus1 = nal_bs_read_ue(&bs); sps_info.pic_height_in_map_units_minus1 = nal_bs_read_ue(&bs); sps_info.frame_mbs_only_flag = nal_bs_read(&bs, 1); if (!sps_info.frame_mbs_only_flag) sps_info.mb_adaptive_frame_field_flag = nal_bs_read(&bs, 1); sps_info.direct_8x8_inference_flag = nal_bs_read(&bs, 1); sps_info.frame_cropping_flag = nal_bs_read(&bs, 1); if (sps_info.frame_cropping_flag) { sps_info.frame_crop_left_offset = nal_bs_read_ue(&bs); sps_info.frame_crop_right_offset = nal_bs_read_ue(&bs); sps_info.frame_crop_top_offset = nal_bs_read_ue(&bs); sps_info.frame_crop_bottom_offset = nal_bs_read_ue(&bs); } *level = (int)sps_info.level_idc; *profile = (int)sps_info.profile_idc; *interlaced = (int)!sps_info.frame_mbs_only_flag; *max_ref_frames = (int)sps_info.max_num_ref_frames; } static bool validate_avcC_spc(uint8_t *extradata, uint32_t extrasize, int32_t *max_ref_frames, int *level, int *profile) { // check the avcC atom's sps for number of reference frames and // bail if interlaced, VDA does not handle interlaced h264. bool interlaced = true; uint8_t *spc = extradata + 6; uint32_t sps_size = AV_RB16(spc); if (sps_size) parseh264_sps(spc+3, sps_size-1, level, profile, &interlaced, max_ref_frames); if (interlaced) return false; return true; } static inline int ff_get_nal_units_type(const uint8_t * const data) { return data[4] & 0x1f; } static uint32_t bytesToInt(uint8_t* src) { uint32_t value; value = (uint32_t)((src[0] & 0xFF)<<24|(src[1]&0xFF)<<16|(src[2]&0xFF)<<8|(src[3]&0xFF)); return value; } static bool ff_avpacket_is_idr(const AVPacket* pkt) { int state = -1; if (pkt->data && pkt->size >= 5) { int offset = 0; while (offset >= 0 && offset + 5 <= pkt->size) { void* nal_start = pkt->data+offset; state = ff_get_nal_units_type(nal_start); if (state == NAL_IDR_SLICE) { return true; } // ALOGI("offset %d \n", bytesToInt(nal_start)); offset+=(bytesToInt(nal_start) + 4); } } return false; } static bool ff_avpacket_is_key(const AVPacket* pkt) { if (pkt->flags & AV_PKT_FLAG_KEY) { return true; } else { return false; } } static bool ff_avpacket_i_or_idr(const AVPacket* pkt,bool isIdr) { if (isIdr == true) { return ff_avpacket_is_idr(pkt); } else { return ff_avpacket_is_key(pkt); } } #endif ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLAudioKit.h ================================================ /* * IJKSDLAudioKit.h * * Copyright (c) 2013-2014 Bilibili * Copyright (c) 2013-2014 Zhang Rui * * based on https://github.com/kolyvan/kxmovie * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import #include "ijksdl/ijksdl_aout.h" extern void IJKSDLGetAudioComponentDescriptionFromSpec(const SDL_AudioSpec *spec, AudioComponentDescription *desc); extern void IJKSDLGetAudioStreamBasicDescriptionFromSpec(const SDL_AudioSpec *spec, AudioStreamBasicDescription *desc); ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLAudioKit.m ================================================ /* * IJKSDLAudioKit.m * * Copyright (c) 2013-2014 Bilibili * Copyright (c) 2013-2014 Zhang Rui * * based on https://github.com/kolyvan/kxmovie * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKSDLAudioKit.h" extern void IJKSDLGetAudioComponentDescriptionFromSpec(const SDL_AudioSpec *spec, AudioComponentDescription *desc) { desc->componentType = kAudioUnitType_Output; desc->componentSubType = kAudioUnitSubType_RemoteIO; desc->componentManufacturer = kAudioUnitManufacturer_Apple; desc->componentFlags = 0; desc->componentFlagsMask = 0; } extern void IJKSDLGetAudioStreamBasicDescriptionFromSpec(const SDL_AudioSpec *spec, AudioStreamBasicDescription *desc) { desc->mSampleRate = spec->freq; desc->mFormatID = kAudioFormatLinearPCM; desc->mFormatFlags = kLinearPCMFormatFlagIsPacked; desc->mChannelsPerFrame = spec->channels; desc->mFramesPerPacket = 1; desc->mBitsPerChannel = SDL_AUDIO_BITSIZE(spec->format); if (SDL_AUDIO_ISBIGENDIAN(spec->format)) desc->mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; if (SDL_AUDIO_ISFLOAT(spec->format)) desc->mFormatFlags |= kLinearPCMFormatFlagIsFloat; if (SDL_AUDIO_ISSIGNED(spec->format)) desc->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; desc->mBytesPerFrame = desc->mBitsPerChannel * desc->mChannelsPerFrame / 8; desc->mBytesPerPacket = desc->mBytesPerFrame * desc->mFramesPerPacket; } ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLAudioQueueController.h ================================================ /* * IJKSDLAudioQueueController.h * * Copyright (c) 2013-2014 Bilibili * Copyright (c) 2013-2014 Zhang Rui * * based on https://github.com/kolyvan/kxmovie * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import #include "ijksdl/ijksdl_aout.h" @interface IJKSDLAudioQueueController : NSObject - (id)initWithAudioSpec:(const SDL_AudioSpec *)aSpec; - (void)play; - (void)pause; - (void)flush; - (void)stop; - (void)close; - (void)setPlaybackRate:(float)playbackRate; - (void)setPlaybackVolume:(float)playbackVolume; - (double)get_latency_seconds; @property (nonatomic, readonly) SDL_AudioSpec spec; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLAudioQueueController.m ================================================ /* * IJKSDLAudioQueueController.m * * Copyright (c) 2013-2014 Bilibili * Copyright (c) 2013-2014 Zhang Rui * * based on https://github.com/kolyvan/kxmovie * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKSDLAudioQueueController.h" #import "IJKSDLAudioKit.h" #import "ijksdl_log.h" #import #define kIJKAudioQueueNumberBuffers (3) @implementation IJKSDLAudioQueueController { AudioQueueRef _audioQueueRef; AudioQueueBufferRef _audioQueueBufferRefArray[kIJKAudioQueueNumberBuffers]; BOOL _isPaused; BOOL _isStopped; volatile BOOL _isAborted; NSLock *_lock; } - (id)initWithAudioSpec:(const SDL_AudioSpec *)aSpec { self = [super init]; if (self) { if (aSpec == NULL) { self = nil; return nil; } _spec = *aSpec; if (aSpec->format != AUDIO_S16SYS) { NSLog(@"aout_open_audio: unsupported format %d\n", (int)aSpec->format); return nil; } if (aSpec->channels > 2) { NSLog(@"aout_open_audio: unsupported channels %d\n", (int)aSpec->channels); return nil; } /* Get the current format */ AudioStreamBasicDescription streamDescription; IJKSDLGetAudioStreamBasicDescriptionFromSpec(&_spec, &streamDescription); SDL_CalculateAudioSpec(&_spec); if (_spec.size == 0) { NSLog(@"aout_open_audio: unexcepted audio spec size %u", _spec.size); return nil; } /* Set the desired format */ AudioQueueRef audioQueueRef; OSStatus status = AudioQueueNewOutput(&streamDescription, IJKSDLAudioQueueOuptutCallback, (__bridge void *) self, NULL, kCFRunLoopCommonModes, 0, &audioQueueRef); if (status != noErr) { NSLog(@"AudioQueue: AudioQueueNewOutput failed (%d)\n", (int)status); self = nil; return nil; } UInt32 propValue = 1; AudioQueueSetProperty(audioQueueRef, kAudioQueueProperty_EnableTimePitch, &propValue, sizeof(propValue)); propValue = 1; AudioQueueSetProperty(_audioQueueRef, kAudioQueueProperty_TimePitchBypass, &propValue, sizeof(propValue)); propValue = kAudioQueueTimePitchAlgorithm_Spectral; AudioQueueSetProperty(_audioQueueRef, kAudioQueueProperty_TimePitchAlgorithm, &propValue, sizeof(propValue)); status = AudioQueueStart(audioQueueRef, NULL); if (status != noErr) { NSLog(@"AudioQueue: AudioQueueStart failed (%d)\n", (int)status); self = nil; return nil; } _audioQueueRef = audioQueueRef; for (int i = 0;i < kIJKAudioQueueNumberBuffers; i++) { AudioQueueAllocateBuffer(audioQueueRef, _spec.size, &_audioQueueBufferRefArray[i]); _audioQueueBufferRefArray[i]->mAudioDataByteSize = _spec.size; memset(_audioQueueBufferRefArray[i]->mAudioData, 0, _spec.size); AudioQueueEnqueueBuffer(audioQueueRef, _audioQueueBufferRefArray[i], 0, NULL); } /*- status = AudioQueueStart(audioQueueRef, NULL); if (status != noErr) { NSLog(@"AudioQueue: AudioQueueStart failed (%d)\n", (int)status); self = nil; return nil; } */ _isStopped = NO; _lock = [[NSLock alloc] init]; } return self; } - (void)dealloc { [self close]; } - (void)play { if (!_audioQueueRef) return; self.spec.callback(self.spec.userdata, NULL, 0); @synchronized(_lock) { _isPaused = NO; NSError *error = nil; if (NO == [[AVAudioSession sharedInstance] setActive:YES error:&error]) { NSLog(@"AudioQueue: AVAudioSession.setActive(YES) failed: %@\n", error ? [error localizedDescription] : @"nil"); } OSStatus status = AudioQueueStart(_audioQueueRef, NULL); if (status != noErr) NSLog(@"AudioQueue: AudioQueueStart failed (%d)\n", (int)status); } } - (void)pause { if (!_audioQueueRef) return; @synchronized(_lock) { if (_isStopped) return; _isPaused = YES; OSStatus status = AudioQueuePause(_audioQueueRef); if (status != noErr) NSLog(@"AudioQueue: AudioQueuePause failed (%d)\n", (int)status); } } - (void)flush { if (!_audioQueueRef) return; @synchronized(_lock) { if (_isStopped) return; if (_isPaused == YES) { for (int i = 0; i < kIJKAudioQueueNumberBuffers; i++) { if (_audioQueueBufferRefArray[i] && _audioQueueBufferRefArray[i]->mAudioData) { _audioQueueBufferRefArray[i]->mAudioDataByteSize = _spec.size; memset(_audioQueueBufferRefArray[i]->mAudioData, 0, _spec.size); } } } else { AudioQueueFlush(_audioQueueRef); } } } - (void)stop { if (!_audioQueueRef) return; @synchronized(_lock) { if (_isStopped) return; _isStopped = YES; } // do not lock AudioQueueStop, or may be run into deadlock AudioQueueStop(_audioQueueRef, true); AudioQueueDispose(_audioQueueRef, true); } - (void)close { [self stop]; _audioQueueRef = nil; } - (void)setPlaybackRate:(float)playbackRate { if (fabsf(playbackRate - 1.0f) <= 0.000001) { UInt32 propValue = 1; AudioQueueSetProperty(_audioQueueRef, kAudioQueueProperty_TimePitchBypass, &propValue, sizeof(propValue)); AudioQueueSetParameter(_audioQueueRef, kAudioQueueParam_PlayRate, 1.0f); } else { UInt32 propValue = 0; AudioQueueSetProperty(_audioQueueRef, kAudioQueueProperty_TimePitchBypass, &propValue, sizeof(propValue)); AudioQueueSetParameter(_audioQueueRef, kAudioQueueParam_PlayRate, playbackRate); } } - (void)setPlaybackVolume:(float)playbackVolume { float aq_volume = playbackVolume; if (fabsf(aq_volume - 1.0f) <= 0.000001) { AudioQueueSetParameter(_audioQueueRef, kAudioQueueParam_Volume, 1.f); } else { AudioQueueSetParameter(_audioQueueRef, kAudioQueueParam_Volume, aq_volume); } } - (double)get_latency_seconds { return ((double)(kIJKAudioQueueNumberBuffers)) * _spec.samples / _spec.freq; } static void IJKSDLAudioQueueOuptutCallback(void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) { @autoreleasepool { IJKSDLAudioQueueController* aqController = (__bridge IJKSDLAudioQueueController *) inUserData; if (!aqController) { // do nothing; } else if (aqController->_isPaused || aqController->_isStopped) { memset(inBuffer->mAudioData, aqController.spec.silence, inBuffer->mAudioDataByteSize); } else { (*aqController.spec.callback)(aqController.spec.userdata, inBuffer->mAudioData, inBuffer->mAudioDataByteSize); } AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL); } } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLAudioUnitController.h ================================================ /* * IJKSDLAudioUnitController.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * based on https://github.com/kolyvan/kxmovie * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import #include "ijksdl/ijksdl_aout.h" @interface IJKSDLAudioUnitController : NSObject - (id)initWithAudioSpec:(const SDL_AudioSpec *)aSpec; - (void)play; - (void)pause; - (void)flush; - (void)stop; - (void)close; @property (nonatomic, readonly) SDL_AudioSpec spec; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLAudioUnitController.m ================================================ /* * IJKSDLAudioUnitController.m * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * based on https://github.com/kolyvan/kxmovie * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKSDLAudioUnitController.h" #import "IJKSDLAudioKit.h" #include "ijksdl/ijksdl_log.h" #import @implementation IJKSDLAudioUnitController { AudioUnit _auUnit; BOOL _isPaused; } - (id)initWithAudioSpec:(const SDL_AudioSpec *)aSpec { self = [super init]; if (self) { if (aSpec == NULL) { self = nil; return nil; } _spec = *aSpec; if (aSpec->format != AUDIO_S16SYS) { NSLog(@"aout_open_audio: unsupported format %d\n", (int)aSpec->format); return nil; } if (aSpec->channels > 6) { NSLog(@"aout_open_audio: unsupported channels %d\n", (int)aSpec->channels); return nil; } AudioComponentDescription desc; IJKSDLGetAudioComponentDescriptionFromSpec(&_spec, &desc); AudioComponent auComponent = AudioComponentFindNext(NULL, &desc); if (auComponent == NULL) { ALOGE("AudioUnit: AudioComponentFindNext failed"); self = nil; return nil; } AudioUnit auUnit; OSStatus status = AudioComponentInstanceNew(auComponent, &auUnit); if (status != noErr) { ALOGE("AudioUnit: AudioComponentInstanceNew failed"); self = nil; return nil; } UInt32 flag = 1; status = AudioUnitSetProperty(auUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &flag, sizeof(flag)); if (status != noErr) { ALOGE("AudioUnit: failed to set IO mode (%d)", (int)status); } /* Get the current format */ _spec.format = AUDIO_S16SYS; _spec.channels = 2; AudioStreamBasicDescription streamDescription; IJKSDLGetAudioStreamBasicDescriptionFromSpec(&_spec, &streamDescription); /* Set the desired format */ UInt32 i_param_size = sizeof(streamDescription); status = AudioUnitSetProperty(auUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamDescription, i_param_size); if (status != noErr) { ALOGE("AudioUnit: failed to set stream format (%d)", (int)status); self = nil; return nil; } /* Retrieve actual format */ status = AudioUnitGetProperty(auUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamDescription, &i_param_size); if (status != noErr) { ALOGE("AudioUnit: failed to verify stream format (%d)\n", (int)status); } AURenderCallbackStruct callback; callback.inputProc = (AURenderCallback) RenderCallback; callback.inputProcRefCon = (__bridge void*) self; status = AudioUnitSetProperty(auUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)); if (status != noErr) { ALOGE("AudioUnit: render callback setup failed (%d)\n", (int)status); self = nil; return nil; } SDL_CalculateAudioSpec(&_spec); /* AU initiliaze */ status = AudioUnitInitialize(auUnit); if (status != noErr) { ALOGE("AudioUnit: AudioUnitInitialize failed (%d)\n", (int)status); self = nil; return nil; } _auUnit = auUnit; } return self; } - (void)dealloc { [self close]; } - (void)play { if (!_auUnit) return; _isPaused = NO; NSError *error = nil; if (NO == [[AVAudioSession sharedInstance] setActive:YES error:&error]) { NSLog(@"AudioUnit: AVAudioSession.setActive(YES) failed: %@\n", error ? [error localizedDescription] : @"nil"); } OSStatus status = AudioOutputUnitStart(_auUnit); if (status != noErr) NSLog(@"AudioUnit: AudioOutputUnitStart failed (%d)\n", (int)status); } - (void)pause { if (!_auUnit) return; _isPaused = YES; OSStatus status = AudioOutputUnitStop(_auUnit); if (status != noErr) ALOGE("AudioUnit: failed to stop AudioUnit (%d)\n", (int)status); } - (void)flush { if (!_auUnit) return; AudioUnitReset(_auUnit, kAudioUnitScope_Global, 0); } - (void)stop { if (!_auUnit) return; OSStatus status = AudioOutputUnitStop(_auUnit); if (status != noErr) ALOGE("AudioUnit: failed to stop AudioUnit (%d)", (int)status); } - (void)close { [self stop]; if (!_auUnit) return; AURenderCallbackStruct callback; memset(&callback, 0, sizeof(AURenderCallbackStruct)); AudioUnitSetProperty(_auUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)); AudioComponentInstanceDispose(_auUnit); _auUnit = NULL; } static OSStatus RenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { @autoreleasepool { IJKSDLAudioUnitController* auController = (__bridge IJKSDLAudioUnitController *) inRefCon; if (!auController || auController->_isPaused) { for (UInt32 i = 0; i < ioData->mNumberBuffers; i++) { AudioBuffer *ioBuffer = &ioData->mBuffers[i]; memset(ioBuffer->mData, auController.spec.silence, ioBuffer->mDataByteSize); } return noErr; } for (int i = 0; i < (int)ioData->mNumberBuffers; i++) { AudioBuffer *ioBuffer = &ioData->mBuffers[i]; (*auController.spec.callback)(auController.spec.userdata, ioBuffer->mData, ioBuffer->mDataByteSize); } return noErr; } } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLGLView.h ================================================ /* * IJKSDLGLView.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * based on https://github.com/kolyvan/kxmovie * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import #import "IJKSDLGLViewProtocol.h" #include "ijksdl/ijksdl_vout.h" @interface IJKSDLGLView : UIView - (id) initWithFrame:(CGRect)frame; - (void) display: (SDL_VoutOverlay *) overlay; - (UIImage*) snapshot; - (void)setShouldLockWhileBeingMovedToWindow:(BOOL)shouldLockWhiteBeingMovedToWindow __attribute__((deprecated("unused"))); @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLGLView.m ================================================ /* * IJKSDLGLView.m * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * based on https://github.com/kolyvan/kxmovie * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "IJKSDLGLView.h" #include "ijksdl/ijksdl_timer.h" #include "ijksdl/ios/ijksdl_ios.h" #include "ijksdl/ijksdl_gles2.h" typedef NS_ENUM(NSInteger, IJKSDLGLViewApplicationState) { IJKSDLGLViewApplicationUnknownState = 0, IJKSDLGLViewApplicationForegroundState = 1, IJKSDLGLViewApplicationBackgroundState = 2 }; @interface IJKSDLGLView() @property(atomic,strong) NSRecursiveLock *glActiveLock; @property(atomic) BOOL glActivePaused; @end @implementation IJKSDLGLView { EAGLContext *_context; GLuint _framebuffer; GLuint _renderbuffer; GLint _backingWidth; GLint _backingHeight; int _frameCount; int64_t _lastFrameTime; IJK_GLES2_Renderer *_renderer; int _rendererGravity; BOOL _isRenderBufferInvalidated; int _tryLockErrorCount; BOOL _didSetupGL; BOOL _didStopGL; BOOL _didLockedDueToMovedToWindow; BOOL _shouldLockWhileBeingMovedToWindow; NSMutableArray *_registeredNotifications; IJKSDLGLViewApplicationState _applicationState; } @synthesize isThirdGLView = _isThirdGLView; @synthesize scaleFactor = _scaleFactor; @synthesize fps = _fps; + (Class) layerClass { return [CAEAGLLayer class]; } - (id) initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { _tryLockErrorCount = 0; _shouldLockWhileBeingMovedToWindow = YES; self.glActiveLock = [[NSRecursiveLock alloc] init]; _registeredNotifications = [[NSMutableArray alloc] init]; [self registerApplicationObservers]; _didSetupGL = NO; if ([self isApplicationActive] == YES) [self setupGLOnce]; } return self; } - (void)willMoveToWindow:(UIWindow *)newWindow { if (!_shouldLockWhileBeingMovedToWindow) { [super willMoveToWindow:newWindow]; return; } if (newWindow && !_didLockedDueToMovedToWindow) { [self lockGLActive]; _didLockedDueToMovedToWindow = YES; } [super willMoveToWindow:newWindow]; } - (void)didMoveToWindow { [super didMoveToWindow]; if (self.window && _didLockedDueToMovedToWindow) { [self unlockGLActive]; _didLockedDueToMovedToWindow = NO; } } - (BOOL)setupEAGLContext:(EAGLContext *)context { glGenFramebuffers(1, &_framebuffer); glGenRenderbuffers(1, &_renderbuffer); glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer); glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer); [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer]; glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth); glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _renderbuffer); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { NSLog(@"failed to make complete framebuffer object %x\n", status); return NO; } GLenum glError = glGetError(); if (GL_NO_ERROR != glError) { NSLog(@"failed to setup GL %x\n", glError); return NO; } return YES; } - (CAEAGLLayer *)eaglLayer { return (CAEAGLLayer*) self.layer; } - (BOOL)setupGL { if (_didSetupGL) return YES; CAEAGLLayer *eaglLayer = (CAEAGLLayer*) self.layer; eaglLayer.opaque = YES; eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; _scaleFactor = [[UIScreen mainScreen] scale]; if (_scaleFactor < 0.1f) _scaleFactor = 1.0f; [eaglLayer setContentsScale:_scaleFactor]; _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; if (_context == nil) { NSLog(@"failed to setup EAGLContext\n"); return NO; } EAGLContext *prevContext = [EAGLContext currentContext]; [EAGLContext setCurrentContext:_context]; _didSetupGL = NO; if ([self setupEAGLContext:_context]) { NSLog(@"OK setup GL\n"); _didSetupGL = YES; } [EAGLContext setCurrentContext:prevContext]; return _didSetupGL; } - (BOOL)setupGLOnce { if (_didSetupGL) return YES; if (![self tryLockGLActive]) return NO; BOOL didSetupGL = [self setupGL]; [self unlockGLActive]; return didSetupGL; } - (BOOL)isApplicationActive { switch (_applicationState) { case IJKSDLGLViewApplicationForegroundState: return YES; case IJKSDLGLViewApplicationBackgroundState: return NO; default: { UIApplicationState appState = [UIApplication sharedApplication].applicationState; switch (appState) { case UIApplicationStateActive: return YES; case UIApplicationStateInactive: case UIApplicationStateBackground: default: return NO; } } } } - (void)dealloc { [self lockGLActive]; _didStopGL = YES; EAGLContext *prevContext = [EAGLContext currentContext]; [EAGLContext setCurrentContext:_context]; IJK_GLES2_Renderer_reset(_renderer); IJK_GLES2_Renderer_freeP(&_renderer); if (_framebuffer) { glDeleteFramebuffers(1, &_framebuffer); _framebuffer = 0; } if (_renderbuffer) { glDeleteRenderbuffers(1, &_renderbuffer); _renderbuffer = 0; } glFinish(); [EAGLContext setCurrentContext:prevContext]; _context = nil; [self unregisterApplicationObservers]; [self unlockGLActive]; } - (void)setScaleFactor:(CGFloat)scaleFactor { _scaleFactor = scaleFactor; [self invalidateRenderBuffer]; } - (void)layoutSubviews { [super layoutSubviews]; if (self.window.screen != nil) { _scaleFactor = self.window.screen.scale; } [self invalidateRenderBuffer]; } - (void)setContentMode:(UIViewContentMode)contentMode { [super setContentMode:contentMode]; switch (contentMode) { case UIViewContentModeScaleToFill: _rendererGravity = IJK_GLES2_GRAVITY_RESIZE; break; case UIViewContentModeScaleAspectFit: _rendererGravity = IJK_GLES2_GRAVITY_RESIZE_ASPECT; break; case UIViewContentModeScaleAspectFill: _rendererGravity = IJK_GLES2_GRAVITY_RESIZE_ASPECT_FILL; break; default: _rendererGravity = IJK_GLES2_GRAVITY_RESIZE_ASPECT; break; } [self invalidateRenderBuffer]; } - (BOOL)setupRenderer: (SDL_VoutOverlay *) overlay { if (overlay == nil) return _renderer != nil; if (!IJK_GLES2_Renderer_isValid(_renderer) || !IJK_GLES2_Renderer_isFormat(_renderer, overlay->format)) { IJK_GLES2_Renderer_reset(_renderer); IJK_GLES2_Renderer_freeP(&_renderer); _renderer = IJK_GLES2_Renderer_create(overlay); if (!IJK_GLES2_Renderer_isValid(_renderer)) return NO; if (!IJK_GLES2_Renderer_use(_renderer)) return NO; IJK_GLES2_Renderer_setGravity(_renderer, _rendererGravity, _backingWidth, _backingHeight); } return YES; } - (void)invalidateRenderBuffer { NSLog(@"invalidateRenderBuffer\n"); [self lockGLActive]; _isRenderBufferInvalidated = YES; if ([[NSThread currentThread] isMainThread]) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ if (_isRenderBufferInvalidated) [self display:nil]; }); } else { [self display:nil]; } [self unlockGLActive]; } - (void) display_pixels: (IJKOverlay *) overlay { return; } - (void)display: (SDL_VoutOverlay *) overlay { if (_didSetupGL == NO) return; if ([self isApplicationActive] == NO) return; if (![self tryLockGLActive]) { if (0 == (_tryLockErrorCount % 100)) { NSLog(@"IJKSDLGLView:display: unable to tryLock GL active: %d\n", _tryLockErrorCount); } _tryLockErrorCount++; return; } _tryLockErrorCount = 0; if (_context && !_didStopGL) { EAGLContext *prevContext = [EAGLContext currentContext]; [EAGLContext setCurrentContext:_context]; [self displayInternal:overlay]; [EAGLContext setCurrentContext:prevContext]; } [self unlockGLActive]; } // NOTE: overlay could be NULl - (void)displayInternal: (SDL_VoutOverlay *) overlay { if (![self setupRenderer:overlay]) { if (!overlay && !_renderer) { NSLog(@"IJKSDLGLView: setupDisplay not ready\n"); } else { NSLog(@"IJKSDLGLView: setupDisplay failed\n"); } return; } [[self eaglLayer] setContentsScale:_scaleFactor]; if (_isRenderBufferInvalidated) { NSLog(@"IJKSDLGLView: renderbufferStorage fromDrawable\n"); _isRenderBufferInvalidated = NO; glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer); [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer]; glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth); glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight); IJK_GLES2_Renderer_setGravity(_renderer, _rendererGravity, _backingWidth, _backingHeight); } glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer); glViewport(0, 0, _backingWidth, _backingHeight); if (!IJK_GLES2_Renderer_renderOverlay(_renderer, overlay)) ALOGE("[EGL] IJK_GLES2_render failed\n"); glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer); [_context presentRenderbuffer:GL_RENDERBUFFER]; int64_t current = (int64_t)SDL_GetTickHR(); int64_t delta = (current > _lastFrameTime) ? current - _lastFrameTime : 0; if (delta <= 0) { _lastFrameTime = current; } else if (delta >= 1000) { _fps = ((CGFloat)_frameCount) * 1000 / delta; _frameCount = 0; _lastFrameTime = current; } else { _frameCount++; } } #pragma mark AppDelegate - (void) lockGLActive { [self.glActiveLock lock]; } - (void) unlockGLActive { [self.glActiveLock unlock]; } - (BOOL) tryLockGLActive { if (![self.glActiveLock tryLock]) return NO; /*- if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive && [UIApplication sharedApplication].applicationState != UIApplicationStateInactive) { [self.appLock unlock]; return NO; } */ if (self.glActivePaused) { [self.glActiveLock unlock]; return NO; } return YES; } - (void)toggleGLPaused:(BOOL)paused { [self lockGLActive]; if (!self.glActivePaused && paused) { if (_context != nil) { EAGLContext *prevContext = [EAGLContext currentContext]; [EAGLContext setCurrentContext:_context]; glFinish(); [EAGLContext setCurrentContext:prevContext]; } } self.glActivePaused = paused; [self unlockGLActive]; } - (void)registerApplicationObservers { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil]; [_registeredNotifications addObject:UIApplicationWillEnterForegroundNotification]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil]; [_registeredNotifications addObject:UIApplicationDidBecomeActiveNotification]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive) name:UIApplicationWillResignActiveNotification object:nil]; [_registeredNotifications addObject:UIApplicationWillResignActiveNotification]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil]; [_registeredNotifications addObject:UIApplicationDidEnterBackgroundNotification]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate) name:UIApplicationWillTerminateNotification object:nil]; [_registeredNotifications addObject:UIApplicationWillTerminateNotification]; } - (void)unregisterApplicationObservers { for (NSString *name in _registeredNotifications) { [[NSNotificationCenter defaultCenter] removeObserver:self name:name object:nil]; } } - (void)applicationWillEnterForeground { NSLog(@"IJKSDLGLView:applicationWillEnterForeground: %d", (int)[UIApplication sharedApplication].applicationState); [self setupGLOnce]; _applicationState = IJKSDLGLViewApplicationForegroundState; [self toggleGLPaused:NO]; } - (void)applicationDidBecomeActive { NSLog(@"IJKSDLGLView:applicationDidBecomeActive: %d", (int)[UIApplication sharedApplication].applicationState); [self setupGLOnce]; [self toggleGLPaused:NO]; } - (void)applicationWillResignActive { NSLog(@"IJKSDLGLView:applicationWillResignActive: %d", (int)[UIApplication sharedApplication].applicationState); [self toggleGLPaused:YES]; glFinish(); } - (void)applicationDidEnterBackground { NSLog(@"IJKSDLGLView:applicationDidEnterBackground: %d", (int)[UIApplication sharedApplication].applicationState); _applicationState = IJKSDLGLViewApplicationBackgroundState; [self toggleGLPaused:YES]; glFinish(); } - (void)applicationWillTerminate { NSLog(@"IJKSDLGLView:applicationWillTerminate: %d", (int)[UIApplication sharedApplication].applicationState); [self toggleGLPaused:YES]; } #pragma mark snapshot - (UIImage*)snapshot { [self lockGLActive]; UIImage *image = [self snapshotInternal]; [self unlockGLActive]; return image; } - (UIImage*)snapshotInternal { if (isIOS7OrLater()) { return [self snapshotInternalOnIOS7AndLater]; } else { return [self snapshotInternalOnIOS6AndBefore]; } } - (UIImage*)snapshotInternalOnIOS7AndLater { if (CGSizeEqualToSize(self.bounds.size, CGSizeZero)) { return nil; } UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0); // Render our snapshot into the image context [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:NO]; // Grab the image from the context UIImage *complexViewImage = UIGraphicsGetImageFromCurrentImageContext(); // Finish using the context UIGraphicsEndImageContext(); return complexViewImage; } - (UIImage*)snapshotInternalOnIOS6AndBefore { EAGLContext *prevContext = [EAGLContext currentContext]; [EAGLContext setCurrentContext:_context]; GLint backingWidth, backingHeight; // Bind the color renderbuffer used to render the OpenGL ES view // If your application only creates a single color renderbuffer which is already bound at this point, // this call is redundant, but it is needed if you're dealing with multiple renderbuffers. // Note, replace "viewRenderbuffer" with the actual name of the renderbuffer object defined in your class. glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer); // Get the size of the backing CAEAGLLayer glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth); glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight); NSInteger x = 0, y = 0, width = backingWidth, height = backingHeight; NSInteger dataLength = width * height * 4; GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte)); // Read pixel data from the framebuffer glPixelStorei(GL_PACK_ALIGNMENT, 4); glReadPixels((int)x, (int)y, (int)width, (int)height, GL_RGBA, GL_UNSIGNED_BYTE, data); // Create a CGImage with the pixel data // If your OpenGL ES content is opaque, use kCGImageAlphaNoneSkipLast to ignore the alpha channel // otherwise, use kCGImageAlphaPremultipliedLast CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, data, dataLength, NULL); CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); CGImageRef iref = CGImageCreate(width, height, 8, 32, width * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast, ref, NULL, true, kCGRenderingIntentDefault); [EAGLContext setCurrentContext:prevContext]; // OpenGL ES measures data in PIXELS // Create a graphics context with the target size measured in POINTS UIGraphicsBeginImageContext(CGSizeMake(width, height)); CGContextRef cgcontext = UIGraphicsGetCurrentContext(); // UIKit coordinate system is upside down to GL/Quartz coordinate system // Flip the CGImage by rendering it to the flipped bitmap context // The size of the destination area is measured in POINTS CGContextSetBlendMode(cgcontext, kCGBlendModeCopy); CGContextDrawImage(cgcontext, CGRectMake(0.0, 0.0, width, height), iref); // Retrieve the UIImage from the current context UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); // Clean up free(data); CFRelease(ref); CFRelease(colorspace); CGImageRelease(iref); return image; } - (void)setShouldLockWhileBeingMovedToWindow:(BOOL)shouldLockWhileBeingMovedToWindow { _shouldLockWhileBeingMovedToWindow = shouldLockWhileBeingMovedToWindow; } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewCell.h ================================================ // // IJKSDLHudViewCell.h // IJKMediaPlayer // // Created by Zhang Rui on 15/12/14. // Copyright © 2015年 bilibili. All rights reserved. // #import @interface IJKSDLHudViewCell : UITableViewCell - (id)init; - (void)setHudValue:(NSString *)value forKey:(NSString *)key; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewCell.m ================================================ // // IJKSDLHudViewCell.m // IJKMediaPlayer // // Created by Zhang Rui on 15/12/14. // Copyright © 2015年 bilibili. All rights reserved. // #import "IJKSDLHudViewCell.h" #define COLUMN_COUNT 2 #define CELL_MARGIN 8 @interface IJKSDLHudViewCell() @end @implementation IJKSDLHudViewCell { UILabel *_column[COLUMN_COUNT]; } - (id)init { self = [super init]; if (self) { self.backgroundColor = [UIColor clearColor]; self.contentView.backgroundColor = [UIColor clearColor]; for (int i = 0; i < COLUMN_COUNT; ++i) { _column[i] = [[UILabel alloc] init]; _column[i].textColor = [UIColor whiteColor]; _column[i].font = [UIFont fontWithName:@"Menlo" size:9]; _column[i].adjustsFontSizeToFitWidth = YES; _column[i].numberOfLines = 1; _column[i].minimumScaleFactor = 0.5; [self.contentView addSubview:_column[i]]; } } return self; } - (void)setHudValue:(NSString *)value forKey:(NSString *)key { _column[0].text = key; _column[1].text = value; } - (void)layoutSubviews { [super layoutSubviews]; CGRect parentFrame = self.contentView.frame; CGRect newFrame = parentFrame; CGFloat nextX = CELL_MARGIN; newFrame.origin.x = nextX; newFrame.size.width = parentFrame.size.width * 0.3; _column[0].frame = newFrame; nextX = newFrame.origin.x + newFrame.size.width + CELL_MARGIN; newFrame.origin.x = nextX; newFrame.size.width = parentFrame.size.width - nextX - CELL_MARGIN; _column[1].frame = newFrame; } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewController.h ================================================ // // IJKSDLHudViewController.h // IJKMediaPlayer // // Created by Zhang Rui on 15/12/14. // Copyright © 2015年 bilibili. All rights reserved. // #import @interface IJKSDLHudViewController : UITableViewController - (id)init; - (void)setHudValue:(NSString *)value forKey:(NSString *)key; - (void)setRect:(CGRect) rect; @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/IJKSDLHudViewController.m ================================================ // // IJKSDLHudViewController.m // IJKMediaPlayer // // Created by Zhang Rui on 15/12/14. // Copyright © 2015年 bilibili. All rights reserved. // #import "IJKSDLHudViewController.h" #import "IJKSDLHudViewCell.h" @interface HudViewCellData : NSObject @property(nonatomic) NSString *key; @property(nonatomic) NSString *value; @end @implementation HudViewCellData @end @interface IJKSDLHudViewController() @end @implementation IJKSDLHudViewController { NSMutableDictionary *_keyIndexes; NSMutableArray *_hudDataArray; CGRect _rect; } - (id)init { self = [super init]; if (self) { _keyIndexes = [[NSMutableDictionary alloc] init]; _hudDataArray = [[NSMutableArray alloc] init]; self.tableView.backgroundColor = [[UIColor alloc] initWithRed:.5f green:.5f blue:.5f alpha:.5f]; self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; } return self; } - (void)setHudValue:(NSString *)value forKey:(NSString *)key { HudViewCellData *data = nil; NSNumber *index = [_keyIndexes objectForKey:key]; if (index == nil) { data = [[HudViewCellData alloc] init]; data.key = key; [_keyIndexes setObject:[NSNumber numberWithUnsignedInteger:_hudDataArray.count] forKey:key]; [_hudDataArray addObject:data]; } else { data = [_hudDataArray objectAtIndex:[index unsignedIntegerValue]]; } data.value = value; [self.tableView reloadData]; } #pragma mark UITableViewDataSource - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { assert(section == 0); return _hudDataArray.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { assert(indexPath.section == 0); IJKSDLHudViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"hud"]; if (cell == nil) { cell = [[IJKSDLHudViewCell alloc] init]; } HudViewCellData *data = [_hudDataArray objectAtIndex:indexPath.item]; [cell setHudValue:data.value forKey:data.key]; return cell; } - (void)setRect:(CGRect) rect { _rect = rect; } - (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; CGRect selfFrame = _rect; CGRect newFrame = selfFrame; newFrame.size.width = selfFrame.size.width * 1 / 3; newFrame.origin.x = selfFrame.size.width * 2 / 3; newFrame.size.height = selfFrame.size.height * 8 / 8; newFrame.origin.y += selfFrame.size.height * 0 / 8; self.tableView.frame = newFrame; } #pragma mark UITableViewDelegate - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 16.f; } @end ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_aout_ios_audiounit.h ================================================ /* * ijksdl_aout_ios_audiounit.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl/ijksdl_aout.h" SDL_Aout *SDL_AoutIos_CreateForAudioUnit(); ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_aout_ios_audiounit.m ================================================ /* * ijksdl_aout_ios_audiounit.m * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_aout_ios_audiounit.h" #include #include #include "ijksdl/ijksdl_inc_internal.h" #include "ijksdl/ijksdl_thread.h" #include "ijksdl/ijksdl_aout_internal.h" #import "IJKSDLAudioUnitController.h" #import "IJKSDLAudioQueueController.h" #define SDL_IOS_AUDIO_MAX_CALLBACKS_PER_SEC 15 struct SDL_Aout_Opaque { IJKSDLAudioQueueController *aoutController; }; static int aout_open_audio(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained) { assert(desired); SDLTRACE("aout_open_audio()\n"); SDL_Aout_Opaque *opaque = aout->opaque; opaque->aoutController = [[IJKSDLAudioQueueController alloc] initWithAudioSpec:desired]; if (!opaque->aoutController) { ALOGE("aout_open_audio_n: failed to new AudioTrcak()\n"); return -1; } if (obtained) *obtained = opaque->aoutController.spec; return 0; } static void aout_pause_audio(SDL_Aout *aout, int pause_on) { SDLTRACE("aout_pause_audio(%d)\n", pause_on); SDL_Aout_Opaque *opaque = aout->opaque; if (pause_on) { [opaque->aoutController pause]; } else { [opaque->aoutController play]; } } static void aout_flush_audio(SDL_Aout *aout) { SDLTRACE("aout_flush_audio()\n"); SDL_Aout_Opaque *opaque = aout->opaque; [opaque->aoutController flush]; } static void aout_close_audio(SDL_Aout *aout) { SDLTRACE("aout_close_audio()\n"); SDL_Aout_Opaque *opaque = aout->opaque; [opaque->aoutController close]; } static void aout_set_playback_rate(SDL_Aout *aout, float playbackRate) { SDLTRACE("aout_close_audio()\n"); SDL_Aout_Opaque *opaque = aout->opaque; [opaque->aoutController setPlaybackRate:playbackRate]; } static void aout_set_playback_volume(SDL_Aout *aout, float volume) { SDLTRACE("aout_set_volume()\n"); SDL_Aout_Opaque *opaque = aout->opaque; [opaque->aoutController setPlaybackVolume:volume]; } static double auout_get_latency_seconds(SDL_Aout *aout) { SDL_Aout_Opaque *opaque = aout->opaque; return [opaque->aoutController get_latency_seconds]; } static int aout_get_persecond_callbacks(SDL_Aout *aout) { return SDL_IOS_AUDIO_MAX_CALLBACKS_PER_SEC; } static void aout_free_l(SDL_Aout *aout) { if (!aout) return; aout_close_audio(aout); SDL_Aout_Opaque *opaque = aout->opaque; if (opaque) { [opaque->aoutController release]; opaque->aoutController = nil; } SDL_Aout_FreeInternal(aout); } SDL_Aout *SDL_AoutIos_CreateForAudioUnit() { SDL_Aout *aout = SDL_Aout_CreateInternal(sizeof(SDL_Aout_Opaque)); if (!aout) return NULL; // SDL_Aout_Opaque *opaque = aout->opaque; aout->free_l = aout_free_l; aout->open_audio = aout_open_audio; aout->pause_audio = aout_pause_audio; aout->flush_audio = aout_flush_audio; aout->close_audio = aout_close_audio; aout->func_set_playback_rate = aout_set_playback_rate; aout->func_set_playback_volume = aout_set_playback_volume; aout->func_get_latency_seconds = auout_get_latency_seconds; aout->func_get_audio_persecond_callbacks = aout_get_persecond_callbacks; return aout; } ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_ios.h ================================================ /* * ijksdl_ios.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl/ijksdl.h" #include "ijksdl_aout_ios_audiounit.h" #include "ijksdl_vout_ios_gles2.h" #import #define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) #define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) #define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) #define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending) inline static BOOL isIOS9OrLater() { return SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"9.0"); } inline static BOOL isIOS8OrLater() { return SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0"); } inline static BOOL isIOS7OrLater() { return SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"); } inline static BOOL isIOS6OrLater() { return SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"6.0"); } ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_thread_ios.h ================================================ /* * ijksdl_thread_ios.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_thread_ios.m ================================================ /* * ijksdl_thread_ios.m * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "ijksdl_thread_ios.h" #include "ijksdl/ijksdl_thread.h" static void *SDL_RunThread(void *data) { @autoreleasepool { SDL_Thread *thread = data; pthread_setname_np(thread->name); thread->retval = thread->func(thread->data); return NULL; } } SDL_Thread *SDL_CreateThreadEx(SDL_Thread *thread, int (*fn)(void *), void *data, const char *name) { thread->func = fn; thread->data = data; strlcpy(thread->name, name, sizeof(thread->name) - 1); int retval = pthread_create(&thread->id, NULL, SDL_RunThread, thread); if (retval) return NULL; return thread; } ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_vout_ios_gles2.h ================================================ /* * ijksdl_vout_ios_gles2.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl/ijksdl_stdinc.h" #include "ijksdl/ijksdl_vout.h" @class IJKSDLGLView; SDL_Vout *SDL_VoutIos_CreateForGLES2(); void SDL_VoutIos_SetGLView(SDL_Vout *vout, IJKSDLGLView *view); ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_vout_ios_gles2.m ================================================ /* * ijksdl_vout_ios_gles2.c * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import "ijksdl_vout_ios_gles2.h" #include #include "ijksdl/ijksdl_vout.h" #include "ijksdl/ijksdl_vout_internal.h" #include "ijksdl/ffmpeg/ijksdl_vout_overlay_ffmpeg.h" #include "ijksdl_vout_overlay_videotoolbox.h" #import "IJKSDLGLView.h" typedef struct SDL_VoutSurface_Opaque { SDL_Vout *vout; } SDL_VoutSurface_Opaque; struct SDL_Vout_Opaque { IJKSDLGLView *gl_view; }; static SDL_VoutOverlay *vout_create_overlay_l(int width, int height, int frame_format, SDL_Vout *vout) { switch (frame_format) { case IJK_AV_PIX_FMT__VIDEO_TOOLBOX: return SDL_VoutVideoToolBox_CreateOverlay(width, height, vout); default: return SDL_VoutFFmpeg_CreateOverlay(width, height, frame_format, vout); } } static SDL_VoutOverlay *vout_create_overlay(int width, int height, int frame_format, SDL_Vout *vout) { SDL_LockMutex(vout->mutex); SDL_VoutOverlay *overlay = vout_create_overlay_l(width, height, frame_format, vout); SDL_UnlockMutex(vout->mutex); return overlay; } static void vout_free_l(SDL_Vout *vout) { if (!vout) return; SDL_Vout_Opaque *opaque = vout->opaque; if (opaque) { if (opaque->gl_view) { // TODO: post to MainThread? [opaque->gl_view release]; opaque->gl_view = nil; } } SDL_Vout_FreeInternal(vout); } static int vout_display_overlay_l(SDL_Vout *vout, SDL_VoutOverlay *overlay) { SDL_Vout_Opaque *opaque = vout->opaque; IJKSDLGLView *gl_view = opaque->gl_view; if (!gl_view) { ALOGE("vout_display_overlay_l: NULL gl_view\n"); return -1; } if (!overlay) { ALOGE("vout_display_overlay_l: NULL overlay\n"); return -1; } if (overlay->w <= 0 || overlay->h <= 0) { ALOGE("vout_display_overlay_l: invalid overlay dimensions(%d, %d)\n", overlay->w, overlay->h); return -1; } if (gl_view.isThirdGLView) { IJKOverlay ijk_overlay; ijk_overlay.w = overlay->w; ijk_overlay.h = overlay->h; ijk_overlay.format = overlay->format; ijk_overlay.planes = overlay->planes; ijk_overlay.pitches = overlay->pitches; ijk_overlay.pixels = overlay->pixels; ijk_overlay.sar_num = overlay->sar_num; ijk_overlay.sar_den = overlay->sar_den; #ifdef __APPLE__ if (ijk_overlay.format == SDL_FCC__VTB) { ijk_overlay.pixel_buffer = SDL_VoutOverlayVideoToolBox_GetCVPixelBufferRef(overlay); } #endif if ([gl_view respondsToSelector:@selector(display_pixels:)]) { [gl_view display_pixels:&ijk_overlay]; } } else { [gl_view display:overlay]; } return 0; } static int vout_display_overlay(SDL_Vout *vout, SDL_VoutOverlay *overlay) { @autoreleasepool { SDL_LockMutex(vout->mutex); int retval = vout_display_overlay_l(vout, overlay); SDL_UnlockMutex(vout->mutex); return retval; } } SDL_Vout *SDL_VoutIos_CreateForGLES2() { SDL_Vout *vout = SDL_Vout_CreateInternal(sizeof(SDL_Vout_Opaque)); if (!vout) return NULL; SDL_Vout_Opaque *opaque = vout->opaque; opaque->gl_view = nil; vout->create_overlay = vout_create_overlay; vout->free_l = vout_free_l; vout->display_overlay = vout_display_overlay; return vout; } static void SDL_VoutIos_SetGLView_l(SDL_Vout *vout, IJKSDLGLView *view) { SDL_Vout_Opaque *opaque = vout->opaque; if (opaque->gl_view == view) return; if (opaque->gl_view) { [opaque->gl_view release]; opaque->gl_view = nil; } if (view) opaque->gl_view = [view retain]; } void SDL_VoutIos_SetGLView(SDL_Vout *vout, IJKSDLGLView *view) { SDL_LockMutex(vout->mutex); SDL_VoutIos_SetGLView_l(vout, view); SDL_UnlockMutex(vout->mutex); } ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_vout_overlay_videotoolbox.h ================================================ /***************************************************************************** * ijksdl_vout_overlay_videotoolbox.h ***************************************************************************** * * copyright (c) 2014 ZhouQuan * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __IJKMediaPlayer__ijksdl_vout_overlay_videotoolbox__ #define __IJKMediaPlayer__ijksdl_vout_overlay_videotoolbox__ #import #include "ijksdl_stdinc.h" #include "ijksdl_vout.h" #include "ijksdl_inc_ffmpeg.h" SDL_VoutOverlay *SDL_VoutVideoToolBox_CreateOverlay(int width, int height, SDL_Vout *vout); CVPixelBufferRef SDL_VoutOverlayVideoToolBox_GetCVPixelBufferRef(SDL_VoutOverlay *overlay); #endif ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios/ijksdl_vout_overlay_videotoolbox.m ================================================ /***************************************************************************** * ijksdl_vout_overlay_videotoolbox.m ***************************************************************************** * * copyright (c) 2014 ZhouQuan * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ijksdl_vout_overlay_videotoolbox.h" #include #include "ijksdl_stdinc.h" #include "ijksdl_mutex.h" #include "ijksdl_vout_internal.h" #include "ijksdl_video.h" struct SDL_VoutOverlay_Opaque { SDL_mutex *mutex; CVPixelBufferRef pixel_buffer; Uint16 pitches[AV_NUM_DATA_POINTERS]; Uint8 *pixels[AV_NUM_DATA_POINTERS]; }; static void func_free_l(SDL_VoutOverlay *overlay) { if (!overlay) return; SDL_VoutOverlay_Opaque *opaque = overlay->opaque; if (!opaque) return; overlay->unref(overlay); if (opaque->mutex) SDL_DestroyMutex(opaque->mutex); SDL_VoutOverlay_FreeInternal(overlay); } static int func_lock(SDL_VoutOverlay *overlay) { SDL_VoutOverlay_Opaque *opaque = overlay->opaque; return SDL_LockMutex(opaque->mutex); } static int func_unlock(SDL_VoutOverlay *overlay) { SDL_VoutOverlay_Opaque *opaque = overlay->opaque; return SDL_UnlockMutex(opaque->mutex); } static void func_unref(SDL_VoutOverlay *overlay) { if (!overlay) { return; } SDL_VoutOverlay_Opaque *opaque = overlay->opaque; if (!opaque) { return; } CVBufferRelease(opaque->pixel_buffer); opaque->pixel_buffer = NULL; overlay->pixels[0] = NULL; overlay->pixels[1] = NULL; return; } static int func_fill_frame(SDL_VoutOverlay *overlay, const AVFrame *frame) { assert(frame->format == IJK_AV_PIX_FMT__VIDEO_TOOLBOX); CVBufferRef pixel_buffer = CVBufferRetain(frame->opaque); SDL_VoutOverlay_Opaque *opaque = overlay->opaque; if (opaque->pixel_buffer != NULL) { CVBufferRelease(opaque->pixel_buffer); } opaque->pixel_buffer = pixel_buffer; overlay->format = SDL_FCC__VTB; overlay->planes = 2; #if 1 if (CVPixelBufferLockBaseAddress(pixel_buffer, 0) != kCVReturnSuccess) { overlay->pixels[0] = NULL; overlay->pixels[1] = NULL; overlay->pitches[0] = 0; overlay->pitches[1] = 0; overlay->w = 0; overlay->h = 0; CVBufferRelease(pixel_buffer); opaque->pixel_buffer = NULL; return -1; } // overlay->pixels[0] = CVPixelBufferGetBaseAddressOfPlane(pixel_buffer, 0); // overlay->pixels[1] = CVPixelBufferGetBaseAddressOfPlane(pixel_buffer, 1); overlay->pixels[0] = NULL; overlay->pixels[1] = NULL; overlay->pitches[0] = CVPixelBufferGetWidthOfPlane(pixel_buffer, 0); overlay->pitches[1] = CVPixelBufferGetWidthOfPlane(pixel_buffer, 1); CVPixelBufferUnlockBaseAddress(pixel_buffer, 0); #else overlay->pixels[0] = NULL; overlay->pixels[1] = NULL; overlay->pitches[0] = 0; overlay->pitches[1] = 0; #endif overlay->is_private = 1; overlay->w = (int)frame->width; overlay->h = (int)frame->height; return 0; } static SDL_Class g_vout_overlay_videotoolbox_class = { .name = "VideoToolboxVoutOverlay", }; static bool check_object(SDL_VoutOverlay* object, const char *func_name) { if (!object || !object->opaque || !object->opaque_class) { ALOGE("%s: invalid pipeline\n", func_name); return false; } if (object->opaque_class != &g_vout_overlay_videotoolbox_class) { ALOGE("%s.%s: unsupported method\n", object->opaque_class->name, func_name); return false; } return true; } CVPixelBufferRef SDL_VoutOverlayVideoToolBox_GetCVPixelBufferRef(SDL_VoutOverlay *overlay) { if (!check_object(overlay, __func__)) return NULL; SDL_VoutOverlay_Opaque *opaque = overlay->opaque; return opaque->pixel_buffer; } SDL_VoutOverlay *SDL_VoutVideoToolBox_CreateOverlay(int width, int height, SDL_Vout *display) { SDLTRACE("SDL_VoutVideoToolBox_CreateOverlay(w=%d, h=%d, fmt=_VTB, dp=%p)\n", width, height, display); SDL_VoutOverlay *overlay = SDL_VoutOverlay_CreateInternal(sizeof(SDL_VoutOverlay_Opaque)); if (!overlay) { ALOGE("overlay allocation failed"); return NULL; } SDL_VoutOverlay_Opaque *opaque = overlay->opaque; overlay->opaque_class = &g_vout_overlay_videotoolbox_class; overlay->format = SDL_FCC__VTB; overlay->w = width; overlay->h = height; overlay->pitches = opaque->pitches; overlay->pixels = opaque->pixels; overlay->is_private = 1; overlay->free_l = func_free_l; overlay->lock = func_lock; overlay->unlock = func_unlock; overlay->unref = func_unref; overlay->func_fill_frame = func_fill_frame; opaque->mutex = SDL_CreateMutex(); return overlay; } ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 33BA6FBF254BC4D7004EB9F2 /* ijklas.c in Sources */ = {isa = PBXBuildFile; fileRef = B4449BD5250095700074CEDC /* ijklas.c */; }; 33BA6FC0254BC4D9004EB9F2 /* ijklas.h in Headers */ = {isa = PBXBuildFile; fileRef = B4449BD4250095700074CEDC /* ijklas.h */; }; 33BA6FC1254BC4DC004EB9F2 /* cJSON.c in Sources */ = {isa = PBXBuildFile; fileRef = B417F8E124F7C56C00D159BB /* cJSON.c */; }; 33BA6FC2254BC4DE004EB9F2 /* cJSON.h in Headers */ = {isa = PBXBuildFile; fileRef = B417F8DB24F7C3B400D159BB /* cJSON.h */; }; 4D32BC811F906E3A00CE9F03 /* IJKSDLGLViewProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D32BC801F906E3600CE9F03 /* IJKSDLGLViewProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4D32BC821F906E3B00CE9F03 /* IJKSDLGLViewProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D32BC801F906E3600CE9F03 /* IJKSDLGLViewProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4DA7F6891F2B1E270032A499 /* ijkiourlhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 4DA7F6881F2B1E270032A499 /* ijkiourlhook.c */; }; 4DA7F68A1F2B1E270032A499 /* ijkiourlhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 4DA7F6881F2B1E270032A499 /* ijkiourlhook.c */; }; 5407EC291DF7F93B00457BFE /* IJKVideoToolBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 5407EC271DF7F93B00457BFE /* IJKVideoToolBox.h */; }; 5407EC2A1DF7F93B00457BFE /* IJKVideoToolBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 5407EC281DF7F93B00457BFE /* IJKVideoToolBox.m */; }; 5407EC2D1DF81D2600457BFE /* IJKVideoToolBoxSync.h in Headers */ = {isa = PBXBuildFile; fileRef = 5407EC2B1DF81D2600457BFE /* IJKVideoToolBoxSync.h */; }; 5407EC2E1DF81D2600457BFE /* IJKVideoToolBoxSync.m in Sources */ = {isa = PBXBuildFile; fileRef = 5407EC2C1DF81D2600457BFE /* IJKVideoToolBoxSync.m */; }; 5450AFC41E63EA4300568494 /* IJKKVOController.m in Sources */ = {isa = PBXBuildFile; fileRef = E65DC3B819D93D5F004F8A08 /* IJKKVOController.m */; }; 5450AFC51E63EA4300568494 /* ijksdl_vout.c in Sources */ = {isa = PBXBuildFile; fileRef = E690401117EAFC6100CFD954 /* ijksdl_vout.c */; }; 5450AFC61E63EA4300568494 /* yuv444p10le.fsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598A1C7030B6004831EC /* yuv444p10le.fsh.c */; }; 5450AFC71E63EA4300568494 /* allformats.c in Sources */ = {isa = PBXBuildFile; fileRef = E69BE54A1B93FED300AFBA3F /* allformats.c */; }; 5450AFC81E63EA4300568494 /* ffpipenode_ffplay_vdec.c in Sources */ = {isa = PBXBuildFile; fileRef = E67B91B41A3801E600717EA9 /* ffpipenode_ffplay_vdec.c */; }; 5450AFC91E63EA4300568494 /* renderer_yuv420p.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598D1C7030B6004831EC /* renderer_yuv420p.c */; }; 5450AFCA1E63EA4300568494 /* ijkthreadpool.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A431E15287D00309DD5 /* ijkthreadpool.c */; }; 5450AFCB1E63EA4300568494 /* IJKAVMoviePlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = E67C4E0719D15EEA00415CEE /* IJKAVMoviePlayerController.m */; }; 5450AFCC1E63EA4300568494 /* IJKFFMoviePlayerDef.m in Sources */ = {isa = PBXBuildFile; fileRef = E6F727BA17F2D9D30043623F /* IJKFFMoviePlayerDef.m */; }; 5450AFCD1E63EA4300568494 /* ijkplayer_ios.m in Sources */ = {isa = PBXBuildFile; fileRef = E66F8E0117EFEEA400354D80 /* ijkplayer_ios.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 5450AFCE1E63EA4300568494 /* ffpipeline_ios.c in Sources */ = {isa = PBXBuildFile; fileRef = 454316201A66493700676070 /* ffpipeline_ios.c */; }; 5450AFCF1E63EA4300568494 /* ijkioprotocol.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A301E1526F800309DD5 /* ijkioprotocol.c */; }; 5450AFD01E63EA4300568494 /* ijksdl_vout_dummy.c in Sources */ = {isa = PBXBuildFile; fileRef = E63FC27417F013DE003551EB /* ijksdl_vout_dummy.c */; }; 5450AFD11E63EA4300568494 /* renderer_yuv420sp.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459CA1C70967F004831EC /* renderer_yuv420sp.c */; }; 5450AFD21E63EA4300568494 /* yuv420p.fsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459891C7030B6004831EC /* yuv420p.fsh.c */; }; 5450AFD31E63EA4300568494 /* ijksdl_error.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400417EAFC6100CFD954 /* ijksdl_error.c */; }; 5450AFD41E63EA4300568494 /* IJKDeviceModel.m in Sources */ = {isa = PBXBuildFile; fileRef = E607FFDF1B7B60F9005F11A6 /* IJKDeviceModel.m */; }; 5450AFD51E63EA4300568494 /* ijkiocache.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A2C1E1526F800309DD5 /* ijkiocache.c */; }; 5450AFD61E63EA4300568494 /* ijksdl_egl.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459B81C706A13004831EC /* ijksdl_egl.c */; }; 5450AFD71E63EA4300568494 /* ijkio.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A291E1526F800309DD5 /* ijkio.c */; }; 5450AFD81E63EA4300568494 /* IJKAudioKit.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92A2187810C5009EAB56 /* IJKAudioKit.m */; }; 5450AFD91E63EA4300568494 /* IJKMPMoviePlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = E66F8DC017EEC65200354D80 /* IJKMPMoviePlayerController.m */; }; 5450AFDA1E63EA4300568494 /* IJKSDLHudViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E68B7ACE1C1E97B0001DE241 /* IJKSDLHudViewCell.m */; }; 5450AFDB1E63EA4300568494 /* ijksdl_vout_overlay_videotoolbox.m in Sources */ = {isa = PBXBuildFile; fileRef = 45DB4AA81A5D52AE005CAD41 /* ijksdl_vout_overlay_videotoolbox.m */; }; 5450AFDC1E63EA4300568494 /* ff_ffpipenode.c in Sources */ = {isa = PBXBuildFile; fileRef = E67B91AD1A3801DB00717EA9 /* ff_ffpipenode.c */; }; 5450AFDD1E63EA4300568494 /* ijksdl_stdinc.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400A17EAFC6100CFD954 /* ijksdl_stdinc.c */; }; 5450AFDE1E63EA4300568494 /* IJKVideoToolBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 5407EC281DF7F93B00457BFE /* IJKVideoToolBox.m */; }; 5450AFDF1E63EA4300568494 /* ijksegment.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A029B41D4700E6001C61C1 /* ijksegment.c */; }; 5450AFE01E63EA4300568494 /* IJKMediaUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = E6716E4A1807E5FC00B3FBC1 /* IJKMediaUtils.m */; }; 5450AFE11E63EA4300568494 /* common.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459871C7030B6004831EC /* common.c */; }; 5450AFE21E63EA4300568494 /* ijksdl_aout_ios_audiounit.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92A71878230C009EAB56 /* ijksdl_aout_ios_audiounit.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 5450AFE31E63EA4300568494 /* ijklivehook.c in Sources */ = {isa = PBXBuildFile; fileRef = E69BE5701B946FF600AFBA3F /* ijklivehook.c */; }; 5450AFE41E63EA4300568494 /* ijkurlhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A029B51D4700E6001C61C1 /* ijkurlhook.c */; }; 5450AFE51E63EA4300568494 /* IJKVideoToolBoxSync.m in Sources */ = {isa = PBXBuildFile; fileRef = 5407EC2C1DF81D2600457BFE /* IJKVideoToolBoxSync.m */; }; 5450AFE61E63EA4300568494 /* IJKMediaPlayback.m in Sources */ = {isa = PBXBuildFile; fileRef = E6F727C117F7C9B90043623F /* IJKMediaPlayback.m */; }; 5450AFE71E63EA4300568494 /* ijkdict.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A3D1E15287D00309DD5 /* ijkdict.c */; settings = {COMPILER_FLAGS = "-w"; }; }; 5450AFE81E63EA4300568494 /* ff_ffpipeline.c in Sources */ = {isa = PBXBuildFile; fileRef = E67B91AB1A3801DB00717EA9 /* ff_ffpipeline.c */; }; 5450AFE91E63EA4300568494 /* IJKSDLAudioKit.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92C718782770009EAB56 /* IJKSDLAudioKit.m */; }; 5450AFEA1E63EA4300568494 /* mvp.vsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459911C7030B6004831EC /* mvp.vsh.c */; }; 5450AFEB1E63EA4300568494 /* NSString+IJKMedia.m in Sources */ = {isa = PBXBuildFile; fileRef = E698089A1C7EB13A0048A46C /* NSString+IJKMedia.m */; }; 5450AFEC1E63EA4300568494 /* ijksdl_vout_overlay_ffmpeg.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FFB17EAFC6100CFD954 /* ijksdl_vout_overlay_ffmpeg.c */; }; 5450AFED1E63EA4300568494 /* ijksdl_mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400817EAFC6100CFD954 /* ijksdl_mutex.c */; }; 5450AFEE1E63EA4300568494 /* ijktree.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A451E15287D00309DD5 /* ijktree.c */; }; 5450AFEF1E63EA4300568494 /* IJKSDLAudioQueueController.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92C11878236A009EAB56 /* IJKSDLAudioQueueController.m */; }; 5450AFF01E63EA4300568494 /* ijksdl_thread.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400C17EAFC6100CFD954 /* ijksdl_thread.c */; }; 5450AFF11E63EA4300568494 /* yuv420sp.fsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459C61C7095E5004831EC /* yuv420sp.fsh.c */; }; 5450AFF21E63EA4300568494 /* ff_ffplay.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FDB17EAFC6100CFD954 /* ff_ffplay.c */; }; 5450AFF31E63EA4300568494 /* ijksdl_aout.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FFF17EAFC6100CFD954 /* ijksdl_aout.c */; }; 5450AFF41E63EA4300568494 /* color.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459861C7030B6004831EC /* color.c */; }; 5450AFF51E63EA4300568494 /* ijksdl_audio.c in Sources */ = {isa = PBXBuildFile; fileRef = E63FC27017F01143003551EB /* ijksdl_audio.c */; }; 5450AFF61E63EA4300568494 /* ijksdl_thread_ios.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92AA1878230C009EAB56 /* ijksdl_thread_ios.m */; }; 5450AFF71E63EA4300568494 /* ijkmeta.c in Sources */ = {isa = PBXBuildFile; fileRef = E6FAD9551A515CE300725002 /* ijkmeta.c */; }; 5450AFF81E63EA4300568494 /* ijkasync.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A029B11D4700E6001C61C1 /* ijkasync.c */; }; 5450AFF91E63EA4300568494 /* renderer_yuv420sp_vtb.m in Sources */ = {isa = PBXBuildFile; fileRef = E6E1B9A71C741F72000C6C72 /* renderer_yuv420sp_vtb.m */; }; 5450AFFA1E63EA4300568494 /* ijkutils.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A471E15287D00309DD5 /* ijkutils.c */; }; 5450AFFB1E63EA4300568494 /* IJKSDLGLView.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92B71878230C009EAB56 /* IJKSDLGLView.m */; }; 5450AFFC1E63EA4300568494 /* ijksdl_timer.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400E17EAFC6100CFD954 /* ijksdl_timer.c */; }; 5450AFFD1E63EA4300568494 /* ijkfifo.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A3F1E15287D00309DD5 /* ijkfifo.c */; settings = {COMPILER_FLAGS = "-w"; }; }; 5450AFFE1E63EA4300568494 /* shader.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598F1C7030B6004831EC /* shader.c */; }; 5450AFFF1E63EA4300568494 /* ijkioffio.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A2D1E1526F800309DD5 /* ijkioffio.c */; }; 5450B0001E63EA4300568494 /* renderer.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598C1C7030B6004831EC /* renderer.c */; }; 5450B0011E63EA4300568494 /* ijkioapplication.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A2A1E1526F800309DD5 /* ijkioapplication.c */; }; 5450B0021E63EA4300568494 /* ijkiomanager.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A2E1E1526F800309DD5 /* ijkiomanager.c */; }; 5450B0031E63EA4300568494 /* ijkplayer.c in Sources */ = {isa = PBXBuildFile; fileRef = E66F8DEF17EFEA9400354D80 /* ijkplayer.c */; }; 5450B0041E63EA4300568494 /* IJKFFOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = E62139BD180FA89A00553533 /* IJKFFOptions.m */; }; 5450B0051E63EA4300568494 /* IJKSDLAudioUnitController.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92AE1878230C009EAB56 /* IJKSDLAudioUnitController.m */; }; 5450B0061E63EA4300568494 /* IJKFFMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = E6DBD3881C8941EB0058E4FB /* IJKFFMonitor.m */; }; 5450B0071E63EA4300568494 /* IJKFFMoviePlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = E66F8DE617EFD9C300354D80 /* IJKFFMoviePlayerController.m */; }; 5450B0081E63EA4300568494 /* IJKNotificationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E698089F1C7EB2040048A46C /* IJKNotificationManager.m */; }; 5450B0091E63EA4300568494 /* IJKMediaModule.m in Sources */ = {isa = PBXBuildFile; fileRef = E672D6F218D3445100C51FF9 /* IJKMediaModule.m */; }; 5450B00A1E63EA4300568494 /* ff_cmdutils.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FD517EAFC6100CFD954 /* ff_cmdutils.c */; }; 5450B00B1E63EA4300568494 /* IJKVideoToolBoxAsync.m in Sources */ = {isa = PBXBuildFile; fileRef = 4543162A1A66497900676070 /* IJKVideoToolBoxAsync.m */; }; 5450B00C1E63EA4300568494 /* renderer_yuv444p10le.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598E1C7030B6004831EC /* renderer_yuv444p10le.c */; }; 5450B00D1E63EA4300568494 /* ijkstl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A411E15287D00309DD5 /* ijkstl.cpp */; settings = {COMPILER_FLAGS = "-w"; }; }; 5450B00E1E63EA4300568494 /* image_convert.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FF117EAFC6100CFD954 /* image_convert.c */; }; 5450B00F1E63EA4300568494 /* rgb.fsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459C21C708E60004831EC /* rgb.fsh.c */; }; 5450B0101E63EA4300568494 /* ffpipenode_ios_videotoolbox_vdec.m in Sources */ = {isa = PBXBuildFile; fileRef = 454316231A66493700676070 /* ffpipenode_ios_videotoolbox_vdec.m */; }; 5450B0111E63EA4300568494 /* IJKAVPlayerLayerView.m in Sources */ = {isa = PBXBuildFile; fileRef = E67C4E0419D15B3200415CEE /* IJKAVPlayerLayerView.m */; }; 5450B0121E63EA4300568494 /* IJKSDLHudViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E68B7AC41C1E7F20001DE241 /* IJKSDLHudViewController.m */; }; 5450B0131E63EA4300568494 /* ijksdl_vout_ios_gles2.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92AC1878230C009EAB56 /* ijksdl_vout_ios_gles2.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 5450B0141E63EA4300568494 /* ijklongurl.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A029B31D4700E6001C61C1 /* ijklongurl.c */; }; 5450B0151E63EA4300568494 /* renderer_rgb.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459BE1C708CAF004831EC /* renderer_rgb.c */; }; 5450B0161E63EA4300568494 /* ffpipeline_ffplay.c in Sources */ = {isa = PBXBuildFile; fileRef = E67B91B21A3801E600717EA9 /* ffpipeline_ffplay.c */; }; 5450B0181E63EA4300568494 /* libavcodec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6EF1BCE5A750016835A /* libavcodec.a */; }; 5450B0191E63EA4300568494 /* libavfilter.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F01BCE5A750016835A /* libavfilter.a */; }; 5450B01A1E63EA4300568494 /* libavformat.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F11BCE5A750016835A /* libavformat.a */; }; 5450B01B1E63EA4300568494 /* libavutil.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F21BCE5A750016835A /* libavutil.a */; }; 5450B01C1E63EA4300568494 /* libswresample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F31BCE5A750016835A /* libswresample.a */; }; 5450B01D1E63EA4300568494 /* libswscale.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F41BCE5A750016835A /* libswscale.a */; }; 5450B01F1E63EA4300568494 /* IJKFFMonitor.h in Headers */ = {isa = PBXBuildFile; fileRef = E6DBD3871C8941EB0058E4FB /* IJKFFMonitor.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5450B0201E63EA4300568494 /* ijkiourl.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A321E1526F800309DD5 /* ijkiourl.h */; }; 5450B0211E63EA4300568494 /* IJKFFMoviePlayerController.h in Headers */ = {isa = PBXBuildFile; fileRef = E66F8DE517EFD9C300354D80 /* IJKFFMoviePlayerController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5450B0221E63EA4300568494 /* IJKSDLHudViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = E68B7AC31C1E7F20001DE241 /* IJKSDLHudViewController.h */; }; 5450B0231E63EA4300568494 /* IJKFFOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = E62139BC180FA89A00553533 /* IJKFFOptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5450B0241E63EA4300568494 /* ijkutils.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A481E15287D00309DD5 /* ijkutils.h */; }; 5450B0251E63EA4300568494 /* ijkdict.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A3E1E15287D00309DD5 /* ijkdict.h */; }; 5450B0261E63EA4300568494 /* IJKAVMoviePlayerController.h in Headers */ = {isa = PBXBuildFile; fileRef = E67C4E0619D15EEA00415CEE /* IJKAVMoviePlayerController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5450B0271E63EA4300568494 /* ijksdl_gles2.h in Headers */ = {isa = PBXBuildFile; fileRef = E6C459831C7030AA004831EC /* ijksdl_gles2.h */; }; 5450B0281E63EA4300568494 /* ijksdl_egl.h in Headers */ = {isa = PBXBuildFile; fileRef = E6C459B91C706A13004831EC /* ijksdl_egl.h */; }; 5450B0291E63EA4300568494 /* ff_ffplay_options.h in Headers */ = {isa = PBXBuildFile; fileRef = E6C459BC1C7089AB004831EC /* ff_ffplay_options.h */; }; 5450B02B1E63EA4300568494 /* IJKKVOController.h in Headers */ = {isa = PBXBuildFile; fileRef = E65DC3B719D93D5F004F8A08 /* IJKKVOController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5450B02C1E63EA4300568494 /* IJKNotificationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E698089E1C7EB2040048A46C /* IJKNotificationManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5450B02D1E63EA4300568494 /* ijkthreadpool.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A441E15287D00309DD5 /* ijkthreadpool.h */; }; 5450B02E1E63EA4300568494 /* ijkiomanager.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A2F1E1526F800309DD5 /* ijkiomanager.h */; }; 5450B02F1E63EA4300568494 /* ijkstl.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A421E15287D00309DD5 /* ijkstl.h */; }; 5450B0301E63EA4300568494 /* IJKMediaModule.h in Headers */ = {isa = PBXBuildFile; fileRef = E672D6F118D3445100C51FF9 /* IJKMediaModule.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5450B0311E63EA4300568494 /* ijkfifo.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A401E15287D00309DD5 /* ijkfifo.h */; }; 5450B0321E63EA4300568494 /* ijktree.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A461E15287D00309DD5 /* ijktree.h */; }; 5450B0331E63EA4300568494 /* opt.h in Headers */ = {isa = PBXBuildFile; fileRef = E69BE54F1B93FED300AFBA3F /* opt.h */; }; 5450B0341E63EA4300568494 /* ijkioapplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A2B1E1526F800309DD5 /* ijkioapplication.h */; }; 5450B0351E63EA4300568494 /* ijkioprotocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A311E1526F800309DD5 /* ijkioprotocol.h */; }; 5450B0361E63EA4300568494 /* IJKMediaPlayback.h in Headers */ = {isa = PBXBuildFile; fileRef = E6903EC117EAF6C500CFD954 /* IJKMediaPlayback.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5450B0371E63EA4300568494 /* IJKMediaPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = E66F8DC217EECB1E00354D80 /* IJKMediaPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5450B0381E63EA4300568494 /* internal.h in Headers */ = {isa = PBXBuildFile; fileRef = E6C4598B1C7030B6004831EC /* internal.h */; }; 5450B0391E63EA4300568494 /* IJKVideoToolBoxSync.h in Headers */ = {isa = PBXBuildFile; fileRef = 5407EC2B1DF81D2600457BFE /* IJKVideoToolBoxSync.h */; }; 5450B03A1E63EA4300568494 /* IJKMPMoviePlayerController.h in Headers */ = {isa = PBXBuildFile; fileRef = E66F8DBF17EEC65200354D80 /* IJKMPMoviePlayerController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5450B03B1E63EA4300568494 /* ijkavformat.h in Headers */ = {isa = PBXBuildFile; fileRef = 54A029B21D4700E6001C61C1 /* ijkavformat.h */; }; 5450B03C1E63EA4300568494 /* IJKSDLHudViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = E68B7ACD1C1E97B0001DE241 /* IJKSDLHudViewCell.h */; }; 5450B03D1E63EA4300568494 /* IJKVideoToolBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 5407EC271DF7F93B00457BFE /* IJKVideoToolBox.h */; }; 5450B03E1E63EA4300568494 /* NSString+IJKMedia.h in Headers */ = {isa = PBXBuildFile; fileRef = E69808991C7EB13A0048A46C /* NSString+IJKMedia.h */; }; 5450B0451E63EAB700568494 /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5450AF8B1E63E59300568494 /* libcrypto.a */; }; 5450B0461E63EAB700568494 /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5450AF8C1E63E59300568494 /* libssl.a */; }; 5450B0471E63EABC00568494 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5450AF8F1E63E59800568494 /* libz.tbd */; }; 549385C41E640456001AE08D /* IJKMediaFrameworkWithSSL.h in Headers */ = {isa = PBXBuildFile; fileRef = 5450AF9B1E63E65700568494 /* IJKMediaFrameworkWithSSL.h */; settings = {ATTRIBUTES = (Public, ); }; }; 54A029B61D4700E6001C61C1 /* ijkasync.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A029B11D4700E6001C61C1 /* ijkasync.c */; }; 54A029B71D4700E6001C61C1 /* ijkavformat.h in Headers */ = {isa = PBXBuildFile; fileRef = 54A029B21D4700E6001C61C1 /* ijkavformat.h */; }; 54A029B81D4700E6001C61C1 /* ijklongurl.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A029B31D4700E6001C61C1 /* ijklongurl.c */; }; 54A029B91D4700E6001C61C1 /* ijksegment.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A029B41D4700E6001C61C1 /* ijksegment.c */; }; 54A029BA1D4700E6001C61C1 /* ijkurlhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A029B51D4700E6001C61C1 /* ijkurlhook.c */; }; 54CF8A331E1526F800309DD5 /* ijkio.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A291E1526F800309DD5 /* ijkio.c */; }; 54CF8A341E1526F800309DD5 /* ijkioapplication.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A2A1E1526F800309DD5 /* ijkioapplication.c */; }; 54CF8A351E1526F800309DD5 /* ijkioapplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A2B1E1526F800309DD5 /* ijkioapplication.h */; }; 54CF8A361E1526F800309DD5 /* ijkiocache.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A2C1E1526F800309DD5 /* ijkiocache.c */; }; 54CF8A371E1526F800309DD5 /* ijkioffio.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A2D1E1526F800309DD5 /* ijkioffio.c */; }; 54CF8A381E1526F800309DD5 /* ijkiomanager.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A2E1E1526F800309DD5 /* ijkiomanager.c */; }; 54CF8A391E1526F800309DD5 /* ijkiomanager.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A2F1E1526F800309DD5 /* ijkiomanager.h */; }; 54CF8A3A1E1526F800309DD5 /* ijkioprotocol.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A301E1526F800309DD5 /* ijkioprotocol.c */; }; 54CF8A3B1E1526F800309DD5 /* ijkioprotocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A311E1526F800309DD5 /* ijkioprotocol.h */; }; 54CF8A3C1E1526F800309DD5 /* ijkiourl.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A321E1526F800309DD5 /* ijkiourl.h */; }; 54CF8A491E15287D00309DD5 /* ijkdict.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A3D1E15287D00309DD5 /* ijkdict.c */; settings = {COMPILER_FLAGS = "-w"; }; }; 54CF8A4A1E15287D00309DD5 /* ijkdict.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A3E1E15287D00309DD5 /* ijkdict.h */; }; 54CF8A4B1E15287D00309DD5 /* ijkfifo.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A3F1E15287D00309DD5 /* ijkfifo.c */; settings = {COMPILER_FLAGS = "-w"; }; }; 54CF8A4C1E15287D00309DD5 /* ijkfifo.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A401E15287D00309DD5 /* ijkfifo.h */; }; 54CF8A4D1E15287D00309DD5 /* ijkstl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A411E15287D00309DD5 /* ijkstl.cpp */; settings = {COMPILER_FLAGS = "-w"; }; }; 54CF8A4E1E15287D00309DD5 /* ijkstl.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A421E15287D00309DD5 /* ijkstl.h */; }; 54CF8A4F1E15287D00309DD5 /* ijkthreadpool.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A431E15287D00309DD5 /* ijkthreadpool.c */; }; 54CF8A501E15287D00309DD5 /* ijkthreadpool.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A441E15287D00309DD5 /* ijkthreadpool.h */; }; 54CF8A511E15287D00309DD5 /* ijktree.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A451E15287D00309DD5 /* ijktree.c */; }; 54CF8A521E15287D00309DD5 /* ijktree.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A461E15287D00309DD5 /* ijktree.h */; }; 54CF8A531E15287D00309DD5 /* ijkutils.c in Sources */ = {isa = PBXBuildFile; fileRef = 54CF8A471E15287D00309DD5 /* ijkutils.c */; }; 54CF8A541E15287D00309DD5 /* ijkutils.h in Headers */ = {isa = PBXBuildFile; fileRef = 54CF8A481E15287D00309DD5 /* ijkutils.h */; }; B417F8DE24F7C3B500D159BB /* cJSON.h in Headers */ = {isa = PBXBuildFile; fileRef = B417F8DB24F7C3B400D159BB /* cJSON.h */; }; B417F8E224F7C56C00D159BB /* cJSON.c in Sources */ = {isa = PBXBuildFile; fileRef = B417F8E124F7C56C00D159BB /* cJSON.c */; }; B4449BD6250095700074CEDC /* ijklas.h in Headers */ = {isa = PBXBuildFile; fileRef = B4449BD4250095700074CEDC /* ijklas.h */; }; B4449BD7250095700074CEDC /* ijklas.c in Sources */ = {isa = PBXBuildFile; fileRef = B4449BD5250095700074CEDC /* ijklas.c */; }; E607FFE11B7B62E3005F11A6 /* IJKDeviceModel.m in Sources */ = {isa = PBXBuildFile; fileRef = E607FFDF1B7B60F9005F11A6 /* IJKDeviceModel.m */; }; E653C6F61BCE5A750016835A /* libavcodec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6EF1BCE5A750016835A /* libavcodec.a */; }; E653C6F81BCE5A750016835A /* libavfilter.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F01BCE5A750016835A /* libavfilter.a */; }; E653C6FA1BCE5A750016835A /* libavformat.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F11BCE5A750016835A /* libavformat.a */; }; E653C6FC1BCE5A750016835A /* libavutil.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F21BCE5A750016835A /* libavutil.a */; }; E653C6FE1BCE5A750016835A /* libswresample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F31BCE5A750016835A /* libswresample.a */; }; E653C7001BCE5A750016835A /* libswscale.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E653C6F41BCE5A750016835A /* libswscale.a */; }; E654EA8F1B6B27E600B0F2D0 /* IJKMediaFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = E654EA8E1B6B27E600B0F2D0 /* IJKMediaFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; E654EA951B6B27E600B0F2D0 /* IJKMediaFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E654EA8A1B6B27E600B0F2D0 /* IJKMediaFramework.framework */; }; E654EA9C1B6B27E600B0F2D0 /* IJKMediaFrameworkTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E654EA9B1B6B27E600B0F2D0 /* IJKMediaFrameworkTests.m */; }; E654EAA31B6B283700B0F2D0 /* IJKAudioKit.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92A2187810C5009EAB56 /* IJKAudioKit.m */; }; E654EAA41B6B283700B0F2D0 /* IJKMediaModule.m in Sources */ = {isa = PBXBuildFile; fileRef = E672D6F218D3445100C51FF9 /* IJKMediaModule.m */; }; E654EAA51B6B283700B0F2D0 /* IJKMediaPlayback.m in Sources */ = {isa = PBXBuildFile; fileRef = E6F727C117F7C9B90043623F /* IJKMediaPlayback.m */; }; E654EAA61B6B283700B0F2D0 /* IJKMediaUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = E6716E4A1807E5FC00B3FBC1 /* IJKMediaUtils.m */; }; E654EAA71B6B283700B0F2D0 /* IJKKVOController.m in Sources */ = {isa = PBXBuildFile; fileRef = E65DC3B819D93D5F004F8A08 /* IJKKVOController.m */; }; E654EAA81B6B283D00B0F2D0 /* IJKAVPlayerLayerView.m in Sources */ = {isa = PBXBuildFile; fileRef = E67C4E0419D15B3200415CEE /* IJKAVPlayerLayerView.m */; }; E654EAA91B6B283D00B0F2D0 /* IJKAVMoviePlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = E67C4E0719D15EEA00415CEE /* IJKAVMoviePlayerController.m */; }; E654EAAA1B6B284300B0F2D0 /* IJKMPMoviePlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = E66F8DC017EEC65200354D80 /* IJKMPMoviePlayerController.m */; }; E654EAAB1B6B284C00B0F2D0 /* IJKFFMoviePlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = E66F8DE617EFD9C300354D80 /* IJKFFMoviePlayerController.m */; }; E654EAAC1B6B284C00B0F2D0 /* IJKFFMoviePlayerDef.m in Sources */ = {isa = PBXBuildFile; fileRef = E6F727BA17F2D9D30043623F /* IJKFFMoviePlayerDef.m */; }; E654EAAE1B6B284C00B0F2D0 /* IJKFFOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = E62139BD180FA89A00553533 /* IJKFFOptions.m */; }; E654EAAF1B6B285900B0F2D0 /* ff_cmdutils.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FD517EAFC6100CFD954 /* ff_cmdutils.c */; }; E654EAB01B6B285900B0F2D0 /* ff_ffpipeline.c in Sources */ = {isa = PBXBuildFile; fileRef = E67B91AB1A3801DB00717EA9 /* ff_ffpipeline.c */; }; E654EAB11B6B285900B0F2D0 /* ff_ffpipenode.c in Sources */ = {isa = PBXBuildFile; fileRef = E67B91AD1A3801DB00717EA9 /* ff_ffpipenode.c */; }; E654EAB21B6B285900B0F2D0 /* ff_ffplay.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FDB17EAFC6100CFD954 /* ff_ffplay.c */; }; E654EAB31B6B285900B0F2D0 /* ijkmeta.c in Sources */ = {isa = PBXBuildFile; fileRef = E6FAD9551A515CE300725002 /* ijkmeta.c */; }; E654EAB41B6B285900B0F2D0 /* ijkplayer.c in Sources */ = {isa = PBXBuildFile; fileRef = E66F8DEF17EFEA9400354D80 /* ijkplayer.c */; }; E654EAB51B6B286400B0F2D0 /* ffpipeline_ios.c in Sources */ = {isa = PBXBuildFile; fileRef = 454316201A66493700676070 /* ffpipeline_ios.c */; }; E654EAB61B6B286400B0F2D0 /* ffpipenode_ios_videotoolbox_vdec.m in Sources */ = {isa = PBXBuildFile; fileRef = 454316231A66493700676070 /* ffpipenode_ios_videotoolbox_vdec.m */; }; E654EAB81B6B286400B0F2D0 /* IJKVideoToolBoxAsync.m in Sources */ = {isa = PBXBuildFile; fileRef = 4543162A1A66497900676070 /* IJKVideoToolBoxAsync.m */; }; E654EAB91B6B286700B0F2D0 /* ijkplayer_ios.m in Sources */ = {isa = PBXBuildFile; fileRef = E66F8E0117EFEEA400354D80 /* ijkplayer_ios.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; E654EABA1B6B286B00B0F2D0 /* ffpipeline_ffplay.c in Sources */ = {isa = PBXBuildFile; fileRef = E67B91B21A3801E600717EA9 /* ffpipeline_ffplay.c */; }; E654EABB1B6B286B00B0F2D0 /* ffpipenode_ffplay_vdec.c in Sources */ = {isa = PBXBuildFile; fileRef = E67B91B41A3801E600717EA9 /* ffpipenode_ffplay_vdec.c */; }; E654EABD1B6B287000B0F2D0 /* ijksdl_vout_dummy.c in Sources */ = {isa = PBXBuildFile; fileRef = E63FC27417F013DE003551EB /* ijksdl_vout_dummy.c */; }; E654EABE1B6B287400B0F2D0 /* image_convert.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FF117EAFC6100CFD954 /* image_convert.c */; }; E654EABF1B6B287600B0F2D0 /* ijksdl_vout_overlay_ffmpeg.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FFB17EAFC6100CFD954 /* ijksdl_vout_overlay_ffmpeg.c */; }; E654EAC01B6B287E00B0F2D0 /* ijksdl_aout.c in Sources */ = {isa = PBXBuildFile; fileRef = E6903FFF17EAFC6100CFD954 /* ijksdl_aout.c */; }; E654EAC11B6B287E00B0F2D0 /* ijksdl_audio.c in Sources */ = {isa = PBXBuildFile; fileRef = E63FC27017F01143003551EB /* ijksdl_audio.c */; }; E654EAC21B6B287E00B0F2D0 /* ijksdl_error.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400417EAFC6100CFD954 /* ijksdl_error.c */; }; E654EAC31B6B287E00B0F2D0 /* ijksdl_mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400817EAFC6100CFD954 /* ijksdl_mutex.c */; }; E654EAC41B6B287E00B0F2D0 /* ijksdl_stdinc.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400A17EAFC6100CFD954 /* ijksdl_stdinc.c */; }; E654EAC51B6B287E00B0F2D0 /* ijksdl_thread.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400C17EAFC6100CFD954 /* ijksdl_thread.c */; }; E654EAC61B6B287E00B0F2D0 /* ijksdl_timer.c in Sources */ = {isa = PBXBuildFile; fileRef = E690400E17EAFC6100CFD954 /* ijksdl_timer.c */; }; E654EAC71B6B287E00B0F2D0 /* ijksdl_vout.c in Sources */ = {isa = PBXBuildFile; fileRef = E690401117EAFC6100CFD954 /* ijksdl_vout.c */; }; E654EAC81B6B288A00B0F2D0 /* ijksdl_aout_ios_audiounit.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92A71878230C009EAB56 /* ijksdl_aout_ios_audiounit.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; E654EAC91B6B288A00B0F2D0 /* ijksdl_thread_ios.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92AA1878230C009EAB56 /* ijksdl_thread_ios.m */; }; E654EACA1B6B288A00B0F2D0 /* ijksdl_vout_ios_gles2.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92AC1878230C009EAB56 /* ijksdl_vout_ios_gles2.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; E654EACB1B6B288A00B0F2D0 /* ijksdl_vout_overlay_videotoolbox.m in Sources */ = {isa = PBXBuildFile; fileRef = 45DB4AA81A5D52AE005CAD41 /* ijksdl_vout_overlay_videotoolbox.m */; }; E654EACC1B6B288A00B0F2D0 /* IJKSDLAudioKit.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92C718782770009EAB56 /* IJKSDLAudioKit.m */; }; E654EACD1B6B288A00B0F2D0 /* IJKSDLAudioQueueController.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92C11878236A009EAB56 /* IJKSDLAudioQueueController.m */; }; E654EACE1B6B288A00B0F2D0 /* IJKSDLAudioUnitController.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92AE1878230C009EAB56 /* IJKSDLAudioUnitController.m */; }; E654EAD31B6B288A00B0F2D0 /* IJKSDLGLView.m in Sources */ = {isa = PBXBuildFile; fileRef = E6EE92B71878230C009EAB56 /* IJKSDLGLView.m */; }; E654EAE61B6B295200B0F2D0 /* IJKMediaModule.h in Headers */ = {isa = PBXBuildFile; fileRef = E672D6F118D3445100C51FF9 /* IJKMediaModule.h */; settings = {ATTRIBUTES = (Public, ); }; }; E654EAE71B6B295200B0F2D0 /* IJKMediaPlayback.h in Headers */ = {isa = PBXBuildFile; fileRef = E6903EC117EAF6C500CFD954 /* IJKMediaPlayback.h */; settings = {ATTRIBUTES = (Public, ); }; }; E654EAE81B6B295200B0F2D0 /* IJKAVMoviePlayerController.h in Headers */ = {isa = PBXBuildFile; fileRef = E67C4E0619D15EEA00415CEE /* IJKAVMoviePlayerController.h */; settings = {ATTRIBUTES = (Public, ); }; }; E654EAE91B6B295200B0F2D0 /* IJKMPMoviePlayerController.h in Headers */ = {isa = PBXBuildFile; fileRef = E66F8DBF17EEC65200354D80 /* IJKMPMoviePlayerController.h */; settings = {ATTRIBUTES = (Public, ); }; }; E654EAEA1B6B295200B0F2D0 /* IJKFFMoviePlayerController.h in Headers */ = {isa = PBXBuildFile; fileRef = E66F8DE517EFD9C300354D80 /* IJKFFMoviePlayerController.h */; settings = {ATTRIBUTES = (Public, ); }; }; E654EAEC1B6B295200B0F2D0 /* IJKFFOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = E62139BC180FA89A00553533 /* IJKFFOptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; E654EAED1B6B29C100B0F2D0 /* IJKMediaPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = E66F8DC217EECB1E00354D80 /* IJKMediaPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; E68B7AC51C1E7F20001DE241 /* IJKSDLHudViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = E68B7AC31C1E7F20001DE241 /* IJKSDLHudViewController.h */; }; E68B7AC61C1E7F20001DE241 /* IJKSDLHudViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E68B7AC41C1E7F20001DE241 /* IJKSDLHudViewController.m */; }; E68B7ACF1C1E97B0001DE241 /* IJKSDLHudViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = E68B7ACD1C1E97B0001DE241 /* IJKSDLHudViewCell.h */; }; E68B7AD01C1E97B0001DE241 /* IJKSDLHudViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E68B7ACE1C1E97B0001DE241 /* IJKSDLHudViewCell.m */; }; E698089B1C7EB13A0048A46C /* NSString+IJKMedia.h in Headers */ = {isa = PBXBuildFile; fileRef = E69808991C7EB13A0048A46C /* NSString+IJKMedia.h */; }; E698089C1C7EB13A0048A46C /* NSString+IJKMedia.m in Sources */ = {isa = PBXBuildFile; fileRef = E698089A1C7EB13A0048A46C /* NSString+IJKMedia.m */; }; E69808A01C7EB2040048A46C /* IJKNotificationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E698089E1C7EB2040048A46C /* IJKNotificationManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; E69808A11C7EB2040048A46C /* IJKNotificationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E698089F1C7EB2040048A46C /* IJKNotificationManager.m */; }; E69BE5511B93FED300AFBA3F /* allformats.c in Sources */ = {isa = PBXBuildFile; fileRef = E69BE54A1B93FED300AFBA3F /* allformats.c */; }; E69BE5571B93FED300AFBA3F /* opt.h in Headers */ = {isa = PBXBuildFile; fileRef = E69BE54F1B93FED300AFBA3F /* opt.h */; }; E69BE5721B946FF600AFBA3F /* ijklivehook.c in Sources */ = {isa = PBXBuildFile; fileRef = E69BE5701B946FF600AFBA3F /* ijklivehook.c */; }; E6C2E7BE1C92BD3600E59229 /* IJKKVOController.h in Headers */ = {isa = PBXBuildFile; fileRef = E65DC3B719D93D5F004F8A08 /* IJKKVOController.h */; settings = {ATTRIBUTES = (Public, ); }; }; E6C459841C7030AA004831EC /* ijksdl_gles2.h in Headers */ = {isa = PBXBuildFile; fileRef = E6C459831C7030AA004831EC /* ijksdl_gles2.h */; }; E6C459921C7030B6004831EC /* color.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459861C7030B6004831EC /* color.c */; }; E6C459931C7030B6004831EC /* common.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459871C7030B6004831EC /* common.c */; }; E6C459941C7030B6004831EC /* yuv420p.fsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459891C7030B6004831EC /* yuv420p.fsh.c */; }; E6C459951C7030B6004831EC /* yuv444p10le.fsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598A1C7030B6004831EC /* yuv444p10le.fsh.c */; }; E6C459961C7030B6004831EC /* internal.h in Headers */ = {isa = PBXBuildFile; fileRef = E6C4598B1C7030B6004831EC /* internal.h */; }; E6C459971C7030B6004831EC /* renderer.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598C1C7030B6004831EC /* renderer.c */; }; E6C459981C7030B6004831EC /* renderer_yuv420p.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598D1C7030B6004831EC /* renderer_yuv420p.c */; }; E6C459991C7030B6004831EC /* renderer_yuv444p10le.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598E1C7030B6004831EC /* renderer_yuv444p10le.c */; }; E6C4599A1C7030B6004831EC /* shader.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C4598F1C7030B6004831EC /* shader.c */; }; E6C4599B1C7030B6004831EC /* mvp.vsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459911C7030B6004831EC /* mvp.vsh.c */; }; E6C459BA1C706A13004831EC /* ijksdl_egl.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459B81C706A13004831EC /* ijksdl_egl.c */; }; E6C459BB1C706A13004831EC /* ijksdl_egl.h in Headers */ = {isa = PBXBuildFile; fileRef = E6C459B91C706A13004831EC /* ijksdl_egl.h */; }; E6C459BD1C7089AB004831EC /* ff_ffplay_options.h in Headers */ = {isa = PBXBuildFile; fileRef = E6C459BC1C7089AB004831EC /* ff_ffplay_options.h */; }; E6C459C01C708CAF004831EC /* renderer_rgb.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459BE1C708CAF004831EC /* renderer_rgb.c */; }; E6C459C41C708E60004831EC /* rgb.fsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459C21C708E60004831EC /* rgb.fsh.c */; }; E6C459C81C7095E5004831EC /* yuv420sp.fsh.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459C61C7095E5004831EC /* yuv420sp.fsh.c */; }; E6C459CC1C70967F004831EC /* renderer_yuv420sp.c in Sources */ = {isa = PBXBuildFile; fileRef = E6C459CA1C70967F004831EC /* renderer_yuv420sp.c */; }; E6DBD3891C8941EB0058E4FB /* IJKFFMonitor.h in Headers */ = {isa = PBXBuildFile; fileRef = E6DBD3871C8941EB0058E4FB /* IJKFFMonitor.h */; settings = {ATTRIBUTES = (Public, ); }; }; E6DBD38A1C8941EB0058E4FB /* IJKFFMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = E6DBD3881C8941EB0058E4FB /* IJKFFMonitor.m */; }; E6E1B9A81C741F72000C6C72 /* renderer_yuv420sp_vtb.m in Sources */ = {isa = PBXBuildFile; fileRef = E6E1B9A71C741F72000C6C72 /* renderer_yuv420sp_vtb.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ E654EA961B6B27E600B0F2D0 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = E6903EB117EAF6C500CFD954 /* Project object */; proxyType = 1; remoteGlobalIDString = E654EA891B6B27E600B0F2D0; remoteInfo = IJKMediaFramework; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 454316201A66493700676070 /* ffpipeline_ios.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ffpipeline_ios.c; path = ijkmedia/ijkplayer/ios/pipeline/ffpipeline_ios.c; sourceTree = ""; }; 454316211A66493700676070 /* ffpipeline_ios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ffpipeline_ios.h; path = ijkmedia/ijkplayer/ios/pipeline/ffpipeline_ios.h; sourceTree = ""; }; 454316221A66493700676070 /* ffpipenode_ios_videotoolbox_vdec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ffpipenode_ios_videotoolbox_vdec.h; path = ijkmedia/ijkplayer/ios/pipeline/ffpipenode_ios_videotoolbox_vdec.h; sourceTree = ""; }; 454316231A66493700676070 /* ffpipenode_ios_videotoolbox_vdec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ffpipenode_ios_videotoolbox_vdec.m; path = ijkmedia/ijkplayer/ios/pipeline/ffpipenode_ios_videotoolbox_vdec.m; sourceTree = ""; }; 454316291A66497900676070 /* IJKVideoToolBoxAsync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKVideoToolBoxAsync.h; path = ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBoxAsync.h; sourceTree = ""; }; 4543162A1A66497900676070 /* IJKVideoToolBoxAsync.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKVideoToolBoxAsync.m; path = ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBoxAsync.m; sourceTree = ""; }; 45DB4AA71A5D52AE005CAD41 /* ijksdl_vout_overlay_videotoolbox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_vout_overlay_videotoolbox.h; sourceTree = ""; }; 45DB4AA81A5D52AE005CAD41 /* ijksdl_vout_overlay_videotoolbox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ijksdl_vout_overlay_videotoolbox.m; sourceTree = ""; }; 4D32BC801F906E3600CE9F03 /* IJKSDLGLViewProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJKSDLGLViewProtocol.h; sourceTree = ""; }; 4DA7F6881F2B1E270032A499 /* ijkiourlhook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkiourlhook.c; sourceTree = ""; }; 5407EC271DF7F93B00457BFE /* IJKVideoToolBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKVideoToolBox.h; path = ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBox.h; sourceTree = ""; }; 5407EC281DF7F93B00457BFE /* IJKVideoToolBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKVideoToolBox.m; path = ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBox.m; sourceTree = ""; }; 5407EC2B1DF81D2600457BFE /* IJKVideoToolBoxSync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKVideoToolBoxSync.h; path = ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBoxSync.h; sourceTree = ""; }; 5407EC2C1DF81D2600457BFE /* IJKVideoToolBoxSync.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKVideoToolBoxSync.m; path = ijkmedia/ijkplayer/ios/pipeline/IJKVideoToolBoxSync.m; sourceTree = ""; }; 5450AF8B1E63E59300568494 /* libcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcrypto.a; path = "../../../.warehouse/ff3.2--ijk0.7.6--20170203--001/build/universal/lib/libcrypto.a"; sourceTree = ""; }; 5450AF8C1E63E59300568494 /* libssl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libssl.a; path = "../../../.warehouse/ff3.2--ijk0.7.6--20170203--001/build/universal/lib/libssl.a"; sourceTree = ""; }; 5450AF8F1E63E59800568494 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; 5450AF9B1E63E65700568494 /* IJKMediaFrameworkWithSSL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJKMediaFrameworkWithSSL.h; sourceTree = ""; }; 5450B0431E63EA4300568494 /* IJKMediaFrameworkWithSSL.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = IJKMediaFrameworkWithSSL.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 5450B0441E63EA4300568494 /* IJKMediaFrameworkWithSSL.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = IJKMediaFrameworkWithSSL.plist; path = /Users/zhangxinzheng/Documents/bilibili/BiliShell/contrib/ijkplayer/ios/IJKMediaPlayer/IJKMediaFrameworkWithSSL.plist; sourceTree = ""; }; 54A029B11D4700E6001C61C1 /* ijkasync.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkasync.c; sourceTree = ""; }; 54A029B21D4700E6001C61C1 /* ijkavformat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkavformat.h; sourceTree = ""; }; 54A029B31D4700E6001C61C1 /* ijklongurl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijklongurl.c; sourceTree = ""; }; 54A029B41D4700E6001C61C1 /* ijksegment.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksegment.c; sourceTree = ""; }; 54A029B51D4700E6001C61C1 /* ijkurlhook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkurlhook.c; sourceTree = ""; }; 54CF8A291E1526F800309DD5 /* ijkio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkio.c; sourceTree = ""; }; 54CF8A2A1E1526F800309DD5 /* ijkioapplication.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkioapplication.c; sourceTree = ""; }; 54CF8A2B1E1526F800309DD5 /* ijkioapplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkioapplication.h; sourceTree = ""; }; 54CF8A2C1E1526F800309DD5 /* ijkiocache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkiocache.c; sourceTree = ""; }; 54CF8A2D1E1526F800309DD5 /* ijkioffio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkioffio.c; sourceTree = ""; }; 54CF8A2E1E1526F800309DD5 /* ijkiomanager.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkiomanager.c; sourceTree = ""; }; 54CF8A2F1E1526F800309DD5 /* ijkiomanager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkiomanager.h; sourceTree = ""; }; 54CF8A301E1526F800309DD5 /* ijkioprotocol.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkioprotocol.c; sourceTree = ""; }; 54CF8A311E1526F800309DD5 /* ijkioprotocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkioprotocol.h; sourceTree = ""; }; 54CF8A321E1526F800309DD5 /* ijkiourl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkiourl.h; sourceTree = ""; }; 54CF8A3D1E15287D00309DD5 /* ijkdict.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkdict.c; sourceTree = ""; }; 54CF8A3E1E15287D00309DD5 /* ijkdict.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkdict.h; sourceTree = ""; }; 54CF8A3F1E15287D00309DD5 /* ijkfifo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkfifo.c; sourceTree = ""; }; 54CF8A401E15287D00309DD5 /* ijkfifo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkfifo.h; sourceTree = ""; }; 54CF8A411E15287D00309DD5 /* ijkstl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ijkstl.cpp; sourceTree = ""; }; 54CF8A421E15287D00309DD5 /* ijkstl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkstl.h; sourceTree = ""; }; 54CF8A431E15287D00309DD5 /* ijkthreadpool.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkthreadpool.c; sourceTree = ""; }; 54CF8A441E15287D00309DD5 /* ijkthreadpool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkthreadpool.h; sourceTree = ""; }; 54CF8A451E15287D00309DD5 /* ijktree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijktree.c; sourceTree = ""; }; 54CF8A461E15287D00309DD5 /* ijktree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijktree.h; sourceTree = ""; }; 54CF8A471E15287D00309DD5 /* ijkutils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkutils.c; sourceTree = ""; }; 54CF8A481E15287D00309DD5 /* ijkutils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkutils.h; sourceTree = ""; }; B417F8DB24F7C3B400D159BB /* cJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cJSON.h; sourceTree = ""; }; B417F8E124F7C56C00D159BB /* cJSON.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cJSON.c; sourceTree = ""; }; B4449BD4250095700074CEDC /* ijklas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijklas.h; sourceTree = ""; }; B4449BD5250095700074CEDC /* ijklas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijklas.c; sourceTree = ""; }; E607FFDE1B7B60F9005F11A6 /* IJKDeviceModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKDeviceModel.h; path = IJKMediaPlayer/IJKDeviceModel.h; sourceTree = ""; }; E607FFDF1B7B60F9005F11A6 /* IJKDeviceModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKDeviceModel.m; path = IJKMediaPlayer/IJKDeviceModel.m; sourceTree = ""; }; E62139BC180FA89A00553533 /* IJKFFOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKFFOptions.h; sourceTree = ""; }; E62139BD180FA89A00553533 /* IJKFFOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKFFOptions.m; sourceTree = ""; }; E63FC27017F01143003551EB /* ijksdl_audio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_audio.c; sourceTree = ""; }; E63FC27317F013DE003551EB /* ijksdl_dummy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_dummy.h; sourceTree = ""; }; E63FC27417F013DE003551EB /* ijksdl_vout_dummy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_vout_dummy.c; sourceTree = ""; }; E63FC27517F013DE003551EB /* ijksdl_vout_dummy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_vout_dummy.h; sourceTree = ""; }; E653C6EF1BCE5A750016835A /* libavcodec.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libavcodec.a; sourceTree = ""; }; E653C6F01BCE5A750016835A /* libavfilter.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libavfilter.a; sourceTree = ""; }; E653C6F11BCE5A750016835A /* libavformat.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libavformat.a; sourceTree = ""; }; E653C6F21BCE5A750016835A /* libavutil.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libavutil.a; sourceTree = ""; }; E653C6F31BCE5A750016835A /* libswresample.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libswresample.a; sourceTree = ""; }; E653C6F41BCE5A750016835A /* libswscale.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libswscale.a; sourceTree = ""; }; E654EA8A1B6B27E600B0F2D0 /* IJKMediaFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = IJKMediaFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; E654EA8D1B6B27E600B0F2D0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; E654EA8E1B6B27E600B0F2D0 /* IJKMediaFramework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJKMediaFramework.h; sourceTree = ""; }; E654EA941B6B27E600B0F2D0 /* IJKMediaFrameworkTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IJKMediaFrameworkTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; E654EA9A1B6B27E600B0F2D0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; E654EA9B1B6B27E600B0F2D0 /* IJKMediaFrameworkTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJKMediaFrameworkTests.m; sourceTree = ""; }; E65DC3B719D93D5F004F8A08 /* IJKKVOController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKKVOController.h; path = IJKMediaPlayer/IJKKVOController.h; sourceTree = ""; }; E65DC3B819D93D5F004F8A08 /* IJKKVOController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKKVOController.m; path = IJKMediaPlayer/IJKKVOController.m; sourceTree = ""; }; E66F8DBF17EEC65200354D80 /* IJKMPMoviePlayerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKMPMoviePlayerController.h; path = IJKMediaPlayer/IJKMPMoviePlayerController.h; sourceTree = ""; }; E66F8DC017EEC65200354D80 /* IJKMPMoviePlayerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKMPMoviePlayerController.m; path = IJKMediaPlayer/IJKMPMoviePlayerController.m; sourceTree = ""; }; E66F8DC217EECB1E00354D80 /* IJKMediaPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKMediaPlayer.h; path = IJKMediaPlayer/IJKMediaPlayer.h; sourceTree = ""; }; E66F8DE517EFD9C300354D80 /* IJKFFMoviePlayerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKFFMoviePlayerController.h; sourceTree = ""; }; E66F8DE617EFD9C300354D80 /* IJKFFMoviePlayerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKFFMoviePlayerController.m; sourceTree = ""; }; E66F8DEE17EFEA9400354D80 /* ijkplayer_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkplayer_internal.h; sourceTree = ""; }; E66F8DEF17EFEA9400354D80 /* ijkplayer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkplayer.c; sourceTree = ""; }; E66F8DF017EFEA9400354D80 /* ijkplayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkplayer.h; sourceTree = ""; }; E66F8E0117EFEEA400354D80 /* ijkplayer_ios.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ijkplayer_ios.m; path = ijkmedia/ijkplayer/ios/ijkplayer_ios.m; sourceTree = ""; }; E66F8E0217EFEEA400354D80 /* ijkplayer_ios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ijkplayer_ios.h; path = ijkmedia/ijkplayer/ios/ijkplayer_ios.h; sourceTree = ""; }; E6716E491807E5FC00B3FBC1 /* IJKMediaUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKMediaUtils.h; path = IJKMediaPlayer/IJKMediaUtils.h; sourceTree = ""; }; E6716E4A1807E5FC00B3FBC1 /* IJKMediaUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKMediaUtils.m; path = IJKMediaPlayer/IJKMediaUtils.m; sourceTree = ""; }; E672D6F118D3445100C51FF9 /* IJKMediaModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKMediaModule.h; path = IJKMediaPlayer/IJKMediaModule.h; sourceTree = ""; }; E672D6F218D3445100C51FF9 /* IJKMediaModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKMediaModule.m; path = IJKMediaPlayer/IJKMediaModule.m; sourceTree = ""; }; E67B91AB1A3801DB00717EA9 /* ff_ffpipeline.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ff_ffpipeline.c; sourceTree = ""; }; E67B91AC1A3801DB00717EA9 /* ff_ffpipeline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffpipeline.h; sourceTree = ""; }; E67B91AD1A3801DB00717EA9 /* ff_ffpipenode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ff_ffpipenode.c; sourceTree = ""; }; E67B91AE1A3801DB00717EA9 /* ff_ffpipenode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffpipenode.h; sourceTree = ""; }; E67B91B21A3801E600717EA9 /* ffpipeline_ffplay.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffpipeline_ffplay.c; sourceTree = ""; }; E67B91B31A3801E600717EA9 /* ffpipeline_ffplay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffpipeline_ffplay.h; sourceTree = ""; }; E67B91B41A3801E600717EA9 /* ffpipenode_ffplay_vdec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffpipenode_ffplay_vdec.c; sourceTree = ""; }; E67B91B51A3801E600717EA9 /* ffpipenode_ffplay_vdec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffpipenode_ffplay_vdec.h; sourceTree = ""; }; E67C4E0319D15B3200415CEE /* IJKAVPlayerLayerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKAVPlayerLayerView.h; path = IJKMediaPlayer/IJKAVPlayerLayerView.h; sourceTree = ""; }; E67C4E0419D15B3200415CEE /* IJKAVPlayerLayerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKAVPlayerLayerView.m; path = IJKMediaPlayer/IJKAVPlayerLayerView.m; sourceTree = ""; }; E67C4E0619D15EEA00415CEE /* IJKAVMoviePlayerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKAVMoviePlayerController.h; path = IJKMediaPlayer/IJKAVMoviePlayerController.h; sourceTree = ""; }; E67C4E0719D15EEA00415CEE /* IJKAVMoviePlayerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKAVMoviePlayerController.m; path = IJKMediaPlayer/IJKAVMoviePlayerController.m; sourceTree = ""; }; E67FB4AC1B4A766F00AA94AA /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; E68B7AC31C1E7F20001DE241 /* IJKSDLHudViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKSDLHudViewController.h; sourceTree = ""; }; E68B7AC41C1E7F20001DE241 /* IJKSDLHudViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKSDLHudViewController.m; sourceTree = ""; }; E68B7ACD1C1E97B0001DE241 /* IJKSDLHudViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKSDLHudViewCell.h; sourceTree = ""; }; E68B7ACE1C1E97B0001DE241 /* IJKSDLHudViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKSDLHudViewCell.m; sourceTree = ""; }; E6903EC017EAF6C500CFD954 /* IJKMediaPlayer-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "IJKMediaPlayer-Prefix.pch"; sourceTree = ""; }; E6903EC117EAF6C500CFD954 /* IJKMediaPlayback.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IJKMediaPlayback.h; path = IJKMediaPlayer/IJKMediaPlayback.h; sourceTree = ""; }; E6903FD517EAFC6100CFD954 /* ff_cmdutils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ff_cmdutils.c; sourceTree = ""; }; E6903FD617EAFC6100CFD954 /* ff_cmdutils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_cmdutils.h; sourceTree = ""; }; E6903FD717EAFC6100CFD954 /* ff_fferror.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_fferror.h; sourceTree = ""; }; E6903FD817EAFC6100CFD954 /* ff_ffinc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffinc.h; sourceTree = ""; }; E6903FD917EAFC6100CFD954 /* ff_ffmsg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffmsg.h; sourceTree = ""; }; E6903FDA17EAFC6100CFD954 /* ff_ffmsg_queue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffmsg_queue.h; sourceTree = ""; }; E6903FDB17EAFC6100CFD954 /* ff_ffplay.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ff_ffplay.c; sourceTree = ""; }; E6903FDC17EAFC6100CFD954 /* ff_ffplay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffplay.h; sourceTree = ""; }; E6903FDE17EAFC6100CFD954 /* ff_ffplay_def.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffplay_def.h; sourceTree = ""; }; E6903FF117EAFC6100CFD954 /* image_convert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = image_convert.c; sourceTree = ""; }; E6903FF917EAFC6100CFD954 /* ijksdl_image_convert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_image_convert.h; sourceTree = ""; }; E6903FFA17EAFC6100CFD954 /* ijksdl_inc_ffmpeg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_inc_ffmpeg.h; sourceTree = ""; }; E6903FFB17EAFC6100CFD954 /* ijksdl_vout_overlay_ffmpeg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_vout_overlay_ffmpeg.c; sourceTree = ""; }; E6903FFC17EAFC6100CFD954 /* ijksdl_vout_overlay_ffmpeg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_vout_overlay_ffmpeg.h; sourceTree = ""; }; E6903FFD17EAFC6100CFD954 /* ijksdl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl.h; sourceTree = ""; }; E6903FFF17EAFC6100CFD954 /* ijksdl_aout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_aout.c; sourceTree = ""; }; E690400017EAFC6100CFD954 /* ijksdl_aout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_aout.h; sourceTree = ""; }; E690400117EAFC6100CFD954 /* ijksdl_aout_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_aout_internal.h; sourceTree = ""; }; E690400217EAFC6100CFD954 /* ijksdl_audio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_audio.h; sourceTree = ""; }; E690400317EAFC6100CFD954 /* ijksdl_endian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_endian.h; sourceTree = ""; }; E690400417EAFC6100CFD954 /* ijksdl_error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_error.c; sourceTree = ""; }; E690400517EAFC6100CFD954 /* ijksdl_error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_error.h; sourceTree = ""; }; E690400617EAFC6100CFD954 /* ijksdl_fourcc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_fourcc.h; sourceTree = ""; }; E690400717EAFC6100CFD954 /* ijksdl_inc_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_inc_internal.h; sourceTree = ""; }; E690400817EAFC6100CFD954 /* ijksdl_mutex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_mutex.c; sourceTree = ""; }; E690400917EAFC6100CFD954 /* ijksdl_mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_mutex.h; sourceTree = ""; }; E690400A17EAFC6100CFD954 /* ijksdl_stdinc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_stdinc.c; sourceTree = ""; }; E690400B17EAFC6100CFD954 /* ijksdl_stdinc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_stdinc.h; sourceTree = ""; }; E690400C17EAFC6100CFD954 /* ijksdl_thread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_thread.c; sourceTree = ""; }; E690400D17EAFC6100CFD954 /* ijksdl_thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_thread.h; sourceTree = ""; }; E690400E17EAFC6100CFD954 /* ijksdl_timer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_timer.c; sourceTree = ""; }; E690400F17EAFC6100CFD954 /* ijksdl_timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_timer.h; sourceTree = ""; }; E690401017EAFC6100CFD954 /* ijksdl_video.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_video.h; sourceTree = ""; }; E690401117EAFC6100CFD954 /* ijksdl_vout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_vout.c; sourceTree = ""; }; E690401217EAFC6100CFD954 /* ijksdl_vout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_vout.h; sourceTree = ""; }; E690401317EAFC6100CFD954 /* ijksdl_vout_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_vout_internal.h; sourceTree = ""; }; E69808991C7EB13A0048A46C /* NSString+IJKMedia.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSString+IJKMedia.h"; path = "IJKMediaPlayer/NSString+IJKMedia.h"; sourceTree = ""; }; E698089A1C7EB13A0048A46C /* NSString+IJKMedia.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSString+IJKMedia.m"; path = "IJKMediaPlayer/NSString+IJKMedia.m"; sourceTree = ""; }; E698089E1C7EB2040048A46C /* IJKNotificationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKNotificationManager.h; path = IJKMediaPlayer/IJKNotificationManager.h; sourceTree = ""; }; E698089F1C7EB2040048A46C /* IJKNotificationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKNotificationManager.m; path = IJKMediaPlayer/IJKNotificationManager.m; sourceTree = ""; }; E69BE54A1B93FED300AFBA3F /* allformats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = allformats.c; sourceTree = ""; }; E69BE54F1B93FED300AFBA3F /* opt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opt.h; sourceTree = ""; }; E69BE5701B946FF600AFBA3F /* ijklivehook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijklivehook.c; sourceTree = ""; }; E6C2FD391B300A390081D321 /* ff_ffplay_debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffplay_debug.h; sourceTree = ""; }; E6C459831C7030AA004831EC /* ijksdl_gles2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_gles2.h; sourceTree = ""; }; E6C459861C7030B6004831EC /* color.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = color.c; sourceTree = ""; }; E6C459871C7030B6004831EC /* common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = common.c; sourceTree = ""; }; E6C459891C7030B6004831EC /* yuv420p.fsh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = yuv420p.fsh.c; sourceTree = ""; }; E6C4598A1C7030B6004831EC /* yuv444p10le.fsh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = yuv444p10le.fsh.c; sourceTree = ""; }; E6C4598B1C7030B6004831EC /* internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = internal.h; sourceTree = ""; }; E6C4598C1C7030B6004831EC /* renderer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = renderer.c; sourceTree = ""; }; E6C4598D1C7030B6004831EC /* renderer_yuv420p.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = renderer_yuv420p.c; sourceTree = ""; }; E6C4598E1C7030B6004831EC /* renderer_yuv444p10le.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = renderer_yuv444p10le.c; sourceTree = ""; }; E6C4598F1C7030B6004831EC /* shader.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = shader.c; sourceTree = ""; }; E6C459911C7030B6004831EC /* mvp.vsh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mvp.vsh.c; sourceTree = ""; }; E6C459B81C706A13004831EC /* ijksdl_egl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_egl.c; sourceTree = ""; }; E6C459B91C706A13004831EC /* ijksdl_egl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_egl.h; sourceTree = ""; }; E6C459BC1C7089AB004831EC /* ff_ffplay_options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ff_ffplay_options.h; sourceTree = ""; }; E6C459BE1C708CAF004831EC /* renderer_rgb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = renderer_rgb.c; sourceTree = ""; }; E6C459C21C708E60004831EC /* rgb.fsh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rgb.fsh.c; sourceTree = ""; }; E6C459C61C7095E5004831EC /* yuv420sp.fsh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = yuv420sp.fsh.c; sourceTree = ""; }; E6C459CA1C70967F004831EC /* renderer_yuv420sp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = renderer_yuv420sp.c; sourceTree = ""; }; E6CA1EE71B4FAFCF00BCAF89 /* ijksdl_class.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_class.h; sourceTree = ""; }; E6CA1EE81B4FAFCF00BCAF89 /* ijksdl_misc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_misc.h; sourceTree = ""; }; E6CA1EE91B4FB04500BCAF89 /* ijksdl_log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_log.h; sourceTree = ""; }; E6D5FFF71B5F445E00E1E328 /* h264_sps_parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = h264_sps_parser.h; path = ijkmedia/ijkplayer/ios/pipeline/h264_sps_parser.h; sourceTree = ""; }; E6DBD3871C8941EB0058E4FB /* IJKFFMonitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKFFMonitor.h; sourceTree = ""; }; E6DBD3881C8941EB0058E4FB /* IJKFFMonitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKFFMonitor.m; sourceTree = ""; }; E6E1B9A71C741F72000C6C72 /* renderer_yuv420sp_vtb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = renderer_yuv420sp_vtb.m; sourceTree = ""; }; E6EE92A1187810C5009EAB56 /* IJKAudioKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKAudioKit.h; path = IJKMediaPlayer/IJKAudioKit.h; sourceTree = ""; }; E6EE92A2187810C5009EAB56 /* IJKAudioKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKAudioKit.m; path = IJKMediaPlayer/IJKAudioKit.m; sourceTree = ""; }; E6EE92A61878230C009EAB56 /* ijksdl_aout_ios_audiounit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_aout_ios_audiounit.h; sourceTree = ""; }; E6EE92A71878230C009EAB56 /* ijksdl_aout_ios_audiounit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ijksdl_aout_ios_audiounit.m; sourceTree = ""; }; E6EE92A81878230C009EAB56 /* ijksdl_ios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_ios.h; sourceTree = ""; }; E6EE92A91878230C009EAB56 /* ijksdl_thread_ios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_thread_ios.h; sourceTree = ""; }; E6EE92AA1878230C009EAB56 /* ijksdl_thread_ios.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ijksdl_thread_ios.m; sourceTree = ""; }; E6EE92AB1878230C009EAB56 /* ijksdl_vout_ios_gles2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_vout_ios_gles2.h; sourceTree = ""; }; E6EE92AC1878230C009EAB56 /* ijksdl_vout_ios_gles2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ijksdl_vout_ios_gles2.m; sourceTree = ""; }; E6EE92AD1878230C009EAB56 /* IJKSDLAudioUnitController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKSDLAudioUnitController.h; sourceTree = ""; }; E6EE92AE1878230C009EAB56 /* IJKSDLAudioUnitController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKSDLAudioUnitController.m; sourceTree = ""; }; E6EE92B61878230C009EAB56 /* IJKSDLGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKSDLGLView.h; sourceTree = ""; }; E6EE92B71878230C009EAB56 /* IJKSDLGLView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKSDLGLView.m; sourceTree = ""; }; E6EE92C01878236A009EAB56 /* IJKSDLAudioQueueController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKSDLAudioQueueController.h; sourceTree = ""; }; E6EE92C11878236A009EAB56 /* IJKSDLAudioQueueController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKSDLAudioQueueController.m; sourceTree = ""; }; E6EE92C618782770009EAB56 /* IJKSDLAudioKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKSDLAudioKit.h; sourceTree = ""; }; E6EE92C718782770009EAB56 /* IJKSDLAudioKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKSDLAudioKit.m; sourceTree = ""; }; E6F727B917F2D9D30043623F /* IJKFFMoviePlayerDef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IJKFFMoviePlayerDef.h; sourceTree = ""; }; E6F727BA17F2D9D30043623F /* IJKFFMoviePlayerDef.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IJKFFMoviePlayerDef.m; sourceTree = ""; }; E6F727C117F7C9B90043623F /* IJKMediaPlayback.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKMediaPlayback.m; path = IJKMediaPlayer/IJKMediaPlayback.m; sourceTree = ""; }; E6FAD9551A515CE300725002 /* ijkmeta.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijkmeta.c; sourceTree = ""; }; E6FAD9561A515CE300725002 /* ijkmeta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijkmeta.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 5450B0171E63EA4300568494 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 5450B0471E63EABC00568494 /* libz.tbd in Frameworks */, 5450B0451E63EAB700568494 /* libcrypto.a in Frameworks */, 5450B0461E63EAB700568494 /* libssl.a in Frameworks */, 5450B0181E63EA4300568494 /* libavcodec.a in Frameworks */, 5450B0191E63EA4300568494 /* libavfilter.a in Frameworks */, 5450B01A1E63EA4300568494 /* libavformat.a in Frameworks */, 5450B01B1E63EA4300568494 /* libavutil.a in Frameworks */, 5450B01C1E63EA4300568494 /* libswresample.a in Frameworks */, 5450B01D1E63EA4300568494 /* libswscale.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; E654EA861B6B27E600B0F2D0 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( E653C6F61BCE5A750016835A /* libavcodec.a in Frameworks */, E653C6F81BCE5A750016835A /* libavfilter.a in Frameworks */, E653C6FA1BCE5A750016835A /* libavformat.a in Frameworks */, E653C6FC1BCE5A750016835A /* libavutil.a in Frameworks */, E653C6FE1BCE5A750016835A /* libswresample.a in Frameworks */, E653C7001BCE5A750016835A /* libswscale.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; E654EA911B6B27E600B0F2D0 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( E654EA951B6B27E600B0F2D0 /* IJKMediaFramework.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 4543161F1A66481600676070 /* pipeline */ = { isa = PBXGroup; children = ( 454316201A66493700676070 /* ffpipeline_ios.c */, 454316211A66493700676070 /* ffpipeline_ios.h */, 454316221A66493700676070 /* ffpipenode_ios_videotoolbox_vdec.h */, 454316231A66493700676070 /* ffpipenode_ios_videotoolbox_vdec.m */, E6D5FFF71B5F445E00E1E328 /* h264_sps_parser.h */, 5407EC271DF7F93B00457BFE /* IJKVideoToolBox.h */, 5407EC281DF7F93B00457BFE /* IJKVideoToolBox.m */, 454316291A66497900676070 /* IJKVideoToolBoxAsync.h */, 4543162A1A66497900676070 /* IJKVideoToolBoxAsync.m */, 5407EC2B1DF81D2600457BFE /* IJKVideoToolBoxSync.h */, 5407EC2C1DF81D2600457BFE /* IJKVideoToolBoxSync.m */, ); name = pipeline; sourceTree = ""; }; 5450AF9A1E63E65700568494 /* IJKMediaFrameworkWithSSL */ = { isa = PBXGroup; children = ( 5450AF9B1E63E65700568494 /* IJKMediaFrameworkWithSSL.h */, 5450B0441E63EA4300568494 /* IJKMediaFrameworkWithSSL.plist */, ); path = IJKMediaFrameworkWithSSL; sourceTree = ""; }; E63FC27217F013DE003551EB /* dummy */ = { isa = PBXGroup; children = ( E63FC27317F013DE003551EB /* ijksdl_dummy.h */, E63FC27417F013DE003551EB /* ijksdl_vout_dummy.c */, E63FC27517F013DE003551EB /* ijksdl_vout_dummy.h */, ); path = dummy; sourceTree = ""; }; E654EA8B1B6B27E600B0F2D0 /* IJKMediaFramework */ = { isa = PBXGroup; children = ( E654EA8E1B6B27E600B0F2D0 /* IJKMediaFramework.h */, E654EA8C1B6B27E600B0F2D0 /* Supporting Files */, ); path = IJKMediaFramework; sourceTree = ""; }; E654EA8C1B6B27E600B0F2D0 /* Supporting Files */ = { isa = PBXGroup; children = ( E654EA8D1B6B27E600B0F2D0 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; E654EA981B6B27E600B0F2D0 /* IJKMediaFrameworkTests */ = { isa = PBXGroup; children = ( E654EA9B1B6B27E600B0F2D0 /* IJKMediaFrameworkTests.m */, E654EA991B6B27E600B0F2D0 /* Supporting Files */, ); path = IJKMediaFrameworkTests; sourceTree = ""; }; E654EA991B6B27E600B0F2D0 /* Supporting Files */ = { isa = PBXGroup; children = ( E654EA9A1B6B27E600B0F2D0 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; E66F8DBC17EEC2CF00354D80 /* Classes */ = { isa = PBXGroup; children = ( E6F727B517F2B1690043623F /* IJKMediaPlayer */, E67C4E0219D15B0600415CEE /* IJKAVMoviePlayerController */, E66F8DBE17EEC5DE00354D80 /* IJKMPMoviePlayerController */, E6903EBE17EAF6C500CFD954 /* IJKFFMoviePlayerController */, ); name = Classes; sourceTree = ""; }; E66F8DBE17EEC5DE00354D80 /* IJKMPMoviePlayerController */ = { isa = PBXGroup; children = ( E66F8DBF17EEC65200354D80 /* IJKMPMoviePlayerController.h */, E66F8DC017EEC65200354D80 /* IJKMPMoviePlayerController.m */, ); name = IJKMPMoviePlayerController; sourceTree = ""; }; E66F8DF817EFEC1300354D80 /* ios */ = { isa = PBXGroup; children = ( 4543161F1A66481600676070 /* pipeline */, E66F8E0117EFEEA400354D80 /* ijkplayer_ios.m */, E66F8E0217EFEEA400354D80 /* ijkplayer_ios.h */, ); name = ios; path = ../../ios/IJKMediaPlayer/IJKMediaPlayer; sourceTree = ""; }; E67B91B11A3801E600717EA9 /* pipeline */ = { isa = PBXGroup; children = ( E67B91B21A3801E600717EA9 /* ffpipeline_ffplay.c */, E67B91B31A3801E600717EA9 /* ffpipeline_ffplay.h */, E67B91B41A3801E600717EA9 /* ffpipenode_ffplay_vdec.c */, E67B91B51A3801E600717EA9 /* ffpipenode_ffplay_vdec.h */, ); path = pipeline; sourceTree = ""; }; E67C4E0219D15B0600415CEE /* IJKAVMoviePlayerController */ = { isa = PBXGroup; children = ( E67C4E0319D15B3200415CEE /* IJKAVPlayerLayerView.h */, E67C4E0419D15B3200415CEE /* IJKAVPlayerLayerView.m */, E67C4E0619D15EEA00415CEE /* IJKAVMoviePlayerController.h */, E67C4E0719D15EEA00415CEE /* IJKAVMoviePlayerController.m */, ); name = IJKAVMoviePlayerController; sourceTree = ""; }; E6903EB017EAF6C500CFD954 = { isa = PBXGroup; children = ( E66F8DBC17EEC2CF00354D80 /* Classes */, E654EA8B1B6B27E600B0F2D0 /* IJKMediaFramework */, E654EA981B6B27E600B0F2D0 /* IJKMediaFrameworkTests */, 5450AF9A1E63E65700568494 /* IJKMediaFrameworkWithSSL */, E6903EBB17EAF6C500CFD954 /* Frameworks */, E6903EBA17EAF6C500CFD954 /* Products */, ); sourceTree = ""; }; E6903EBA17EAF6C500CFD954 /* Products */ = { isa = PBXGroup; children = ( E654EA8A1B6B27E600B0F2D0 /* IJKMediaFramework.framework */, E654EA941B6B27E600B0F2D0 /* IJKMediaFrameworkTests.xctest */, 5450B0431E63EA4300568494 /* IJKMediaFrameworkWithSSL.framework */, ); name = Products; sourceTree = ""; }; E6903EBB17EAF6C500CFD954 /* Frameworks */ = { isa = PBXGroup; children = ( 5450AF8F1E63E59800568494 /* libz.tbd */, 5450AF8B1E63E59300568494 /* libcrypto.a */, 5450AF8C1E63E59300568494 /* libssl.a */, ); name = Frameworks; sourceTree = ""; }; E6903EBE17EAF6C500CFD954 /* IJKFFMoviePlayerController */ = { isa = PBXGroup; children = ( E6903F7617EAFC2C00CFD954 /* ffmpeg */, E6DBD3871C8941EB0058E4FB /* IJKFFMonitor.h */, E6DBD3881C8941EB0058E4FB /* IJKFFMonitor.m */, 4D32BC801F906E3600CE9F03 /* IJKSDLGLViewProtocol.h */, E66F8DE517EFD9C300354D80 /* IJKFFMoviePlayerController.h */, E66F8DE617EFD9C300354D80 /* IJKFFMoviePlayerController.m */, E6F727B917F2D9D30043623F /* IJKFFMoviePlayerDef.h */, E6F727BA17F2D9D30043623F /* IJKFFMoviePlayerDef.m */, E62139BC180FA89A00553533 /* IJKFFOptions.h */, E62139BD180FA89A00553533 /* IJKFFOptions.m */, E6903FCC17EAFC6100CFD954 /* ijkmedia */, E6903EBF17EAF6C500CFD954 /* Supporting Files */, ); name = IJKFFMoviePlayerController; path = IJKMediaPlayer; sourceTree = ""; }; E6903EBF17EAF6C500CFD954 /* Supporting Files */ = { isa = PBXGroup; children = ( E6903EC017EAF6C500CFD954 /* IJKMediaPlayer-Prefix.pch */, ); name = "Supporting Files"; sourceTree = ""; }; E6903F7617EAFC2C00CFD954 /* ffmpeg */ = { isa = PBXGroup; children = ( E6903FC117EAFC2C00CFD954 /* lib */, ); name = ffmpeg; path = ../../build/universal; sourceTree = ""; }; E6903FC117EAFC2C00CFD954 /* lib */ = { isa = PBXGroup; children = ( E653C6EF1BCE5A750016835A /* libavcodec.a */, E653C6F01BCE5A750016835A /* libavfilter.a */, E653C6F11BCE5A750016835A /* libavformat.a */, E653C6F21BCE5A750016835A /* libavutil.a */, E653C6F31BCE5A750016835A /* libswresample.a */, E653C6F41BCE5A750016835A /* libswscale.a */, ); path = lib; sourceTree = ""; }; E6903FCC17EAFC6100CFD954 /* ijkmedia */ = { isa = PBXGroup; children = ( E6903FCE17EAFC6100CFD954 /* ijkplayer */, E6903FDF17EAFC6100CFD954 /* ijksdl */, ); name = ijkmedia; path = ../../../ijkmedia; sourceTree = ""; }; E6903FCE17EAFC6100CFD954 /* ijkplayer */ = { isa = PBXGroup; children = ( E67FB4AC1B4A766F00AA94AA /* config.h */, E6903FD517EAFC6100CFD954 /* ff_cmdutils.c */, E6903FD617EAFC6100CFD954 /* ff_cmdutils.h */, E6903FD717EAFC6100CFD954 /* ff_fferror.h */, E6903FD817EAFC6100CFD954 /* ff_ffinc.h */, E6903FDA17EAFC6100CFD954 /* ff_ffmsg_queue.h */, E6903FD917EAFC6100CFD954 /* ff_ffmsg.h */, E67B91AB1A3801DB00717EA9 /* ff_ffpipeline.c */, E67B91AC1A3801DB00717EA9 /* ff_ffpipeline.h */, E67B91AD1A3801DB00717EA9 /* ff_ffpipenode.c */, E67B91AE1A3801DB00717EA9 /* ff_ffpipenode.h */, E6C2FD391B300A390081D321 /* ff_ffplay_debug.h */, E6903FDE17EAFC6100CFD954 /* ff_ffplay_def.h */, E6C459BC1C7089AB004831EC /* ff_ffplay_options.h */, E6903FDB17EAFC6100CFD954 /* ff_ffplay.c */, E6903FDC17EAFC6100CFD954 /* ff_ffplay.h */, E69BE5491B93FED300AFBA3F /* ijkavformat */, E69BE54E1B93FED300AFBA3F /* ijkavutil */, E6FAD9551A515CE300725002 /* ijkmeta.c */, E6FAD9561A515CE300725002 /* ijkmeta.h */, E66F8DEE17EFEA9400354D80 /* ijkplayer_internal.h */, E66F8DEF17EFEA9400354D80 /* ijkplayer.c */, E66F8DF017EFEA9400354D80 /* ijkplayer.h */, E66F8DF817EFEC1300354D80 /* ios */, E67B91B11A3801E600717EA9 /* pipeline */, ); path = ijkplayer; sourceTree = ""; }; E6903FDF17EAFC6100CFD954 /* ijksdl */ = { isa = PBXGroup; children = ( E63FC27217F013DE003551EB /* dummy */, E6903FEF17EAFC6100CFD954 /* ffmpeg */, E6C459851C7030B6004831EC /* gles2 */, E690400117EAFC6100CFD954 /* ijksdl_aout_internal.h */, E6903FFF17EAFC6100CFD954 /* ijksdl_aout.c */, E690400017EAFC6100CFD954 /* ijksdl_aout.h */, E63FC27017F01143003551EB /* ijksdl_audio.c */, E690400217EAFC6100CFD954 /* ijksdl_audio.h */, E6CA1EE71B4FAFCF00BCAF89 /* ijksdl_class.h */, E6C459B81C706A13004831EC /* ijksdl_egl.c */, E6C459B91C706A13004831EC /* ijksdl_egl.h */, E690400317EAFC6100CFD954 /* ijksdl_endian.h */, E690400417EAFC6100CFD954 /* ijksdl_error.c */, E690400517EAFC6100CFD954 /* ijksdl_error.h */, E690400617EAFC6100CFD954 /* ijksdl_fourcc.h */, E6C459831C7030AA004831EC /* ijksdl_gles2.h */, E690400717EAFC6100CFD954 /* ijksdl_inc_internal.h */, E6CA1EE91B4FB04500BCAF89 /* ijksdl_log.h */, E6CA1EE81B4FAFCF00BCAF89 /* ijksdl_misc.h */, E690400817EAFC6100CFD954 /* ijksdl_mutex.c */, E690400917EAFC6100CFD954 /* ijksdl_mutex.h */, E690400A17EAFC6100CFD954 /* ijksdl_stdinc.c */, E690400B17EAFC6100CFD954 /* ijksdl_stdinc.h */, E690400C17EAFC6100CFD954 /* ijksdl_thread.c */, E690400D17EAFC6100CFD954 /* ijksdl_thread.h */, E690400E17EAFC6100CFD954 /* ijksdl_timer.c */, E690400F17EAFC6100CFD954 /* ijksdl_timer.h */, E690401017EAFC6100CFD954 /* ijksdl_video.h */, E690401317EAFC6100CFD954 /* ijksdl_vout_internal.h */, E690401117EAFC6100CFD954 /* ijksdl_vout.c */, E690401217EAFC6100CFD954 /* ijksdl_vout.h */, E6903FFD17EAFC6100CFD954 /* ijksdl.h */, E6EE92A51878230C009EAB56 /* ios */, ); path = ijksdl; sourceTree = ""; }; E6903FEF17EAFC6100CFD954 /* ffmpeg */ = { isa = PBXGroup; children = ( E6903FF017EAFC6100CFD954 /* abi_all */, E6903FF917EAFC6100CFD954 /* ijksdl_image_convert.h */, E6903FFA17EAFC6100CFD954 /* ijksdl_inc_ffmpeg.h */, E6903FFB17EAFC6100CFD954 /* ijksdl_vout_overlay_ffmpeg.c */, E6903FFC17EAFC6100CFD954 /* ijksdl_vout_overlay_ffmpeg.h */, ); path = ffmpeg; sourceTree = ""; }; E6903FF017EAFC6100CFD954 /* abi_all */ = { isa = PBXGroup; children = ( E6903FF117EAFC6100CFD954 /* image_convert.c */, ); path = abi_all; sourceTree = ""; }; E69BE5491B93FED300AFBA3F /* ijkavformat */ = { isa = PBXGroup; children = ( B4449BD5250095700074CEDC /* ijklas.c */, B4449BD4250095700074CEDC /* ijklas.h */, B417F8E124F7C56C00D159BB /* cJSON.c */, B417F8DB24F7C3B400D159BB /* cJSON.h */, 54A029B11D4700E6001C61C1 /* ijkasync.c */, 4DA7F6881F2B1E270032A499 /* ijkiourlhook.c */, 54A029B21D4700E6001C61C1 /* ijkavformat.h */, 54A029B31D4700E6001C61C1 /* ijklongurl.c */, 54A029B41D4700E6001C61C1 /* ijksegment.c */, 54A029B51D4700E6001C61C1 /* ijkurlhook.c */, E69BE54A1B93FED300AFBA3F /* allformats.c */, E69BE5701B946FF600AFBA3F /* ijklivehook.c */, 54CF8A291E1526F800309DD5 /* ijkio.c */, 54CF8A2A1E1526F800309DD5 /* ijkioapplication.c */, 54CF8A2B1E1526F800309DD5 /* ijkioapplication.h */, 54CF8A2C1E1526F800309DD5 /* ijkiocache.c */, 54CF8A2D1E1526F800309DD5 /* ijkioffio.c */, 54CF8A2E1E1526F800309DD5 /* ijkiomanager.c */, 54CF8A2F1E1526F800309DD5 /* ijkiomanager.h */, 54CF8A301E1526F800309DD5 /* ijkioprotocol.c */, 54CF8A311E1526F800309DD5 /* ijkioprotocol.h */, 54CF8A321E1526F800309DD5 /* ijkiourl.h */, ); path = ijkavformat; sourceTree = ""; }; E69BE54E1B93FED300AFBA3F /* ijkavutil */ = { isa = PBXGroup; children = ( 54CF8A3D1E15287D00309DD5 /* ijkdict.c */, 54CF8A3E1E15287D00309DD5 /* ijkdict.h */, 54CF8A3F1E15287D00309DD5 /* ijkfifo.c */, 54CF8A401E15287D00309DD5 /* ijkfifo.h */, 54CF8A411E15287D00309DD5 /* ijkstl.cpp */, 54CF8A421E15287D00309DD5 /* ijkstl.h */, 54CF8A431E15287D00309DD5 /* ijkthreadpool.c */, 54CF8A441E15287D00309DD5 /* ijkthreadpool.h */, 54CF8A451E15287D00309DD5 /* ijktree.c */, 54CF8A461E15287D00309DD5 /* ijktree.h */, 54CF8A471E15287D00309DD5 /* ijkutils.c */, 54CF8A481E15287D00309DD5 /* ijkutils.h */, E69BE54F1B93FED300AFBA3F /* opt.h */, ); path = ijkavutil; sourceTree = ""; }; E6C459851C7030B6004831EC /* gles2 */ = { isa = PBXGroup; children = ( E6C459861C7030B6004831EC /* color.c */, E6C459871C7030B6004831EC /* common.c */, E6C459881C7030B6004831EC /* fsh */, E6C4598B1C7030B6004831EC /* internal.h */, E6C459BE1C708CAF004831EC /* renderer_rgb.c */, E6C4598D1C7030B6004831EC /* renderer_yuv420p.c */, E6E1B9A71C741F72000C6C72 /* renderer_yuv420sp_vtb.m */, E6C459CA1C70967F004831EC /* renderer_yuv420sp.c */, E6C4598E1C7030B6004831EC /* renderer_yuv444p10le.c */, E6C4598C1C7030B6004831EC /* renderer.c */, E6C4598F1C7030B6004831EC /* shader.c */, E6C459901C7030B6004831EC /* vsh */, ); path = gles2; sourceTree = ""; }; E6C459881C7030B6004831EC /* fsh */ = { isa = PBXGroup; children = ( E6C459C21C708E60004831EC /* rgb.fsh.c */, E6C459891C7030B6004831EC /* yuv420p.fsh.c */, E6C459C61C7095E5004831EC /* yuv420sp.fsh.c */, E6C4598A1C7030B6004831EC /* yuv444p10le.fsh.c */, ); path = fsh; sourceTree = ""; }; E6C459901C7030B6004831EC /* vsh */ = { isa = PBXGroup; children = ( E6C459911C7030B6004831EC /* mvp.vsh.c */, ); path = vsh; sourceTree = ""; }; E6EE92A51878230C009EAB56 /* ios */ = { isa = PBXGroup; children = ( E6EE92A61878230C009EAB56 /* ijksdl_aout_ios_audiounit.h */, E6EE92A71878230C009EAB56 /* ijksdl_aout_ios_audiounit.m */, E6EE92A81878230C009EAB56 /* ijksdl_ios.h */, E6EE92A91878230C009EAB56 /* ijksdl_thread_ios.h */, E6EE92AA1878230C009EAB56 /* ijksdl_thread_ios.m */, E6EE92AB1878230C009EAB56 /* ijksdl_vout_ios_gles2.h */, E6EE92AC1878230C009EAB56 /* ijksdl_vout_ios_gles2.m */, 45DB4AA71A5D52AE005CAD41 /* ijksdl_vout_overlay_videotoolbox.h */, 45DB4AA81A5D52AE005CAD41 /* ijksdl_vout_overlay_videotoolbox.m */, E6EE92C618782770009EAB56 /* IJKSDLAudioKit.h */, E6EE92C718782770009EAB56 /* IJKSDLAudioKit.m */, E6EE92C01878236A009EAB56 /* IJKSDLAudioQueueController.h */, E6EE92C11878236A009EAB56 /* IJKSDLAudioQueueController.m */, E6EE92AD1878230C009EAB56 /* IJKSDLAudioUnitController.h */, E6EE92AE1878230C009EAB56 /* IJKSDLAudioUnitController.m */, E6EE92B61878230C009EAB56 /* IJKSDLGLView.h */, E6EE92B71878230C009EAB56 /* IJKSDLGLView.m */, E68B7ACD1C1E97B0001DE241 /* IJKSDLHudViewCell.h */, E68B7ACE1C1E97B0001DE241 /* IJKSDLHudViewCell.m */, E68B7AC31C1E7F20001DE241 /* IJKSDLHudViewController.h */, E68B7AC41C1E7F20001DE241 /* IJKSDLHudViewController.m */, ); name = ios; path = ../../ios/IJKMediaPlayer/IJKMediaPlayer/ijkmedia/ijksdl/ios; sourceTree = ""; }; E6F727B517F2B1690043623F /* IJKMediaPlayer */ = { isa = PBXGroup; children = ( E6EE92A1187810C5009EAB56 /* IJKAudioKit.h */, E6EE92A2187810C5009EAB56 /* IJKAudioKit.m */, E607FFDE1B7B60F9005F11A6 /* IJKDeviceModel.h */, E607FFDF1B7B60F9005F11A6 /* IJKDeviceModel.m */, E65DC3B719D93D5F004F8A08 /* IJKKVOController.h */, E65DC3B819D93D5F004F8A08 /* IJKKVOController.m */, E672D6F118D3445100C51FF9 /* IJKMediaModule.h */, E672D6F218D3445100C51FF9 /* IJKMediaModule.m */, E6903EC117EAF6C500CFD954 /* IJKMediaPlayback.h */, E6F727C117F7C9B90043623F /* IJKMediaPlayback.m */, E66F8DC217EECB1E00354D80 /* IJKMediaPlayer.h */, E6716E491807E5FC00B3FBC1 /* IJKMediaUtils.h */, E6716E4A1807E5FC00B3FBC1 /* IJKMediaUtils.m */, E698089E1C7EB2040048A46C /* IJKNotificationManager.h */, E698089F1C7EB2040048A46C /* IJKNotificationManager.m */, E69808991C7EB13A0048A46C /* NSString+IJKMedia.h */, E698089A1C7EB13A0048A46C /* NSString+IJKMedia.m */, ); name = IJKMediaPlayer; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 5450B01E1E63EA4300568494 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 5450B01F1E63EA4300568494 /* IJKFFMonitor.h in Headers */, 5450B0201E63EA4300568494 /* ijkiourl.h in Headers */, 5450B0211E63EA4300568494 /* IJKFFMoviePlayerController.h in Headers */, 5450B0221E63EA4300568494 /* IJKSDLHudViewController.h in Headers */, 5450B0231E63EA4300568494 /* IJKFFOptions.h in Headers */, 5450B0241E63EA4300568494 /* ijkutils.h in Headers */, 5450B0251E63EA4300568494 /* ijkdict.h in Headers */, 5450B0261E63EA4300568494 /* IJKAVMoviePlayerController.h in Headers */, 5450B0271E63EA4300568494 /* ijksdl_gles2.h in Headers */, 5450B0281E63EA4300568494 /* ijksdl_egl.h in Headers */, 549385C41E640456001AE08D /* IJKMediaFrameworkWithSSL.h in Headers */, 5450B0291E63EA4300568494 /* ff_ffplay_options.h in Headers */, 5450B02B1E63EA4300568494 /* IJKKVOController.h in Headers */, 5450B02C1E63EA4300568494 /* IJKNotificationManager.h in Headers */, 5450B02D1E63EA4300568494 /* ijkthreadpool.h in Headers */, 5450B02E1E63EA4300568494 /* ijkiomanager.h in Headers */, 33BA6FC0254BC4D9004EB9F2 /* ijklas.h in Headers */, 5450B02F1E63EA4300568494 /* ijkstl.h in Headers */, 4D32BC821F906E3B00CE9F03 /* IJKSDLGLViewProtocol.h in Headers */, 5450B0301E63EA4300568494 /* IJKMediaModule.h in Headers */, 5450B0311E63EA4300568494 /* ijkfifo.h in Headers */, 5450B0321E63EA4300568494 /* ijktree.h in Headers */, 5450B0331E63EA4300568494 /* opt.h in Headers */, 5450B0341E63EA4300568494 /* ijkioapplication.h in Headers */, 5450B0351E63EA4300568494 /* ijkioprotocol.h in Headers */, 5450B0361E63EA4300568494 /* IJKMediaPlayback.h in Headers */, 5450B0371E63EA4300568494 /* IJKMediaPlayer.h in Headers */, 5450B0381E63EA4300568494 /* internal.h in Headers */, 5450B0391E63EA4300568494 /* IJKVideoToolBoxSync.h in Headers */, 5450B03A1E63EA4300568494 /* IJKMPMoviePlayerController.h in Headers */, 5450B03B1E63EA4300568494 /* ijkavformat.h in Headers */, 5450B03C1E63EA4300568494 /* IJKSDLHudViewCell.h in Headers */, 5450B03D1E63EA4300568494 /* IJKVideoToolBox.h in Headers */, 33BA6FC2254BC4DE004EB9F2 /* cJSON.h in Headers */, 5450B03E1E63EA4300568494 /* NSString+IJKMedia.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; E654EA871B6B27E600B0F2D0 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( E6DBD3891C8941EB0058E4FB /* IJKFFMonitor.h in Headers */, 54CF8A3C1E1526F800309DD5 /* ijkiourl.h in Headers */, E654EAEA1B6B295200B0F2D0 /* IJKFFMoviePlayerController.h in Headers */, E68B7AC51C1E7F20001DE241 /* IJKSDLHudViewController.h in Headers */, E654EAEC1B6B295200B0F2D0 /* IJKFFOptions.h in Headers */, 54CF8A541E15287D00309DD5 /* ijkutils.h in Headers */, 54CF8A4A1E15287D00309DD5 /* ijkdict.h in Headers */, E654EAE81B6B295200B0F2D0 /* IJKAVMoviePlayerController.h in Headers */, E6C459841C7030AA004831EC /* ijksdl_gles2.h in Headers */, E6C459BB1C706A13004831EC /* ijksdl_egl.h in Headers */, E6C459BD1C7089AB004831EC /* ff_ffplay_options.h in Headers */, E654EA8F1B6B27E600B0F2D0 /* IJKMediaFramework.h in Headers */, E6C2E7BE1C92BD3600E59229 /* IJKKVOController.h in Headers */, E69808A01C7EB2040048A46C /* IJKNotificationManager.h in Headers */, B417F8DE24F7C3B500D159BB /* cJSON.h in Headers */, 54CF8A501E15287D00309DD5 /* ijkthreadpool.h in Headers */, 54CF8A391E1526F800309DD5 /* ijkiomanager.h in Headers */, 54CF8A4E1E15287D00309DD5 /* ijkstl.h in Headers */, 4D32BC811F906E3A00CE9F03 /* IJKSDLGLViewProtocol.h in Headers */, E654EAE61B6B295200B0F2D0 /* IJKMediaModule.h in Headers */, 54CF8A4C1E15287D00309DD5 /* ijkfifo.h in Headers */, 54CF8A521E15287D00309DD5 /* ijktree.h in Headers */, E69BE5571B93FED300AFBA3F /* opt.h in Headers */, 54CF8A351E1526F800309DD5 /* ijkioapplication.h in Headers */, 54CF8A3B1E1526F800309DD5 /* ijkioprotocol.h in Headers */, B4449BD6250095700074CEDC /* ijklas.h in Headers */, E654EAE71B6B295200B0F2D0 /* IJKMediaPlayback.h in Headers */, E654EAED1B6B29C100B0F2D0 /* IJKMediaPlayer.h in Headers */, E6C459961C7030B6004831EC /* internal.h in Headers */, 5407EC2D1DF81D2600457BFE /* IJKVideoToolBoxSync.h in Headers */, E654EAE91B6B295200B0F2D0 /* IJKMPMoviePlayerController.h in Headers */, 54A029B71D4700E6001C61C1 /* ijkavformat.h in Headers */, E68B7ACF1C1E97B0001DE241 /* IJKSDLHudViewCell.h in Headers */, 5407EC291DF7F93B00457BFE /* IJKVideoToolBox.h in Headers */, E698089B1C7EB13A0048A46C /* NSString+IJKMedia.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 5450AFC11E63EA4300568494 /* IJKMediaFrameworkWithSSL */ = { isa = PBXNativeTarget; buildConfigurationList = 5450B0401E63EA4300568494 /* Build configuration list for PBXNativeTarget "IJKMediaFrameworkWithSSL" */; buildPhases = ( 5450AFC21E63EA4300568494 /* ijkversion.h */, 5450AFC31E63EA4300568494 /* Sources */, 5450B0171E63EA4300568494 /* Frameworks */, 5450B01E1E63EA4300568494 /* Headers */, 5450B03F1E63EA4300568494 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = IJKMediaFrameworkWithSSL; productName = IJKMediaFramework; productReference = 5450B0431E63EA4300568494 /* IJKMediaFrameworkWithSSL.framework */; productType = "com.apple.product-type.framework"; }; E654EA891B6B27E600B0F2D0 /* IJKMediaFramework */ = { isa = PBXNativeTarget; buildConfigurationList = E654EAA11B6B27E600B0F2D0 /* Build configuration list for PBXNativeTarget "IJKMediaFramework" */; buildPhases = ( 544E73271D93DEF4005CA5D9 /* ijkversion.h */, E654EA851B6B27E600B0F2D0 /* Sources */, E654EA861B6B27E600B0F2D0 /* Frameworks */, E654EA871B6B27E600B0F2D0 /* Headers */, E654EA881B6B27E600B0F2D0 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = IJKMediaFramework; productName = IJKMediaFramework; productReference = E654EA8A1B6B27E600B0F2D0 /* IJKMediaFramework.framework */; productType = "com.apple.product-type.framework"; }; E654EA931B6B27E600B0F2D0 /* IJKMediaFrameworkTests */ = { isa = PBXNativeTarget; buildConfigurationList = E654EAA21B6B27E600B0F2D0 /* Build configuration list for PBXNativeTarget "IJKMediaFrameworkTests" */; buildPhases = ( E654EA901B6B27E600B0F2D0 /* Sources */, E654EA911B6B27E600B0F2D0 /* Frameworks */, E654EA921B6B27E600B0F2D0 /* Resources */, ); buildRules = ( ); dependencies = ( E654EA971B6B27E600B0F2D0 /* PBXTargetDependency */, ); name = IJKMediaFrameworkTests; productName = IJKMediaFrameworkTests; productReference = E654EA941B6B27E600B0F2D0 /* IJKMediaFrameworkTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ E6903EB117EAF6C500CFD954 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0700; ORGANIZATIONNAME = bilibili; TargetAttributes = { E654EA891B6B27E600B0F2D0 = { CreatedOnToolsVersion = 6.4; }; E654EA931B6B27E600B0F2D0 = { CreatedOnToolsVersion = 6.4; }; }; }; buildConfigurationList = E6903EB417EAF6C500CFD954 /* Build configuration list for PBXProject "IJKMediaPlayer" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( English, en, ); mainGroup = E6903EB017EAF6C500CFD954; productRefGroup = E6903EBA17EAF6C500CFD954 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( E654EA891B6B27E600B0F2D0 /* IJKMediaFramework */, 5450AFC11E63EA4300568494 /* IJKMediaFrameworkWithSSL */, E654EA931B6B27E600B0F2D0 /* IJKMediaFrameworkTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 5450B03F1E63EA4300568494 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; E654EA881B6B27E600B0F2D0 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; E654EA921B6B27E600B0F2D0 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 544E73271D93DEF4005CA5D9 /* ijkversion.h */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = ijkversion.h; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "sh \"${PROJECT_DIR}/../../ijkmedia/ijkplayer/version.sh\" \"${PROJECT_DIR}/../../ijkmedia/ijkplayer\" \"ijkversion.h\""; }; 5450AFC21E63EA4300568494 /* ijkversion.h */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = ijkversion.h; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "sh \"${PROJECT_DIR}/../../ijkmedia/ijkplayer/version.sh\" \"${PROJECT_DIR}/../../ijkmedia/ijkplayer\" \"ijkversion.h\""; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 5450AFC31E63EA4300568494 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 5450AFC41E63EA4300568494 /* IJKKVOController.m in Sources */, 5450AFC51E63EA4300568494 /* ijksdl_vout.c in Sources */, 5450AFC61E63EA4300568494 /* yuv444p10le.fsh.c in Sources */, 5450AFC71E63EA4300568494 /* allformats.c in Sources */, 5450AFC81E63EA4300568494 /* ffpipenode_ffplay_vdec.c in Sources */, 5450AFC91E63EA4300568494 /* renderer_yuv420p.c in Sources */, 5450AFCA1E63EA4300568494 /* ijkthreadpool.c in Sources */, 5450AFCB1E63EA4300568494 /* IJKAVMoviePlayerController.m in Sources */, 5450AFCC1E63EA4300568494 /* IJKFFMoviePlayerDef.m in Sources */, 5450AFCD1E63EA4300568494 /* ijkplayer_ios.m in Sources */, 5450AFCE1E63EA4300568494 /* ffpipeline_ios.c in Sources */, 5450AFCF1E63EA4300568494 /* ijkioprotocol.c in Sources */, 5450AFD01E63EA4300568494 /* ijksdl_vout_dummy.c in Sources */, 5450AFD11E63EA4300568494 /* renderer_yuv420sp.c in Sources */, 5450AFD21E63EA4300568494 /* yuv420p.fsh.c in Sources */, 5450AFD31E63EA4300568494 /* ijksdl_error.c in Sources */, 5450AFD41E63EA4300568494 /* IJKDeviceModel.m in Sources */, 5450AFD51E63EA4300568494 /* ijkiocache.c in Sources */, 5450AFD61E63EA4300568494 /* ijksdl_egl.c in Sources */, 5450AFD71E63EA4300568494 /* ijkio.c in Sources */, 5450AFD81E63EA4300568494 /* IJKAudioKit.m in Sources */, 5450AFD91E63EA4300568494 /* IJKMPMoviePlayerController.m in Sources */, 5450AFDA1E63EA4300568494 /* IJKSDLHudViewCell.m in Sources */, 5450AFDB1E63EA4300568494 /* ijksdl_vout_overlay_videotoolbox.m in Sources */, 5450AFDC1E63EA4300568494 /* ff_ffpipenode.c in Sources */, 5450AFDD1E63EA4300568494 /* ijksdl_stdinc.c in Sources */, 5450AFDE1E63EA4300568494 /* IJKVideoToolBox.m in Sources */, 5450AFDF1E63EA4300568494 /* ijksegment.c in Sources */, 5450AFE01E63EA4300568494 /* IJKMediaUtils.m in Sources */, 5450AFE11E63EA4300568494 /* common.c in Sources */, 5450AFE21E63EA4300568494 /* ijksdl_aout_ios_audiounit.m in Sources */, 5450AFE31E63EA4300568494 /* ijklivehook.c in Sources */, 5450AFE41E63EA4300568494 /* ijkurlhook.c in Sources */, 5450AFE51E63EA4300568494 /* IJKVideoToolBoxSync.m in Sources */, 5450AFE61E63EA4300568494 /* IJKMediaPlayback.m in Sources */, 5450AFE71E63EA4300568494 /* ijkdict.c in Sources */, 5450AFE81E63EA4300568494 /* ff_ffpipeline.c in Sources */, 4DA7F68A1F2B1E270032A499 /* ijkiourlhook.c in Sources */, 5450AFE91E63EA4300568494 /* IJKSDLAudioKit.m in Sources */, 5450AFEA1E63EA4300568494 /* mvp.vsh.c in Sources */, 5450AFEB1E63EA4300568494 /* NSString+IJKMedia.m in Sources */, 5450AFEC1E63EA4300568494 /* ijksdl_vout_overlay_ffmpeg.c in Sources */, 5450AFED1E63EA4300568494 /* ijksdl_mutex.c in Sources */, 33BA6FC1254BC4DC004EB9F2 /* cJSON.c in Sources */, 5450AFEE1E63EA4300568494 /* ijktree.c in Sources */, 5450AFEF1E63EA4300568494 /* IJKSDLAudioQueueController.m in Sources */, 5450AFF01E63EA4300568494 /* ijksdl_thread.c in Sources */, 5450AFF11E63EA4300568494 /* yuv420sp.fsh.c in Sources */, 5450AFF21E63EA4300568494 /* ff_ffplay.c in Sources */, 5450AFF31E63EA4300568494 /* ijksdl_aout.c in Sources */, 5450AFF41E63EA4300568494 /* color.c in Sources */, 5450AFF51E63EA4300568494 /* ijksdl_audio.c in Sources */, 5450AFF61E63EA4300568494 /* ijksdl_thread_ios.m in Sources */, 5450AFF71E63EA4300568494 /* ijkmeta.c in Sources */, 5450AFF81E63EA4300568494 /* ijkasync.c in Sources */, 5450AFF91E63EA4300568494 /* renderer_yuv420sp_vtb.m in Sources */, 5450AFFA1E63EA4300568494 /* ijkutils.c in Sources */, 5450AFFB1E63EA4300568494 /* IJKSDLGLView.m in Sources */, 33BA6FBF254BC4D7004EB9F2 /* ijklas.c in Sources */, 5450AFFC1E63EA4300568494 /* ijksdl_timer.c in Sources */, 5450AFFD1E63EA4300568494 /* ijkfifo.c in Sources */, 5450AFFE1E63EA4300568494 /* shader.c in Sources */, 5450AFFF1E63EA4300568494 /* ijkioffio.c in Sources */, 5450B0001E63EA4300568494 /* renderer.c in Sources */, 5450B0011E63EA4300568494 /* ijkioapplication.c in Sources */, 5450B0021E63EA4300568494 /* ijkiomanager.c in Sources */, 5450B0031E63EA4300568494 /* ijkplayer.c in Sources */, 5450B0041E63EA4300568494 /* IJKFFOptions.m in Sources */, 5450B0051E63EA4300568494 /* IJKSDLAudioUnitController.m in Sources */, 5450B0061E63EA4300568494 /* IJKFFMonitor.m in Sources */, 5450B0071E63EA4300568494 /* IJKFFMoviePlayerController.m in Sources */, 5450B0081E63EA4300568494 /* IJKNotificationManager.m in Sources */, 5450B0091E63EA4300568494 /* IJKMediaModule.m in Sources */, 5450B00A1E63EA4300568494 /* ff_cmdutils.c in Sources */, 5450B00B1E63EA4300568494 /* IJKVideoToolBoxAsync.m in Sources */, 5450B00C1E63EA4300568494 /* renderer_yuv444p10le.c in Sources */, 5450B00D1E63EA4300568494 /* ijkstl.cpp in Sources */, 5450B00E1E63EA4300568494 /* image_convert.c in Sources */, 5450B00F1E63EA4300568494 /* rgb.fsh.c in Sources */, 5450B0101E63EA4300568494 /* ffpipenode_ios_videotoolbox_vdec.m in Sources */, 5450B0111E63EA4300568494 /* IJKAVPlayerLayerView.m in Sources */, 5450B0121E63EA4300568494 /* IJKSDLHudViewController.m in Sources */, 5450B0131E63EA4300568494 /* ijksdl_vout_ios_gles2.m in Sources */, 5450B0141E63EA4300568494 /* ijklongurl.c in Sources */, 5450B0151E63EA4300568494 /* renderer_rgb.c in Sources */, 5450B0161E63EA4300568494 /* ffpipeline_ffplay.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; E654EA851B6B27E600B0F2D0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E654EAA71B6B283700B0F2D0 /* IJKKVOController.m in Sources */, E654EAC71B6B287E00B0F2D0 /* ijksdl_vout.c in Sources */, E6C459951C7030B6004831EC /* yuv444p10le.fsh.c in Sources */, E69BE5511B93FED300AFBA3F /* allformats.c in Sources */, E654EABB1B6B286B00B0F2D0 /* ffpipenode_ffplay_vdec.c in Sources */, E6C459981C7030B6004831EC /* renderer_yuv420p.c in Sources */, 54CF8A4F1E15287D00309DD5 /* ijkthreadpool.c in Sources */, E654EAA91B6B283D00B0F2D0 /* IJKAVMoviePlayerController.m in Sources */, B417F8E224F7C56C00D159BB /* cJSON.c in Sources */, E654EAAC1B6B284C00B0F2D0 /* IJKFFMoviePlayerDef.m in Sources */, E654EAB91B6B286700B0F2D0 /* ijkplayer_ios.m in Sources */, E654EAB51B6B286400B0F2D0 /* ffpipeline_ios.c in Sources */, 54CF8A3A1E1526F800309DD5 /* ijkioprotocol.c in Sources */, E654EABD1B6B287000B0F2D0 /* ijksdl_vout_dummy.c in Sources */, E6C459CC1C70967F004831EC /* renderer_yuv420sp.c in Sources */, E6C459941C7030B6004831EC /* yuv420p.fsh.c in Sources */, E654EAC21B6B287E00B0F2D0 /* ijksdl_error.c in Sources */, E607FFE11B7B62E3005F11A6 /* IJKDeviceModel.m in Sources */, 54CF8A361E1526F800309DD5 /* ijkiocache.c in Sources */, E6C459BA1C706A13004831EC /* ijksdl_egl.c in Sources */, 54CF8A331E1526F800309DD5 /* ijkio.c in Sources */, E654EAA31B6B283700B0F2D0 /* IJKAudioKit.m in Sources */, E654EAAA1B6B284300B0F2D0 /* IJKMPMoviePlayerController.m in Sources */, E68B7AD01C1E97B0001DE241 /* IJKSDLHudViewCell.m in Sources */, E654EACB1B6B288A00B0F2D0 /* ijksdl_vout_overlay_videotoolbox.m in Sources */, E654EAB11B6B285900B0F2D0 /* ff_ffpipenode.c in Sources */, E654EAC41B6B287E00B0F2D0 /* ijksdl_stdinc.c in Sources */, 5407EC2A1DF7F93B00457BFE /* IJKVideoToolBox.m in Sources */, 54A029B91D4700E6001C61C1 /* ijksegment.c in Sources */, E654EAA61B6B283700B0F2D0 /* IJKMediaUtils.m in Sources */, E6C459931C7030B6004831EC /* common.c in Sources */, E654EAC81B6B288A00B0F2D0 /* ijksdl_aout_ios_audiounit.m in Sources */, E69BE5721B946FF600AFBA3F /* ijklivehook.c in Sources */, 54A029BA1D4700E6001C61C1 /* ijkurlhook.c in Sources */, 5407EC2E1DF81D2600457BFE /* IJKVideoToolBoxSync.m in Sources */, E654EAA51B6B283700B0F2D0 /* IJKMediaPlayback.m in Sources */, 54CF8A491E15287D00309DD5 /* ijkdict.c in Sources */, E654EAB01B6B285900B0F2D0 /* ff_ffpipeline.c in Sources */, 4DA7F6891F2B1E270032A499 /* ijkiourlhook.c in Sources */, E654EACC1B6B288A00B0F2D0 /* IJKSDLAudioKit.m in Sources */, E6C4599B1C7030B6004831EC /* mvp.vsh.c in Sources */, E698089C1C7EB13A0048A46C /* NSString+IJKMedia.m in Sources */, E654EABF1B6B287600B0F2D0 /* ijksdl_vout_overlay_ffmpeg.c in Sources */, E654EAC31B6B287E00B0F2D0 /* ijksdl_mutex.c in Sources */, 54CF8A511E15287D00309DD5 /* ijktree.c in Sources */, E654EACD1B6B288A00B0F2D0 /* IJKSDLAudioQueueController.m in Sources */, E654EAC51B6B287E00B0F2D0 /* ijksdl_thread.c in Sources */, E6C459C81C7095E5004831EC /* yuv420sp.fsh.c in Sources */, E654EAB21B6B285900B0F2D0 /* ff_ffplay.c in Sources */, E654EAC01B6B287E00B0F2D0 /* ijksdl_aout.c in Sources */, E6C459921C7030B6004831EC /* color.c in Sources */, E654EAC11B6B287E00B0F2D0 /* ijksdl_audio.c in Sources */, E654EAC91B6B288A00B0F2D0 /* ijksdl_thread_ios.m in Sources */, E654EAB31B6B285900B0F2D0 /* ijkmeta.c in Sources */, 54A029B61D4700E6001C61C1 /* ijkasync.c in Sources */, E6E1B9A81C741F72000C6C72 /* renderer_yuv420sp_vtb.m in Sources */, 54CF8A531E15287D00309DD5 /* ijkutils.c in Sources */, E654EAD31B6B288A00B0F2D0 /* IJKSDLGLView.m in Sources */, E654EAC61B6B287E00B0F2D0 /* ijksdl_timer.c in Sources */, 54CF8A4B1E15287D00309DD5 /* ijkfifo.c in Sources */, E6C4599A1C7030B6004831EC /* shader.c in Sources */, 54CF8A371E1526F800309DD5 /* ijkioffio.c in Sources */, E6C459971C7030B6004831EC /* renderer.c in Sources */, 54CF8A341E1526F800309DD5 /* ijkioapplication.c in Sources */, 54CF8A381E1526F800309DD5 /* ijkiomanager.c in Sources */, E654EAB41B6B285900B0F2D0 /* ijkplayer.c in Sources */, E654EAAE1B6B284C00B0F2D0 /* IJKFFOptions.m in Sources */, E654EACE1B6B288A00B0F2D0 /* IJKSDLAudioUnitController.m in Sources */, E6DBD38A1C8941EB0058E4FB /* IJKFFMonitor.m in Sources */, E654EAAB1B6B284C00B0F2D0 /* IJKFFMoviePlayerController.m in Sources */, E69808A11C7EB2040048A46C /* IJKNotificationManager.m in Sources */, E654EAA41B6B283700B0F2D0 /* IJKMediaModule.m in Sources */, E654EAAF1B6B285900B0F2D0 /* ff_cmdutils.c in Sources */, E654EAB81B6B286400B0F2D0 /* IJKVideoToolBoxAsync.m in Sources */, E6C459991C7030B6004831EC /* renderer_yuv444p10le.c in Sources */, 54CF8A4D1E15287D00309DD5 /* ijkstl.cpp in Sources */, E654EABE1B6B287400B0F2D0 /* image_convert.c in Sources */, B4449BD7250095700074CEDC /* ijklas.c in Sources */, E6C459C41C708E60004831EC /* rgb.fsh.c in Sources */, E654EAB61B6B286400B0F2D0 /* ffpipenode_ios_videotoolbox_vdec.m in Sources */, E654EAA81B6B283D00B0F2D0 /* IJKAVPlayerLayerView.m in Sources */, E68B7AC61C1E7F20001DE241 /* IJKSDLHudViewController.m in Sources */, E654EACA1B6B288A00B0F2D0 /* ijksdl_vout_ios_gles2.m in Sources */, 54A029B81D4700E6001C61C1 /* ijklongurl.c in Sources */, E6C459C01C708CAF004831EC /* renderer_rgb.c in Sources */, E654EABA1B6B286B00B0F2D0 /* ffpipeline_ffplay.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; E654EA901B6B27E600B0F2D0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E654EA9C1B6B27E600B0F2D0 /* IJKMediaFrameworkTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ E654EA971B6B27E600B0F2D0 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = E654EA891B6B27E600B0F2D0 /* IJKMediaFramework */; targetProxy = E654EA961B6B27E600B0F2D0 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 5450B0411E63EA4300568494 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; CURRENT_PROJECT_VERSION = 0.8.8; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; HEADER_SEARCH_PATHS = ( "$(inherited)", ../build/universal/include, IJKMediaPlayer/ijkmedia, ../../ijkmedia, ); INFOPLIST_FILE = "$(SRCROOT)/IJKMediaFrameworkWithSSL.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "\"$(SRCROOT)/../build/universal/lib\"", ); MACH_O_TYPE = mh_dylib; MTL_ENABLE_DEBUG_INFO = YES; OTHER_LDFLAGS = ( "-read_only_relocs", suppress, ); PRODUCT_BUNDLE_IDENTIFIER = "tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; 5450B0421E63EA4300568494 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; CURRENT_PROJECT_VERSION = 0.8.8; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; HEADER_SEARCH_PATHS = ( "$(inherited)", ../build/universal/include, IJKMediaPlayer/ijkmedia, ../../ijkmedia, ); INFOPLIST_FILE = "$(SRCROOT)/IJKMediaFrameworkWithSSL.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "\"$(SRCROOT)/../build/universal/lib\"", ); MACH_O_TYPE = mh_dylib; MTL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = ( "-read_only_relocs", suppress, ); PRODUCT_BUNDLE_IDENTIFIER = "tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Release; }; E654EA9D1B6B27E600B0F2D0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CURRENT_PROJECT_VERSION = 0.8.8; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; HEADER_SEARCH_PATHS = ( "$(inherited)", ../build/universal/include, IJKMediaPlayer/ijkmedia, ../../ijkmedia, ); INFOPLIST_FILE = IJKMediaFramework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "\"$(SRCROOT)/../build/universal/lib\"", ); MACH_O_TYPE = staticlib; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; E654EA9E1B6B27E600B0F2D0 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CURRENT_PROJECT_VERSION = 0.8.8; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; HEADER_SEARCH_PATHS = ( "$(inherited)", ../build/universal/include, IJKMediaPlayer/ijkmedia, ../../ijkmedia, ); INFOPLIST_FILE = IJKMediaFramework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "\"$(SRCROOT)/../build/universal/lib\"", ); MACH_O_TYPE = staticlib; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Release; }; E654EA9F1B6B27E600B0F2D0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; INFOPLIST_FILE = IJKMediaFrameworkTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.4; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; E654EAA01B6B27E600B0F2D0 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; INFOPLIST_FILE = IJKMediaFrameworkTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.4; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "tv.danmaku.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; E6903EC517EAF6C500CFD954 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; GCC_WARN_SHADOW = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; STRIP_INSTALLED_PRODUCT = NO; }; name = Debug; }; E6903EC617EAF6C500CFD954 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; GCC_WARN_SHADOW = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; SDKROOT = iphoneos; STRIP_INSTALLED_PRODUCT = NO; VALIDATE_PRODUCT = YES; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 5450B0401E63EA4300568494 /* Build configuration list for PBXNativeTarget "IJKMediaFrameworkWithSSL" */ = { isa = XCConfigurationList; buildConfigurations = ( 5450B0411E63EA4300568494 /* Debug */, 5450B0421E63EA4300568494 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; E654EAA11B6B27E600B0F2D0 /* Build configuration list for PBXNativeTarget "IJKMediaFramework" */ = { isa = XCConfigurationList; buildConfigurations = ( E654EA9D1B6B27E600B0F2D0 /* Debug */, E654EA9E1B6B27E600B0F2D0 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; E654EAA21B6B27E600B0F2D0 /* Build configuration list for PBXNativeTarget "IJKMediaFrameworkTests" */ = { isa = XCConfigurationList; buildConfigurations = ( E654EA9F1B6B27E600B0F2D0 /* Debug */, E654EAA01B6B27E600B0F2D0 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; E6903EB417EAF6C500CFD954 /* Build configuration list for PBXProject "IJKMediaPlayer" */ = { isa = XCConfigurationList; buildConfigurations = ( E6903EC517EAF6C500CFD954 /* Debug */, E6903EC617EAF6C500CFD954 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = E6903EB117EAF6C500CFD954 /* Project object */; } ================================================ FILE: ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: ios/IJKMediaPodDemo/.gitignore ================================================ IJKMediaPodDemo.xcworkspace Pods Podfile.lock ================================================ FILE: ios/IJKMediaPodDemo/IJKMediaPodDemo/AppDelegate.h ================================================ // // AppDelegate.h // IJKMediaPodDemo // // Created by Zhang Rui on 15/7/23. // Copyright (c) 2015年 Zhang Rui. All rights reserved. // #import @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @end ================================================ FILE: ios/IJKMediaPodDemo/IJKMediaPodDemo/AppDelegate.m ================================================ // // AppDelegate.m // IJKMediaPodDemo // // Created by Zhang Rui on 15/7/23. // Copyright (c) 2015年 Zhang Rui. All rights reserved. // #import "AppDelegate.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. return YES; } - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @end ================================================ FILE: ios/IJKMediaPodDemo/IJKMediaPodDemo/Base.lproj/LaunchScreen.xib ================================================ ================================================ FILE: ios/IJKMediaPodDemo/IJKMediaPodDemo/Base.lproj/Main.storyboard ================================================ ================================================ FILE: ios/IJKMediaPodDemo/IJKMediaPodDemo/Images.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "1x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "2x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "1x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "2x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "1x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: ios/IJKMediaPodDemo/IJKMediaPodDemo/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier tv.danmaku.$(PRODUCT_NAME:rfc1034identifier) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: ios/IJKMediaPodDemo/IJKMediaPodDemo/ViewController.h ================================================ // // ViewController.h // IJKMediaPodDemo // // Created by Zhang Rui on 15/7/23. // Copyright (c) 2015年 Zhang Rui. All rights reserved. // #import @interface ViewController : UIViewController @end ================================================ FILE: ios/IJKMediaPodDemo/IJKMediaPodDemo/ViewController.m ================================================ // // ViewController.m // IJKMediaPodDemo // // Created by Zhang Rui on 15/7/23. // Copyright (c) 2015年 Zhang Rui. All rights reserved. // #import "ViewController.h" #import @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. id playback = [[IJKFFMoviePlayerController alloc] initWithContentURL:nil withOptions:nil]; [playback shutdown]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end ================================================ FILE: ios/IJKMediaPodDemo/IJKMediaPodDemo/main.m ================================================ // // main.m // IJKMediaPodDemo // // Created by Zhang Rui on 15/7/23. // Copyright (c) 2015年 Zhang Rui. All rights reserved. // #import #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ================================================ FILE: ios/IJKMediaPodDemo/IJKMediaPodDemo.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 3254039E620E12D7E1E62FC4 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E676A9CBD9C96C0D97C7071 /* libPods.a */; }; E63399A51B60E790008F50CE /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E63399A41B60E790008F50CE /* main.m */; }; E63399A81B60E790008F50CE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E63399A71B60E790008F50CE /* AppDelegate.m */; }; E63399AB1B60E790008F50CE /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E63399AA1B60E790008F50CE /* ViewController.m */; }; E63399AE1B60E790008F50CE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E63399AC1B60E790008F50CE /* Main.storyboard */; }; E63399B01B60E790008F50CE /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E63399AF1B60E790008F50CE /* Images.xcassets */; }; E63399B31B60E790008F50CE /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = E63399B11B60E790008F50CE /* LaunchScreen.xib */; }; E63399BF1B60E790008F50CE /* IJKMediaPodDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E63399BE1B60E790008F50CE /* IJKMediaPodDemoTests.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ E63399B91B60E790008F50CE /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = E63399971B60E790008F50CE /* Project object */; proxyType = 1; remoteGlobalIDString = E633999E1B60E790008F50CE; remoteInfo = IJKMediaPodDemo; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 47C5C1BCE477FD39847AD2F8 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; 7E676A9CBD9C96C0D97C7071 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; E633999F1B60E790008F50CE /* IJKMediaPodDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IJKMediaPodDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; E63399A31B60E790008F50CE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; E63399A41B60E790008F50CE /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; E63399A61B60E790008F50CE /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; E63399A71B60E790008F50CE /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; E63399A91B60E790008F50CE /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; E63399AA1B60E790008F50CE /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; E63399AD1B60E790008F50CE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; E63399AF1B60E790008F50CE /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; E63399B21B60E790008F50CE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; E63399B81B60E790008F50CE /* IJKMediaPodDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IJKMediaPodDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; E63399BD1B60E790008F50CE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; E63399BE1B60E790008F50CE /* IJKMediaPodDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJKMediaPodDemoTests.m; sourceTree = ""; }; EAB805C5FAE107E60F65BC10 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ E633999C1B60E790008F50CE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 3254039E620E12D7E1E62FC4 /* libPods.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; E63399B51B60E790008F50CE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ A58489F820FCBD11F986D498 /* Pods */ = { isa = PBXGroup; children = ( 47C5C1BCE477FD39847AD2F8 /* Pods.debug.xcconfig */, EAB805C5FAE107E60F65BC10 /* Pods.release.xcconfig */, ); name = Pods; sourceTree = ""; }; E63399961B60E790008F50CE = { isa = PBXGroup; children = ( E63399A11B60E790008F50CE /* IJKMediaPodDemo */, E63399BB1B60E790008F50CE /* IJKMediaPodDemoTests */, E63399A01B60E790008F50CE /* Products */, A58489F820FCBD11F986D498 /* Pods */, E9A894D41E27E605A44A8673 /* Frameworks */, ); sourceTree = ""; }; E63399A01B60E790008F50CE /* Products */ = { isa = PBXGroup; children = ( E633999F1B60E790008F50CE /* IJKMediaPodDemo.app */, E63399B81B60E790008F50CE /* IJKMediaPodDemoTests.xctest */, ); name = Products; sourceTree = ""; }; E63399A11B60E790008F50CE /* IJKMediaPodDemo */ = { isa = PBXGroup; children = ( E63399A61B60E790008F50CE /* AppDelegate.h */, E63399A71B60E790008F50CE /* AppDelegate.m */, E63399A91B60E790008F50CE /* ViewController.h */, E63399AA1B60E790008F50CE /* ViewController.m */, E63399AC1B60E790008F50CE /* Main.storyboard */, E63399AF1B60E790008F50CE /* Images.xcassets */, E63399B11B60E790008F50CE /* LaunchScreen.xib */, E63399A21B60E790008F50CE /* Supporting Files */, ); path = IJKMediaPodDemo; sourceTree = ""; }; E63399A21B60E790008F50CE /* Supporting Files */ = { isa = PBXGroup; children = ( E63399A31B60E790008F50CE /* Info.plist */, E63399A41B60E790008F50CE /* main.m */, ); name = "Supporting Files"; sourceTree = ""; }; E63399BB1B60E790008F50CE /* IJKMediaPodDemoTests */ = { isa = PBXGroup; children = ( E63399BE1B60E790008F50CE /* IJKMediaPodDemoTests.m */, E63399BC1B60E790008F50CE /* Supporting Files */, ); path = IJKMediaPodDemoTests; sourceTree = ""; }; E63399BC1B60E790008F50CE /* Supporting Files */ = { isa = PBXGroup; children = ( E63399BD1B60E790008F50CE /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; E9A894D41E27E605A44A8673 /* Frameworks */ = { isa = PBXGroup; children = ( 7E676A9CBD9C96C0D97C7071 /* libPods.a */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ E633999E1B60E790008F50CE /* IJKMediaPodDemo */ = { isa = PBXNativeTarget; buildConfigurationList = E63399C21B60E790008F50CE /* Build configuration list for PBXNativeTarget "IJKMediaPodDemo" */; buildPhases = ( 4F73080015A4CAFB5E66E708 /* Check Pods Manifest.lock */, E633999B1B60E790008F50CE /* Sources */, E633999C1B60E790008F50CE /* Frameworks */, E633999D1B60E790008F50CE /* Resources */, 82155C5704F0DE61754A7A12 /* Copy Pods Resources */, ); buildRules = ( ); dependencies = ( ); name = IJKMediaPodDemo; productName = IJKMediaPodDemo; productReference = E633999F1B60E790008F50CE /* IJKMediaPodDemo.app */; productType = "com.apple.product-type.application"; }; E63399B71B60E790008F50CE /* IJKMediaPodDemoTests */ = { isa = PBXNativeTarget; buildConfigurationList = E63399C51B60E790008F50CE /* Build configuration list for PBXNativeTarget "IJKMediaPodDemoTests" */; buildPhases = ( E63399B41B60E790008F50CE /* Sources */, E63399B51B60E790008F50CE /* Frameworks */, E63399B61B60E790008F50CE /* Resources */, ); buildRules = ( ); dependencies = ( E63399BA1B60E790008F50CE /* PBXTargetDependency */, ); name = IJKMediaPodDemoTests; productName = IJKMediaPodDemoTests; productReference = E63399B81B60E790008F50CE /* IJKMediaPodDemoTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ E63399971B60E790008F50CE /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0640; ORGANIZATIONNAME = "Zhang Rui"; TargetAttributes = { E633999E1B60E790008F50CE = { CreatedOnToolsVersion = 6.4; }; E63399B71B60E790008F50CE = { CreatedOnToolsVersion = 6.4; TestTargetID = E633999E1B60E790008F50CE; }; }; }; buildConfigurationList = E633999A1B60E790008F50CE /* Build configuration list for PBXProject "IJKMediaPodDemo" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = E63399961B60E790008F50CE; productRefGroup = E63399A01B60E790008F50CE /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( E633999E1B60E790008F50CE /* IJKMediaPodDemo */, E63399B71B60E790008F50CE /* IJKMediaPodDemoTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ E633999D1B60E790008F50CE /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( E63399AE1B60E790008F50CE /* Main.storyboard in Resources */, E63399B31B60E790008F50CE /* LaunchScreen.xib in Resources */, E63399B01B60E790008F50CE /* Images.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; E63399B61B60E790008F50CE /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 4F73080015A4CAFB5E66E708 /* Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; 82155C5704F0DE61754A7A12 /* Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ E633999B1B60E790008F50CE /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E63399AB1B60E790008F50CE /* ViewController.m in Sources */, E63399A81B60E790008F50CE /* AppDelegate.m in Sources */, E63399A51B60E790008F50CE /* main.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; E63399B41B60E790008F50CE /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E63399BF1B60E790008F50CE /* IJKMediaPodDemoTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ E63399BA1B60E790008F50CE /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = E633999E1B60E790008F50CE /* IJKMediaPodDemo */; targetProxy = E63399B91B60E790008F50CE /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ E63399AC1B60E790008F50CE /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( E63399AD1B60E790008F50CE /* Base */, ); name = Main.storyboard; sourceTree = ""; }; E63399B11B60E790008F50CE /* LaunchScreen.xib */ = { isa = PBXVariantGroup; children = ( E63399B21B60E790008F50CE /* Base */, ); name = LaunchScreen.xib; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ E63399C01B60E790008F50CE /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.4; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; E63399C11B60E790008F50CE /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.4; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; E63399C31B60E790008F50CE /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 47C5C1BCE477FD39847AD2F8 /* Pods.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = IJKMediaPodDemo/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; E63399C41B60E790008F50CE /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = EAB805C5FAE107E60F65BC10 /* Pods.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = IJKMediaPodDemo/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; E63399C61B60E790008F50CE /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = IJKMediaPodDemoTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/IJKMediaPodDemo.app/IJKMediaPodDemo"; }; name = Debug; }; E63399C71B60E790008F50CE /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); INFOPLIST_FILE = IJKMediaPodDemoTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/IJKMediaPodDemo.app/IJKMediaPodDemo"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ E633999A1B60E790008F50CE /* Build configuration list for PBXProject "IJKMediaPodDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( E63399C01B60E790008F50CE /* Debug */, E63399C11B60E790008F50CE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; E63399C21B60E790008F50CE /* Build configuration list for PBXNativeTarget "IJKMediaPodDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( E63399C31B60E790008F50CE /* Debug */, E63399C41B60E790008F50CE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; E63399C51B60E790008F50CE /* Build configuration list for PBXNativeTarget "IJKMediaPodDemoTests" */ = { isa = XCConfigurationList; buildConfigurations = ( E63399C61B60E790008F50CE /* Debug */, E63399C71B60E790008F50CE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = E63399971B60E790008F50CE /* Project object */; } ================================================ FILE: ios/IJKMediaPodDemo/IJKMediaPodDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: ios/IJKMediaPodDemo/IJKMediaPodDemoTests/IJKMediaPodDemoTests.m ================================================ // // IJKMediaPodDemoTests.m // IJKMediaPodDemoTests // // Created by Zhang Rui on 15/7/23. // Copyright (c) 2015年 Zhang Rui. All rights reserved. // #import #import @interface IJKMediaPodDemoTests : XCTestCase @end @implementation IJKMediaPodDemoTests - (void)setUp { [super setUp]; // Put setup code here. This method is called before the invocation of each test method in the class. } - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the class. [super tearDown]; } - (void)testExample { // This is an example of a functional test case. XCTAssert(YES, @"Pass"); } - (void)testPerformanceExample { // This is an example of a performance test case. [self measureBlock:^{ // Put the code you want to measure the time of here. }]; } @end ================================================ FILE: ios/IJKMediaPodDemo/IJKMediaPodDemoTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier tv.danmaku.$(PRODUCT_NAME:rfc1034identifier) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: ios/IJKMediaPodDemo/Podfile ================================================ source 'https://github.com/CocoaPods/Specs.git' # source platform :ios, '8.0' pod 'ijkplayer', '~> 0.3.2-rc.2' ================================================ FILE: ios/compile-ffmpeg.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2014 Bilibili # Copyright (C) 2013-2014 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # #---------- # modify for your build tool FF_ALL_ARCHS_IOS6_SDK="armv7 armv7s i386" FF_ALL_ARCHS_IOS7_SDK="armv7 armv7s arm64 i386 x86_64" FF_ALL_ARCHS_IOS8_SDK="armv7 arm64 i386 x86_64" FF_ALL_ARCHS=$FF_ALL_ARCHS_IOS8_SDK #---------- UNI_BUILD_ROOT=`pwd` UNI_TMP="$UNI_BUILD_ROOT/tmp" UNI_TMP_LLVM_VER_FILE="$UNI_TMP/llvm.ver.txt" FF_TARGET=$1 FF_TARGET_EXTRA=$2 set -e #---------- echo_archs() { echo "====================" echo "[*] check xcode version" echo "====================" echo "FF_ALL_ARCHS = $FF_ALL_ARCHS" } FF_LIBS="libavcodec libavfilter libavformat libavutil libswscale libswresample" do_lipo_ffmpeg () { LIB_FILE=$1 LIPO_FLAGS= for ARCH in $FF_ALL_ARCHS do ARCH_LIB_FILE="$UNI_BUILD_ROOT/build/ffmpeg-$ARCH/output/lib/$LIB_FILE" if [ -f "$ARCH_LIB_FILE" ]; then LIPO_FLAGS="$LIPO_FLAGS $ARCH_LIB_FILE" else echo "skip $LIB_FILE of $ARCH"; fi done xcrun lipo -create $LIPO_FLAGS -output $UNI_BUILD_ROOT/build/universal/lib/$LIB_FILE xcrun lipo -info $UNI_BUILD_ROOT/build/universal/lib/$LIB_FILE } SSL_LIBS="libcrypto libssl" do_lipo_ssl () { LIB_FILE=$1 LIPO_FLAGS= for ARCH in $FF_ALL_ARCHS do ARCH_LIB_FILE="$UNI_BUILD_ROOT/build/openssl-$ARCH/output/lib/$LIB_FILE" if [ -f "$ARCH_LIB_FILE" ]; then LIPO_FLAGS="$LIPO_FLAGS $ARCH_LIB_FILE" else echo "skip $LIB_FILE of $ARCH"; fi done if [ "$LIPO_FLAGS" != "" ]; then xcrun lipo -create $LIPO_FLAGS -output $UNI_BUILD_ROOT/build/universal/lib/$LIB_FILE xcrun lipo -info $UNI_BUILD_ROOT/build/universal/lib/$LIB_FILE fi } do_lipo_all () { mkdir -p $UNI_BUILD_ROOT/build/universal/lib echo "lipo archs: $FF_ALL_ARCHS" for FF_LIB in $FF_LIBS do do_lipo_ffmpeg "$FF_LIB.a"; done ANY_ARCH= for ARCH in $FF_ALL_ARCHS do ARCH_INC_DIR="$UNI_BUILD_ROOT/build/ffmpeg-$ARCH/output/include" if [ -d "$ARCH_INC_DIR" ]; then if [ -z "$ANY_ARCH" ]; then ANY_ARCH=$ARCH cp -R "$ARCH_INC_DIR" "$UNI_BUILD_ROOT/build/universal/" fi UNI_INC_DIR="$UNI_BUILD_ROOT/build/universal/include" mkdir -p "$UNI_INC_DIR/libavutil/$ARCH" cp -f "$ARCH_INC_DIR/libavutil/avconfig.h" "$UNI_INC_DIR/libavutil/$ARCH/avconfig.h" cp -f tools/avconfig.h "$UNI_INC_DIR/libavutil/avconfig.h" cp -f "$ARCH_INC_DIR/libavutil/ffversion.h" "$UNI_INC_DIR/libavutil/$ARCH/ffversion.h" cp -f tools/ffversion.h "$UNI_INC_DIR/libavutil/ffversion.h" mkdir -p "$UNI_INC_DIR/libffmpeg/$ARCH" cp -f "$ARCH_INC_DIR/libffmpeg/config.h" "$UNI_INC_DIR/libffmpeg/$ARCH/config.h" cp -f tools/config.h "$UNI_INC_DIR/libffmpeg/config.h" fi done for SSL_LIB in $SSL_LIBS do do_lipo_ssl "$SSL_LIB.a"; done } #---------- if [ "$FF_TARGET" = "armv7" -o "$FF_TARGET" = "armv7s" -o "$FF_TARGET" = "arm64" ]; then echo_archs sh tools/do-compile-ffmpeg.sh $FF_TARGET $FF_TARGET_EXTRA do_lipo_all elif [ "$FF_TARGET" = "i386" -o "$FF_TARGET" = "x86_64" ]; then echo_archs sh tools/do-compile-ffmpeg.sh $FF_TARGET $FF_TARGET_EXTRA do_lipo_all elif [ "$FF_TARGET" = "lipo" ]; then echo_archs do_lipo_all elif [ "$FF_TARGET" = "all" ]; then echo_archs for ARCH in $FF_ALL_ARCHS do sh tools/do-compile-ffmpeg.sh $ARCH $FF_TARGET_EXTRA done do_lipo_all elif [ "$FF_TARGET" = "check" ]; then echo_archs elif [ "$FF_TARGET" = "clean" ]; then echo_archs echo "==================" for ARCH in $FF_ALL_ARCHS do echo "clean ffmpeg-$ARCH" echo "==================" cd ffmpeg-$ARCH && git clean -xdf && cd - done echo "clean build cache" echo "=================" rm -rf build/ffmpeg-* rm -rf build/openssl-* rm -rf build/universal/include rm -rf build/universal/lib echo "clean success" else echo "Usage:" echo " compile-ffmpeg.sh armv7|arm64|i386|x86_64" echo " compile-ffmpeg.sh armv7s (obselete)" echo " compile-ffmpeg.sh lipo" echo " compile-ffmpeg.sh all" echo " compile-ffmpeg.sh clean" echo " compile-ffmpeg.sh check" exit 1 fi ================================================ FILE: ios/compile-openssl.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2014 Bilibili # Copyright (C) 2013-2014 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # #---------- # modify for your build tool FF_ALL_ARCHS_IOS6_SDK="armv7 armv7s i386" FF_ALL_ARCHS_IOS7_SDK="armv7 armv7s arm64 i386 x86_64" FF_ALL_ARCHS_IOS8_SDK="armv7 arm64 i386 x86_64" FF_ALL_ARCHS=$FF_ALL_ARCHS_IOS8_SDK #---------- UNI_BUILD_ROOT=`pwd` UNI_TMP="$UNI_BUILD_ROOT/tmp" UNI_TMP_LLVM_VER_FILE="$UNI_TMP/llvm.ver.txt" FF_TARGET=$1 set -e #---------- FF_LIBS="libssl libcrypto" #---------- echo_archs() { echo "====================" echo "[*] check xcode version" echo "====================" echo "FF_ALL_ARCHS = $FF_ALL_ARCHS" } do_lipo () { LIB_FILE=$1 LIPO_FLAGS= for ARCH in $FF_ALL_ARCHS do LIPO_FLAGS="$LIPO_FLAGS $UNI_BUILD_ROOT/build/openssl-$ARCH/output/lib/$LIB_FILE" done xcrun lipo -create $LIPO_FLAGS -output $UNI_BUILD_ROOT/build/universal/lib/$LIB_FILE xcrun lipo -info $UNI_BUILD_ROOT/build/universal/lib/$LIB_FILE } do_lipo_all () { mkdir -p $UNI_BUILD_ROOT/build/universal/lib echo "lipo archs: $FF_ALL_ARCHS" for FF_LIB in $FF_LIBS do do_lipo "$FF_LIB.a"; done cp -R $UNI_BUILD_ROOT/build/openssl-armv7/output/include $UNI_BUILD_ROOT/build/universal/ } #---------- if [ "$FF_TARGET" = "armv7" -o "$FF_TARGET" = "armv7s" -o "$FF_TARGET" = "arm64" ]; then echo_archs sh tools/do-compile-openssl.sh $FF_TARGET elif [ "$FF_TARGET" = "i386" -o "$FF_TARGET" = "x86_64" ]; then echo_archs sh tools/do-compile-openssl.sh $FF_TARGET elif [ "$FF_TARGET" = "lipo" ]; then echo_archs do_lipo_all elif [ "$FF_TARGET" = "all" ]; then echo_archs for ARCH in $FF_ALL_ARCHS do sh tools/do-compile-openssl.sh $ARCH done do_lipo_all elif [ "$FF_TARGET" = "check" ]; then echo_archs elif [ "$FF_TARGET" = "clean" ]; then echo_archs for ARCH in $FF_ALL_ARCHS do cd openssl-$ARCH && git clean -xdf && cd - done else echo "Usage:" echo " compile-openssl.sh armv7|arm64|i386|x86_64" echo " compile-openssl.sh armv7s (obselete)" echo " compile-openssl.sh lipo" echo " compile-openssl.sh all" echo " compile-openssl.sh clean" echo " compile-openssl.sh check" exit 1 fi ================================================ FILE: ios/tools/avconfig.h ================================================ /* * avconfig.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #if defined(__aarch64__) # include "arm64/avconfig.h" #elif defined(__x86_64__) # include "x86_64/avconfig.h" #elif defined(__arm__) # if defined(__ARM_ARCH_7S__) # include "armv7s/avconfig.h" # elif defined(__ARM_ARCH) # if __ARM_ARCH == 7 # include "armv7/avconfig.h" # else # error Unsupport ARM architecture # endif # else # error Unsupport ARM architecture # endif #elif defined(__i386__) # include "i386/avconfig.h" #else # error Unsupport architecture #endif ================================================ FILE: ios/tools/config.h ================================================ /* * config.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #if defined(__aarch64__) # include "arm64/config.h" #elif defined(__x86_64__) # include "x86_64/config.h" #elif defined(__arm__) # if defined(__ARM_ARCH_7S__) # include "armv7s/config.h" # elif defined(__ARM_ARCH) # if __ARM_ARCH == 7 # include "armv7/config.h" # else # error Unsupport ARM architecture # endif # else # error Unsupport ARM architecture # endif #elif defined(__i386__) # include "i386/config.h" #else # error Unsupport architecture #endif ================================================ FILE: ios/tools/do-compile-ffmpeg.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2014 Bilibili # Copyright (C) 2013-2014 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # This script is based on projects below # https://github.com/kolyvan/kxmovie # https://github.com/yixia/FFmpeg-Android # http://git.videolan.org/?p=vlc-ports/android.git;a=summary # https://github.com/kewlbear/FFmpeg-iOS-build-script/ #-------------------- echo "====================" echo "[*] check host" echo "====================" set -e #-------------------- # include #-------------------- # common defines FF_ARCH=$1 FF_BUILD_OPT=$2 echo "FF_ARCH=$FF_ARCH" echo "FF_BUILD_OPT=$FF_BUILD_OPT" if [ -z "$FF_ARCH" ]; then echo "You must specific an architecture 'armv7, armv7s, arm64, i386, x86_64, ...'.\n" exit 1 fi FF_BUILD_ROOT=`pwd` FF_TAGET_OS="darwin" # ffmpeg build params export COMMON_FF_CFG_FLAGS= source $FF_BUILD_ROOT/../config/module.sh FFMPEG_CFG_FLAGS= FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS $COMMON_FF_CFG_FLAGS" # Optimization options (experts only): # FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS --disable-armv5te" # FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS --disable-armv6" # FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS --disable-armv6t2" # Advanced options (experts only): FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS --enable-cross-compile" # --disable-symver may indicate a bug # FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS --disable-symver" # Developer options (useful when working on FFmpeg itself): FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS --disable-stripping" ## FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS --arch=$FF_ARCH" FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS --target-os=$FF_TAGET_OS" FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS --enable-static" FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS --disable-shared" FFMPEG_EXTRA_CFLAGS= # i386, x86_64 FFMPEG_CFG_FLAGS_SIMULATOR= FFMPEG_CFG_FLAGS_SIMULATOR="$FFMPEG_CFG_FLAGS_SIMULATOR --disable-asm" FFMPEG_CFG_FLAGS_SIMULATOR="$FFMPEG_CFG_FLAGS_SIMULATOR --disable-mmx" FFMPEG_CFG_FLAGS_SIMULATOR="$FFMPEG_CFG_FLAGS_SIMULATOR --assert-level=2" # armv7, armv7s, arm64 FFMPEG_CFG_FLAGS_ARM= FFMPEG_CFG_FLAGS_ARM="$FFMPEG_CFG_FLAGS_ARM --enable-pic" FFMPEG_CFG_FLAGS_ARM="$FFMPEG_CFG_FLAGS_ARM --enable-neon" case "$FF_BUILD_OPT" in debug) FFMPEG_CFG_FLAGS_ARM="$FFMPEG_CFG_FLAGS_ARM --disable-optimizations" FFMPEG_CFG_FLAGS_ARM="$FFMPEG_CFG_FLAGS_ARM --enable-debug" FFMPEG_CFG_FLAGS_ARM="$FFMPEG_CFG_FLAGS_ARM --disable-small" ;; *) FFMPEG_CFG_FLAGS_ARM="$FFMPEG_CFG_FLAGS_ARM --enable-optimizations" FFMPEG_CFG_FLAGS_ARM="$FFMPEG_CFG_FLAGS_ARM --enable-debug" FFMPEG_CFG_FLAGS_ARM="$FFMPEG_CFG_FLAGS_ARM --enable-small" ;; esac echo "build_root: $FF_BUILD_ROOT" #-------------------- echo "====================" echo "[*] check gas-preprocessor" echo "====================" FF_TOOLS_ROOT="$FF_BUILD_ROOT/../extra" export PATH="$FF_TOOLS_ROOT/gas-preprocessor:$PATH" echo "gasp: $FF_TOOLS_ROOT/gas-preprocessor/gas-preprocessor.pl" #-------------------- echo "====================" echo "[*] config arch $FF_ARCH" echo "====================" FF_BUILD_NAME="unknown" FF_XCRUN_PLATFORM="iPhoneOS" FF_XCRUN_OSVERSION= FF_GASPP_EXPORT= FF_DEP_OPENSSL_INC= FF_DEP_OPENSSL_LIB= FF_XCODE_BITCODE= if [ "$FF_ARCH" = "i386" ]; then FF_BUILD_NAME="ffmpeg-i386" FF_BUILD_NAME_OPENSSL=openssl-i386 FF_XCRUN_PLATFORM="iPhoneSimulator" FF_XCRUN_OSVERSION="-mios-simulator-version-min=6.0" FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS $FFMPEG_CFG_FLAGS_SIMULATOR" elif [ "$FF_ARCH" = "x86_64" ]; then FF_BUILD_NAME="ffmpeg-x86_64" FF_BUILD_NAME_OPENSSL=openssl-x86_64 FF_XCRUN_PLATFORM="iPhoneSimulator" FF_XCRUN_OSVERSION="-mios-simulator-version-min=7.0" FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS $FFMPEG_CFG_FLAGS_SIMULATOR" elif [ "$FF_ARCH" = "armv7" ]; then FF_BUILD_NAME="ffmpeg-armv7" FF_BUILD_NAME_OPENSSL=openssl-armv7 FF_XCRUN_OSVERSION="-miphoneos-version-min=6.0" FF_XCODE_BITCODE="-fembed-bitcode" FFMPEG_CFG_FLAGS_ARM="$FFMPEG_CFG_FLAGS_ARM --disable-asm" FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS $FFMPEG_CFG_FLAGS_ARM" # FFMPEG_CFG_CPU="--cpu=cortex-a8" elif [ "$FF_ARCH" = "armv7s" ]; then FF_BUILD_NAME="ffmpeg-armv7s" FF_BUILD_NAME_OPENSSL=openssl-armv7s FFMPEG_CFG_CPU="--cpu=swift" FF_XCRUN_OSVERSION="-miphoneos-version-min=6.0" FF_XCODE_BITCODE="-fembed-bitcode" FFMPEG_CFG_FLAGS_ARM="$FFMPEG_CFG_FLAGS_ARM --disable-asm" FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS $FFMPEG_CFG_FLAGS_ARM" elif [ "$FF_ARCH" = "arm64" ]; then FF_BUILD_NAME="ffmpeg-arm64" FF_BUILD_NAME_OPENSSL=openssl-arm64 FF_XCRUN_OSVERSION="-miphoneos-version-min=7.0" FF_XCODE_BITCODE="-fembed-bitcode" FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS $FFMPEG_CFG_FLAGS_ARM" FF_GASPP_EXPORT="GASPP_FIX_XCODE5=1" else echo "unknown architecture $FF_ARCH"; exit 1 fi echo "build_name: $FF_BUILD_NAME" echo "platform: $FF_XCRUN_PLATFORM" echo "osversion: $FF_XCRUN_OSVERSION" #-------------------- echo "====================" echo "[*] make ios toolchain $FF_BUILD_NAME" echo "====================" FF_BUILD_SOURCE="$FF_BUILD_ROOT/$FF_BUILD_NAME" FF_BUILD_PREFIX="$FF_BUILD_ROOT/build/$FF_BUILD_NAME/output" FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS --prefix=$FF_BUILD_PREFIX" mkdir -p $FF_BUILD_PREFIX echo "build_source: $FF_BUILD_SOURCE" echo "build_prefix: $FF_BUILD_PREFIX" #-------------------- echo "\n--------------------" echo "[*] configurate ffmpeg" echo "--------------------" FF_XCRUN_SDK=`echo $FF_XCRUN_PLATFORM | tr '[:upper:]' '[:lower:]'` FF_XCRUN_CC="xcrun -sdk $FF_XCRUN_SDK clang" FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS $FFMPEG_CFG_CPU" FFMPEG_CFLAGS= FFMPEG_CFLAGS="$FFMPEG_CFLAGS -arch $FF_ARCH" FFMPEG_CFLAGS="$FFMPEG_CFLAGS $FF_XCRUN_OSVERSION" FFMPEG_CFLAGS="$FFMPEG_CFLAGS $FFMPEG_EXTRA_CFLAGS" FFMPEG_CFLAGS="$FFMPEG_CFLAGS $FF_XCODE_BITCODE" FFMPEG_LDFLAGS="$FFMPEG_CFLAGS" FFMPEG_DEP_LIBS= #-------------------- echo "\n--------------------" echo "[*] check OpenSSL" echo "----------------------" FFMPEG_DEP_OPENSSL_INC=$FF_BUILD_ROOT/build/$FF_BUILD_NAME_OPENSSL/output/include FFMPEG_DEP_OPENSSL_LIB=$FF_BUILD_ROOT/build/$FF_BUILD_NAME_OPENSSL/output/lib #-------------------- # with openssl if [ -f "${FFMPEG_DEP_OPENSSL_LIB}/libssl.a" ]; then FFMPEG_CFG_FLAGS="$FFMPEG_CFG_FLAGS --enable-openssl" FFMPEG_CFLAGS="$FFMPEG_CFLAGS -I${FFMPEG_DEP_OPENSSL_INC}" FFMPEG_DEP_LIBS="$FFMPEG_CFLAGS -L${FFMPEG_DEP_OPENSSL_LIB} -lssl -lcrypto" fi #-------------------- echo "\n--------------------" echo "[*] configure" echo "----------------------" if [ ! -d $FF_BUILD_SOURCE ]; then echo "" echo "!! ERROR" echo "!! Can not find FFmpeg directory for $FF_BUILD_NAME" echo "!! Run 'sh init-ios.sh' first" echo "" exit 1 fi # xcode configuration export DEBUG_INFORMATION_FORMAT=dwarf-with-dsym cd $FF_BUILD_SOURCE if [ -f "./config.h" ]; then echo 'reuse configure' else echo "config: $FFMPEG_CFG_FLAGS $FF_XCRUN_CC" ./configure \ $FFMPEG_CFG_FLAGS \ --cc="$FF_XCRUN_CC" \ $FFMPEG_CFG_CPU \ --extra-cflags="$FFMPEG_CFLAGS" \ --extra-cxxflags="$FFMPEG_CFLAGS" \ --extra-ldflags="$FFMPEG_LDFLAGS $FFMPEG_DEP_LIBS" make clean fi #-------------------- echo "\n--------------------" echo "[*] compile ffmpeg" echo "--------------------" cp config.* $FF_BUILD_PREFIX make -j3 $FF_GASPP_EXPORT make install mkdir -p $FF_BUILD_PREFIX/include/libffmpeg cp -f config.h $FF_BUILD_PREFIX/include/libffmpeg/config.h ================================================ FILE: ios/tools/do-compile-openssl.sh ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2014 Bilibili # Copyright (C) 2013-2014 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # This script is based on projects below # https://github.com/x2on/OpenSSL-for-iPhone #-------------------- echo "====================" echo "[*] check host" echo "====================" set -e FF_XCRUN_DEVELOPER=`xcode-select -print-path` if [ ! -d "$FF_XCRUN_DEVELOPER" ]; then echo "xcode path is not set correctly $FF_XCRUN_DEVELOPER does not exist (most likely because of xcode > 4.3)" echo "run" echo "sudo xcode-select -switch " echo "for default installation:" echo "sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer" exit 1 fi case $FF_XCRUN_DEVELOPER in *\ * ) echo "Your Xcode path contains whitespaces, which is not supported." exit 1 ;; esac #-------------------- # include #-------------------- # common defines FF_ARCH=$1 if [ -z "$FF_ARCH" ]; then echo "You must specific an architecture 'armv7, armv7s, arm64, i386, x86_64, ...'.\n" exit 1 fi FF_BUILD_ROOT=`pwd` FF_TAGET_OS="darwin" # openssl build params export COMMON_FF_CFG_FLAGS= OPENSSL_CFG_FLAGS= OPENSSL_EXTRA_CFLAGS= OPENSSL_CFG_CPU= # i386, x86_64 OPENSSL_CFG_FLAGS_SIMULATOR= # armv7, armv7s, arm64 OPENSSL_CFG_FLAGS_ARM= OPENSSL_CFG_FLAGS_ARM="iphoneos-cross" echo "build_root: $FF_BUILD_ROOT" #-------------------- echo "====================" echo "[*] config arch $FF_ARCH" echo "====================" FF_BUILD_NAME="unknown" FF_XCRUN_PLATFORM="iPhoneOS" FF_XCRUN_OSVERSION= FF_GASPP_EXPORT= FF_XCODE_BITCODE= if [ "$FF_ARCH" = "i386" ]; then FF_BUILD_NAME="openssl-i386" FF_XCRUN_PLATFORM="iPhoneSimulator" FF_XCRUN_OSVERSION="-mios-simulator-version-min=6.0" OPENSSL_CFG_FLAGS="darwin-i386-cc $OPENSSL_CFG_FLAGS" elif [ "$FF_ARCH" = "x86_64" ]; then FF_BUILD_NAME="openssl-x86_64" FF_XCRUN_PLATFORM="iPhoneSimulator" FF_XCRUN_OSVERSION="-mios-simulator-version-min=7.0" OPENSSL_CFG_FLAGS="darwin64-x86_64-cc $OPENSSL_CFG_FLAGS" elif [ "$FF_ARCH" = "armv7" ]; then FF_BUILD_NAME="openssl-armv7" FF_XCRUN_OSVERSION="-miphoneos-version-min=6.0" FF_XCODE_BITCODE="-fembed-bitcode" OPENSSL_CFG_FLAGS="$OPENSSL_CFG_FLAGS_ARM $OPENSSL_CFG_FLAGS" # OPENSSL_CFG_CPU="--cpu=cortex-a8" elif [ "$FF_ARCH" = "armv7s" ]; then FF_BUILD_NAME="openssl-armv7s" OPENSSL_CFG_CPU="--cpu=swift" FF_XCRUN_OSVERSION="-miphoneos-version-min=6.0" FF_XCODE_BITCODE="-fembed-bitcode" OPENSSL_CFG_FLAGS="$OPENSSL_CFG_FLAGS_ARM $OPENSSL_CFG_FLAGS" elif [ "$FF_ARCH" = "arm64" ]; then FF_BUILD_NAME="openssl-arm64" FF_XCRUN_OSVERSION="-miphoneos-version-min=7.0" FF_XCODE_BITCODE="-fembed-bitcode" OPENSSL_CFG_FLAGS="$OPENSSL_CFG_FLAGS_ARM $OPENSSL_CFG_FLAGS" FF_GASPP_EXPORT="GASPP_FIX_XCODE5=1" else echo "unknown architecture $FF_ARCH"; exit 1 fi echo "build_name: $FF_BUILD_NAME" echo "platform: $FF_XCRUN_PLATFORM" echo "osversion: $FF_XCRUN_OSVERSION" #-------------------- echo "====================" echo "[*] make ios toolchain $FF_BUILD_NAME" echo "====================" FF_BUILD_SOURCE="$FF_BUILD_ROOT/$FF_BUILD_NAME" FF_BUILD_PREFIX="$FF_BUILD_ROOT/build/$FF_BUILD_NAME/output" mkdir -p $FF_BUILD_PREFIX FF_XCRUN_SDK=`echo $FF_XCRUN_PLATFORM | tr '[:upper:]' '[:lower:]'` FF_XCRUN_SDK_PLATFORM_PATH=`xcrun -sdk $FF_XCRUN_SDK --show-sdk-platform-path` FF_XCRUN_SDK_PATH=`xcrun -sdk $FF_XCRUN_SDK --show-sdk-path` FF_XCRUN_CC="xcrun -sdk $FF_XCRUN_SDK clang" export CROSS_TOP="$FF_XCRUN_SDK_PLATFORM_PATH/Developer" export CROSS_SDK=`echo ${FF_XCRUN_SDK_PATH/#$CROSS_TOP\/SDKs\//}` export BUILD_TOOL="$FF_XCRUN_DEVELOPER" export CC="$FF_XCRUN_CC -arch $FF_ARCH $FF_XCRUN_OSVERSION" echo "build_source: $FF_BUILD_SOURCE" echo "build_prefix: $FF_BUILD_PREFIX" echo "CROSS_TOP: $CROSS_TOP" echo "CROSS_SDK: $CROSS_SDK" echo "BUILD_TOOL: $BUILD_TOOL" echo "CC: $CC" #-------------------- echo "\n--------------------" echo "[*] configurate openssl" echo "--------------------" OPENSSL_CFG_FLAGS="$OPENSSL_CFG_FLAGS $FF_XCODE_BITCODE" OPENSSL_CFG_FLAGS="$OPENSSL_CFG_FLAGS --openssldir=$FF_BUILD_PREFIX" # xcode configuration export DEBUG_INFORMATION_FORMAT=dwarf-with-dsym cd $FF_BUILD_SOURCE if [ -f "./Makefile" ]; then echo 'reuse configure' else echo "config: $OPENSSL_CFG_FLAGS" ./Configure \ $OPENSSL_CFG_FLAGS make clean fi #-------------------- echo "\n--------------------" echo "[*] compile openssl" echo "--------------------" set +e make make install_sw ================================================ FILE: ios/tools/ffversion.h ================================================ /* * ffversion.h * * Copyright (c) 2013 Bilibili * Copyright (c) 2013 Zhang Rui * * This file is part of ijkPlayer. * * ijkPlayer 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. * * ijkPlayer 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 ijkPlayer; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #if defined(__aarch64__) # include "arm64/ffversion.h" #elif defined(__x86_64__) # include "x86_64/ffversion.h" #elif defined(__arm__) # if defined(__ARM_ARCH_7S__) # include "armv7s/ffversion.h" # elif defined(__ARM_ARCH_7__) # include "armv7/ffversion.h" # else # error Unsupport ARM architecture # endif #elif defined(__i386__) # include "i386/ffversion.h" #else # error Unsupport architecture #endif ================================================ FILE: tools/.gitignore ================================================ #################### # from gitignore/Python.gitignore #################### # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python env/ build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *,cover .hypothesis/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # pyenv .python-version # celery beat schedule file celerybeat-schedule # dotenv .env # virtualenv .venv/ venv/ ENV/ # Spyder project settings .spyderproject # Rope project settings .ropeproject ================================================ FILE: tools/copyrighter/CRContext.py ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2017 Bilibili # Copyright (C) 2013-2017 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import datetime import os import fnmatch from sets import Set from copyrighter.CRCopyright import CRCopyright class CRContext: file_ext_white_list = Set([ # '*', 'c', 'h', 'java', 'm', 'mk', 'py', 'sh', ]) rel_path_black_list = Set([ '*.a', '*.d', '*.jar', '*.lib', '*.lproj', '*.o', '*.patch', '*.pbxproj', '*.pch', '*.png', '*.pyc', '*.so', '*.strings', '*.xcassets', '*.xcodeproj', '*.xcuserdatad', '*.xcworkspace', '*.xib', 'android/contrib', 'android/ijkplayer/build', 'android/ijkplayer/*/build', 'android/ijkplayer/*/libs', 'android/ijkplayer/*/obj', 'android/ijkplayer/*/res', 'android/patches', 'extra', 'ijkmedia/ijkyuv', 'ijkmedia/ijkj4a', 'ijkprof/android-ndk-profiler', 'ios/build', 'ios/contrib', 'ios/ffmpeg-*', 'ios/openssl-*', ]) def __init__(self, verbose = True, dryrun = True): self.verbose = verbose self.dryrun = dryrun self.root_path = os.path.realpath(os.path.join(__file__, '../../..')) self.year = datetime.date.today().year def get_path_of_file(self, file): if not os.path.isabs(file): file = os.path.realpath(os.path.join(self.root_path, file)) return file def get_relpath(self, file): return os.path.relpath(file, self.root_path) def is_black_path(self, path): rel_path = self.get_relpath(path) for black_item in CRContext.rel_path_black_list: if fnmatch.fnmatch(rel_path, black_item): # print ' + fnmatch %s %s' % (rel_path, black_item) return True # else: # print ' - fnmatch %s %s' % (rel_path, black_item) return False def need_copyright(self, file): if '*' in CRContext.file_ext_white_list: return True ext = os.path.splitext(file)[1][1:] return ext in CRContext.file_ext_white_list def log_file(self, tag, file): if self.verbose: rel_path = self.get_relpath(file) print '%-10s %s' % (tag, rel_path) ================================================ FILE: tools/copyrighter/CRCopyright.py ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2017 Bilibili # Copyright (C) 2013-2017 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import re class CRCopyright: regexp = None def __init__(self, name, url = None, prefix = None, symbol = None, years = None): self.name = name self.url = url self.prefix = prefix self.symbol = symbol self.years = years assert prefix assert symbol assert years assert name def duplicate(self): return CRCopyright( name = self.name, url = self.url, prefix = self.prefix, symbol = self.symbol, years = self.years, ) def get_line(self): line = '%sCopyright %s %s %s' % (self.prefix, self.symbol, self.years, self.name) if self.url: line += ' <%s>' % self.url return line def match_name(self, name): if not self.name or not name: return False return self.name.lower() == name.lower() def match_name(self, url): if not self.url or not url: return False return self.url.lower() == url.lower() @staticmethod def scan_line(context, line): if line[-1] == '\n': line = line[0:-1] if not CRCopyright.regexp: # CRCopyright.regexp = re.compile("^([#\*\/\s]+)Copyright(?:\s+)([\(\)\w]+)(?:\s+)([\d]+|[\d]+-[\d]+)(?:\s+)([\w\s]+)[$|(<[\w\.@]+>)$]") # 1 prefix # 3 symbol # 5 year # 6 name # 7 url CRCopyright.regexp = re.compile( pattern = "^([#\*\/\s]+)Copyright(\s+)([\(\)\w]+)(\s+)([0-9\-]+)([^<]+)(.*)$", flags = re.IGNORECASE, ) m = CRCopyright.regexp.match(line) if m: prefix = m.group(1) symbol = m.group(3).strip() years = m.group(5).strip() name = m.group(6).strip() url = m.group(7).strip().strip('<>') if prefix and symbol and years and name: cr = CRCopyright( prefix = prefix, symbol = symbol, years = years, name = name, url = url, ) return cr # print '>=====' # for i in range(1, 8): # print '> %d "%s"' % (i, match.group(i)) # print '>=====' return None ================================================ FILE: tools/copyrighter/CRFile.py ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2017 Bilibili # Copyright (C) 2013-2017 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import os import shutil from copyrighter.CRCopyright import CRCopyright class CRFile: def __init__(self, context, file): self.dirty = False self.context = context self.abs_path = context.get_path_of_file(file) self.file_ext = os.path.splitext(self.abs_path)[1][1:] self.copyright_names = {} self.copyright_urls = {} self.need_insert_bilibili_copyright = True def update(self): if not self.dirty: self.context.log_file('~ remain', self.abs_path) return tmp_path = self.abs_path + '.tmp' if self.context.dryrun: src = open(self.abs_path, 'r') else: shutil.copy2(self.abs_path, tmp_path) src = open(tmp_path, 'r') tmp = open(self.abs_path, 'w') did_insert_bilibili_copyright = False for line in src: if self.need_insert_bilibili_copyright and not did_insert_bilibili_copyright: copyright = CRCopyright.scan_line(self.context, line) if copyright: copyright.name = 'Bilibili' copyright.url = None if not self.context.dryrun: tmp.write(copyright.get_line()) tmp.write("\n") # print ' insert %s' % copyright.get_line() did_insert_bilibili_copyright = True if not self.context.dryrun: tmp.write(line) src.close() if not self.context.dryrun: tmp.close() os.remove(tmp_path) if self.need_insert_bilibili_copyright and did_insert_bilibili_copyright: self.context.log_file('+ update', self.abs_path) else: self.context.log_file('~ missing', self.abs_path) def copyright_names(self): return self.copyright_names.keys() def copyright_urls(self): return self.copyright_urls.keys() def __parse_line(self, line): copyright = CRCopyright.scan_line(self.context, line) if copyright: # print "match %s" % copyright.name self.copyright_names[copyright.name.lower()] = copyright self.copyright_urls[copyright.url.lower()] = copyright return True @staticmethod def load_from_file(context, file): parsed_lines = 0; crf = CRFile(context = context, file = file) f = open(crf.abs_path, 'r') for line in f: if parsed_lines > 20: break parsed_lines += 1 crf.__parse_line(line) f.close() # TODO: use a visitor if 'bilibili' not in crf.copyright_names: if 'zhang rui' in crf.copyright_names or 'bbcallen@gmail.com' in crf.copyright_urls: crf.need_insert_bilibili_copyright = True crf.dirty = True return crf @staticmethod def update_path(context, file): base_name = os.path.basename(file) abs_path = context.get_path_of_file(file) if base_name.startswith('.'): context.log_file('- hidden', abs_path) return elif context.is_black_path(abs_path): context.log_file('- black', abs_path) return elif os.path.islink(abs_path): context.log_file('- link', abs_path) return elif os.path.isdir(abs_path): for sub_file in os.listdir(abs_path): sub_path = os.path.realpath(os.path.join(abs_path, sub_file)) CRFile.update_path(context, sub_path) elif not context.need_copyright(abs_path): context.log_file('- nohead', abs_path) return elif os.path.isfile(abs_path): src_file = CRFile.load_from_file(context, abs_path) src_file.update() ================================================ FILE: tools/copyrighter/__init__.py ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2017 Bilibili # Copyright (C) 2013-2017 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ================================================ FILE: tools/copyrighter/__main__.py ================================================ #! /usr/bin/env bash # # Copyright (C) 2013-2017 Bilibili # Copyright (C) 2013-2017 Zhang Rui # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import sys import os import fnmatch from sets import Set if not __package__: path = os.path.join(os.path.dirname(__file__), os.pardir) sys.path.insert(0, path) from copyrighter.CRContext import CRContext from copyrighter.CRFile import CRFile context = CRContext(); target_list = Set([ 'ijkmedia', 'extra/init-extra.sh' ]) for target in Set(['']): # for target in target_list: CRFile.update_path(context, target) ================================================ FILE: tools/pull-repo-base.sh ================================================ #! /usr/bin/env bash REMOTE_REPO=$1 LOCAL_WORKSPACE=$2 if [ -z $REMOTE_REPO -o -z $LOCAL_WORKSPACE ]; then echo "invalid call pull-repo.sh '$REMOTE_REPO' '$LOCAL_WORKSPACE'" elif [ ! -d $LOCAL_WORKSPACE ]; then git clone $REMOTE_REPO $LOCAL_WORKSPACE else cd $LOCAL_WORKSPACE git fetch --all --tags cd - fi ================================================ FILE: tools/pull-repo-ref.sh ================================================ #! /usr/bin/env bash REMOTE_REPO=$1 LOCAL_WORKSPACE=$2 REF_REPO=$3 if [ -z $1 -o -z $2 -o -z $3 ]; then echo "invalid call pull-repo.sh '$1' '$2' '$3'" elif [ ! -d $LOCAL_WORKSPACE ]; then git clone --reference $REF_REPO $REMOTE_REPO $LOCAL_WORKSPACE cd $LOCAL_WORKSPACE git repack -a else cd $LOCAL_WORKSPACE git fetch --all --tags cd - fi ================================================ FILE: tools/setup-as-commiter.sh ================================================ #! /usr/bin/env bash git remote add gitcafe git@gitcafe.com:bbcallen/ijkplayer.git git remote add oschina git@git.oschina.net:bbcallen/ijkplayer.git git remote add csdn git@code.csdn.net:bbcallen/ijkplayer.git git fetch --all ================================================ FILE: tools/sync-mirrors.sh ================================================ #! /usr/bin/env bash git push origin --all --follow-tags git push gitcafe --all --follow-tags git push oschina --all --follow-tags git push csdn --all --follow-tags ================================================ FILE: version.sh ================================================ #!/bin/sh set -e VERSION_CODE=800800 VERSION_NAME=0.8.8 VERSION_TARGET=$1 do_version_readme() { # README.md # cat README.md \ # | sed "s/\(#compile 'tv.danmaku.ijk.media:ijkplayer-java:#\)[[:digit:]][[:digit:].]*\(#'#\)/\1:$VERSION_NAME\2/" \ # > README.md.new cat README.md \ | sed "s/\(compile \'tv.danmaku.ijk.media:ijkplayer-[[:alnum:]_]*:\)[[:digit:].]*[[:digit:]]/\1$VERSION_NAME/g" \ | sed "s/\(git checkout -B latest k\)[[:digit:]][[:digit:].]*/\1$VERSION_NAME/g" \ > README.md.new mv -f README.md.new README.md } do_version_gradle() { # android/ijkplayer/build.gradle cat android/ijkplayer/build.gradle \ | sed "s/\(versionCode[[:space:]]*=[[:space:]]*\)[[:digit:]][[:digit:]]*/\1$VERSION_CODE/" \ | sed "s/\(versionName[[:space:]]*=[[:space:]]*\)\"[[:digit:].]*[[:digit:]]\"/\1\"$VERSION_NAME\"/" \ > android/ijkplayer/build.gradle.new mv -f android/ijkplayer/build.gradle.new android/ijkplayer/build.gradle # android/ijkplayer/gradle.properties cat android/ijkplayer/gradle.properties \ | sed "s/\(VERSION_NAME=\)[[:digit:].]*[[:digit:]]/\1$VERSION_NAME/" \ | sed "s/\(VERSION_CODE=\)[[:digit:]][[:digit:]]*/\1$VERSION_CODE/" \ > android/ijkplayer/gradle.properties.new mv -f android/ijkplayer/gradle.properties.new android/ijkplayer/gradle.properties # android/ijkplayer/ijkplayer-exo/build.gradle cat android/ijkplayer/ijkplayer-exo/build.gradle \ | sed "s/\(compile \'tv.danmaku.ijk.media:ijkplayer-[-_[:alpha:][:digit:]]*:\)[[:digit:].]*[[:digit:]]/\1$VERSION_NAME/g" \ > android/ijkplayer/ijkplayer-exo/build.gradle.new mv -f android/ijkplayer/ijkplayer-exo/build.gradle.new android/ijkplayer/ijkplayer-exo/build.gradle # android/ijkplayer/ijkplayer-example/build.gradle cat android/ijkplayer/ijkplayer-example/build.gradle \ | sed "s/\(ompile \'tv.danmaku.ijk.media:ijkplayer-[-_[:alpha:][:digit:]]*:\)[[:digit:].]*[[:digit:]]/\1$VERSION_NAME/g" \ > android/ijkplayer/ijkplayer-example/build.gradle.new mv -f android/ijkplayer/ijkplayer-example/build.gradle.new android/ijkplayer/ijkplayer-example/build.gradle } do_version_xcode() { # ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj cat ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj \ | sed "s/\(CURRENT_PROJECT_VERSION = \).*;/\1$VERSION_NAME;/g" \ > ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj.new mv -f ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj.new ios/IJKMediaPlayer/IJKMediaPlayer.xcodeproj/project.pbxproj } if [ "$VERSION_TARGET" = "readme" ]; then do_version_readme elif [ "$VERSION_TARGET" = "gradle" ]; then do_version_gradle elif [ "$VERSION_TARGET" = "show" ]; then echo $VERSION_NAME elif [ "$VERSION_TARGET" = "xcode" ]; then do_version_xcode else do_version_readme do_version_gradle do_version_xcode fi