提交 da15bd92 编写于 作者: Z Zhang Rui

Merge branch 'ios-r0.0.5-dev'

Conflicts:
	android/ijkmediademo/src/tv/danmaku/ijk/media/demo/VideoPlayerActivity.java
......@@ -2,6 +2,7 @@
build/
ffmpeg-temp/
android/ffmpeg-armv7a
ios/ffmpeg-*
extra
.DS_Store
......
Changes between 0.0.5 and 0.0.4:
--------------------------------
- build: disable -fmodulo-sched -fmodulo-sched-allow-regmoves
- 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
Changes between 0.0.4 and 0.0.3:
--------------------------------
- ffmpeg: enable ac3
- android: target API-18
- build: switch to NDKr9 gcc4.8 toolchain
Changes between 0.0.3 and 0.0.1:
--------------------------------
......
......@@ -116,10 +116,12 @@ FF_CFLAGS="-O3 -Wall -pipe \
-std=c99 \
-ffast-math \
-fstrict-aliasing -Werror=strict-aliasing \
-fmodulo-sched -fmodulo-sched-allow-regmoves \
-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"
......
......@@ -84,7 +84,8 @@ public class VideoPlayerActivity extends Activity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player);
mVideoPath = "http://113.142.44.44/e0012jy0ana.m3u8?type=m3u8&srctype=mp4&srcname=e0012jy0ana.mp4&fc=0&sha=82e0d6adb6e697d1821abbbacb766373afa26ff4&vkey=OAz_lwrlhx0tqBefQmHnxKTm8PqvrJCl5iJtLhVtSj6hla57btxiuw";
mVideoPath = "rtsp://l.m.cztv.com:554/hdmi/hntv1hd.stream";
// mVideoPath = "http://live.gslb.letv.com/gslb?stream_id=btv6_800&tag=live&ext=m3u8";
Intent intent = getIntent();
String intentAction = intent.getAction();
......
ijkmedia
\ No newline at end of file
......@@ -29,6 +29,7 @@ LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)
LOCAL_SRC_FILES += ff_cmdutils.c
LOCAL_SRC_FILES += ff_ffplay.c
LOCAL_SRC_FILES += ijkplayer.c
LOCAL_SRC_FILES += android/ijkplayer_android.c
LOCAL_SRC_FILES += android/ijkplayer_jni.c
......
......@@ -23,81 +23,14 @@
#include "ijkplayer_android.h"
#include <assert.h>
#include "ijksdl/ijksdl_android.h"
#include "ijksdl/android/ijksdl_android.h"
#include "../ff_fferror.h"
#include "../ff_ffplay.h"
#include "../ijkplayer_internal.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)
typedef struct IjkMediaPlayer {
volatile int ref_count;
pthread_mutex_t mutex;
FFPlayer *ffplayer;
void *(*msg_loop)(void*);
pthread_t msg_thread;
int mp_state;
char *data_source;
void *weak_thiz;
int restart_from_beginning;
int seek_req;
long seek_msec;
} IjkMediaPlayer;
inline static void ijkmp_destroy(IjkMediaPlayer *mp)
{
if (!mp)
return;
ffp_destroy_p(&mp->ffplayer);
pthread_mutex_destroy(&mp->mutex);
av_freep(&mp->data_source);
memset(mp, 0, sizeof(IjkMediaPlayer));
av_freep(&mp);
}
inline static void ijkmp_destroy_p(IjkMediaPlayer **pmp)
IjkMediaPlayer *ijkmp_android_create(int(*msg_loop)(void*))
{
if (!pmp)
return;
ijkmp_destroy(*pmp);
*pmp = NULL;
}
void ijkmp_global_init()
{
ffp_global_init();
}
void ijkmp_global_uninit()
{
ffp_global_uninit();
}
IjkMediaPlayer *ijkmp_create(void *(*msg_loop)(void*))
{
IjkMediaPlayer *mp = (IjkMediaPlayer *) av_mallocz(sizeof(IjkMediaPlayer));
if (!mp)
goto fail;
mp->ffplayer = ffp_create();
IjkMediaPlayer *mp = ijkmp_create(msg_loop);
if (!mp)
goto fail;
......@@ -109,382 +42,14 @@ IjkMediaPlayer *ijkmp_create(void *(*msg_loop)(void*))
if (!mp->ffplayer->vout)
goto fail;
mp->msg_loop = msg_loop;
ijkmp_inc_ref(mp);
pthread_mutex_init(&mp->mutex, NULL);
return mp;
fail:
ijkmp_destroy_p(&mp);
ijkmp_dec_ref_p(&mp);
return NULL;
}
void ijkmp_shutdown_l(IjkMediaPlayer *mp)
{
assert(mp);
MPTRACE("ijkmp_shutdown_l()");
if (mp->ffplayer) {
ffp_stop_l(mp->ffplayer);
ffp_wait_stop_l(mp->ffplayer);
}
MPTRACE("ijkmp_shutdown_l()=void");
}
void ijkmp_shutdown(IjkMediaPlayer *mp)
{
return ijkmp_shutdown_l(mp);
}
void ijkmp_reset_l(IjkMediaPlayer *mp)
{
assert(mp);
ijkmp_shutdown_l(mp);
ffp_reset_internal(mp->ffplayer);
av_freep(&mp->data_source);
mp->mp_state = MP_STATE_IDLE;
}
void ijkmp_reset(IjkMediaPlayer *mp)
{
assert(mp);
MPTRACE("ijkmp_reset()");
pthread_mutex_lock(&mp->mutex);
ijkmp_reset_l(mp);
pthread_mutex_unlock(&mp->mutex);
MPTRACE("ijkmp_reset()=void");
}
void ijkmp_set_format_option(IjkMediaPlayer *mp, const char *name, const char *value)
{
assert(mp);
MPTRACE("ijkmp_reset()");
pthread_mutex_lock(&mp->mutex);
ffp_set_format_option(mp->ffplayer, name, value);
pthread_mutex_unlock(&mp->mutex);
MPTRACE("ijkmp_reset()=void");
}
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_fetch_and_sub(&mp->ref_count, 1);
if (ref_count == 0) {
MPTRACE("ijkmp_dec_ref(): ref=0");
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);
char *dup_url = strdup(url);
if (!dup_url)
return EIJK_OUT_OF_MEMORY;
av_freep(&mp->data_source);
mp->data_source = av_strdup(url);
mp->mp_state = 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\")", 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", url, retval);
return retval;
}
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);
mp->mp_state = MP_STATE_ASYNC_PREPARING;
msg_queue_start(&mp->ffplayer->msg_queue);
ijkmp_inc_ref(mp);
pthread_create(&mp->msg_thread, NULL, mp->msg_loop, mp);
// TODO: 9 release weak_thiz if pthread_create() failed;
int retval = ffp_prepare_async_l(mp->ffplayer, mp->data_source);
if (retval < 0) {
mp->mp_state = MP_STATE_ERROR;
return retval;
}
return 0;
}
int ijkmp_prepare_async(IjkMediaPlayer *mp)
{
assert(mp);
MPTRACE("ijkmp_prepare_async()");
pthread_mutex_lock(&mp->mutex);
int retval = ijkmp_prepare_async_l(mp);
pthread_mutex_unlock(&mp->mutex);
MPTRACE("ijkmp_prepare_async()=%d", 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()");
pthread_mutex_lock(&mp->mutex);
int retval = ijkmp_start_l(mp);
pthread_mutex_unlock(&mp->mutex);
MPTRACE("ijkmp_start()=%d", 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()");
pthread_mutex_lock(&mp->mutex);
int retval = ijkmp_pause_l(mp);
pthread_mutex_unlock(&mp->mutex);
MPTRACE("ijkmp_pause()=%d", 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;
}
mp->mp_state = MP_STATE_STOPPED;
return 0;
}
int ijkmp_stop(IjkMediaPlayer *mp)
{
assert(mp);
MPTRACE("ijkmp_stop()");
pthread_mutex_lock(&mp->mutex);
int retval = ijkmp_stop_l(mp);
pthread_mutex_unlock(&mp->mutex);
MPTRACE("ijkmp_stop()=%d", 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, msec);
// TODO: 9 64-bit long?
return 0;
}
int ijkmp_seek_to(IjkMediaPlayer *mp, long msec)
{
assert(mp);
MPTRACE("ijkmp_seek_to(%ld)", 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", msec, retval);
return retval;
}
static long ijkmp_get_current_position_l(IjkMediaPlayer *mp)
{
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);
int retval = ijkmp_get_duration_l(mp);
pthread_mutex_unlock(&mp->mutex);
return retval;
}
void ijkmp_set_android_surface_l(JNIEnv *env, IjkMediaPlayer *mp, jobject android_surface)
void ijkmp_android_set_surface_l(JNIEnv *env, IjkMediaPlayer *mp, jobject android_surface)
{
assert(mp);
assert(mp->ffplayer);
......@@ -493,126 +58,12 @@ void ijkmp_set_android_surface_l(JNIEnv *env, IjkMediaPlayer *mp, jobject androi
SDL_VoutAndroid_SetAndroidSurface(env, mp->ffplayer->vout, android_surface);
}
void ijkmp_set_android_surface(JNIEnv *env, IjkMediaPlayer *mp, jobject android_surface)
void ijkmp_android_set_surface(JNIEnv *env, IjkMediaPlayer *mp, jobject android_surface)
{
assert(mp);
MPTRACE("ijkmp_set_android_surface(surface=%p)", (void*)android_surface);
pthread_mutex_lock(&mp->mutex);
ijkmp_set_android_surface_l(env, mp, android_surface);
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_set_weak_thiz(IjkMediaPlayer *mp, void *weak_thiz)
{
void *prev_weak_thiz = mp->weak_thiz;
mp->weak_thiz = weak_thiz;
return prev_weak_thiz;
}
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");
pthread_mutex_lock(&mp->mutex);
if (mp->mp_state == MP_STATE_ASYNC_PREPARING) {
mp->mp_state = MP_STATE_PREPARED;
} else {
// FIXME: 1: onError() ?
ALOGE("FFP_MSG_PREPARED: expecting mp_state==MP_STATE_ASYNC_PREPARING");
}
pthread_mutex_unlock(&mp->mutex);
break;
case FFP_MSG_COMPLETED:
MPTRACE("ijkmp_get_msg: FFP_MSG_COMPLETED");
pthread_mutex_lock(&mp->mutex);
mp->restart_from_beginning = 1;
mp->mp_state = MP_STATE_COMPLETED;
pthread_mutex_unlock(&mp->mutex);
break;
case FFP_MSG_SEEK_COMPLETE:
MPTRACE("ijkmp_get_msg: FFP_MSG_SEEK_COMPLETE");
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");
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->mp_state == MP_STATE_COMPLETED) {
if (mp->restart_from_beginning) {
ALOGD("ijkmp_get_msg: FFP_REQ_START: restart from beginning");
retval = ffp_start_from_l(mp->ffplayer, 0);
if (retval == 0)
mp->mp_state = MP_STATE_STARTED;
} else {
ALOGD("ijkmp_get_msg: FFP_REQ_START: restart from seek pos");
retval = ffp_start_l(mp->ffplayer);
if (retval == 0)
mp->mp_state = MP_STATE_STARTED;
}
mp->restart_from_beginning = 0;
} else {
ALOGD("ijkmp_get_msg: FFP_REQ_START: start on fly");
retval = ffp_start_l(mp->ffplayer);
if (retval == 0)
mp->mp_state = MP_STATE_STARTED;
}
}
pthread_mutex_unlock(&mp->mutex);
break;
case FFP_REQ_PAUSE:
MPTRACE("ijkmp_get_msg: FFP_REQ_PAUSE");
continue_wait_next_msg = 1;
pthread_mutex_lock(&mp->mutex);
if (0 == ikjmp_chkst_pause_l(mp->mp_state)) {
int retval = ffp_pause_l(mp->ffplayer);
if (retval == 0)
mp->mp_state = MP_STATE_PAUSED;
}
pthread_mutex_unlock(&mp->mutex);
break;
case FFP_REQ_SEEK:
MPTRACE("ijkmp_get_msg: FFP_REQ_SEEK");
continue_wait_next_msg = 1;
pthread_mutex_lock(&mp->mutex);
if (0 == ikjmp_chkst_seek_l(mp->mp_state)) {
if (0 == ffp_seek_to_l(mp->ffplayer, msg->arg1)) {
ALOGD("ijkmp_get_msg: FFP_REQ_SEEK: seek to %d", (int)msg->arg1);
mp->restart_from_beginning = 0;
}
}
pthread_mutex_unlock(&mp->mutex);
break;
}
if (continue_wait_next_msg)
continue;
return retval;
}
return -1;
}
......@@ -23,159 +23,12 @@
#ifndef IJKPLAYER_ANDROID__IJKPLAYER_ANDROID_H
#define IJKPLAYER_ANDROID__IJKPLAYER_ANDROID_H
#include <stdbool.h>
#include <jni.h>
#include "ff_ffmsg_queue.h"
#include "ijkutil/ijkutil_android.h"
#ifndef MPTRACE
#define MPTRACE ALOGW
#endif
struct IjkMediaPlayer;
typedef struct FFPlayer FFPlayer;
typedef struct SDL_Vout 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
typedef struct IjkMediaPlayer IjkMediaPlayer;
void ijkmp_global_init();
void ijkmp_global_uninit();
#include "../ijkplayer.h"
// ref_count is 1 after open
IjkMediaPlayer *ijkmp_create(void *(*msg_loop)(void*));
// 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);
bool ijkmp_is_playing(IjkMediaPlayer *mp);
long ijkmp_get_current_position(IjkMediaPlayer *mp);
long ijkmp_get_duration(IjkMediaPlayer *mp);
void ijkmp_reset(IjkMediaPlayer *mp);
void ijkmp_set_format_option(IjkMediaPlayer *mp, const char *name, const char *value);
void ijkmp_set_android_surface(JNIEnv *env, IjkMediaPlayer *mp, jobject android_surface);
void *ijkmp_set_weak_thiz(IjkMediaPlayer *mp, void *weak_thiz);
IjkMediaPlayer *ijkmp_android_create(int(*msg_loop)(void*));
/* return < 0 if aborted, 0 if no packet and > 0 if packet. */
int ijkmp_get_msg(IjkMediaPlayer *mp, AVMessage *msg, int block);
void ijkmp_android_set_surface(JNIEnv *env, IjkMediaPlayer *mp, jobject android_surface);
#endif
......@@ -24,7 +24,7 @@
#include <string.h>
#include <pthread.h>
#include <jni.h>
#include "ijkutil/ijkutil_android.h"
#include "ijkutil/ijkutil.h"
#include "../ff_ffplay.h"
#include "ijkplayer_android_def.h"
#include "ijkplayer_android.h"
......@@ -85,7 +85,7 @@ static IjkMediaPlayer *jni_set_media_player(JNIEnv* env, jobject thiz, IjkMediaP
return old;
}
static void *message_loop(void *arg);
static int message_loop(void *arg);
static void
IjkMediaPlayer_setDataSourceAndHeaders(
......@@ -119,7 +119,7 @@ IjkMediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface)
IjkMediaPlayer *mp = jni_get_media_player(env, thiz);
JNI_CHECK_GOTO(mp, env, NULL, "mpjni: setVideoSurface: null mp", LABEL_RETURN);
ijkmp_set_android_surface(env, mp, jsurface);
ijkmp_android_set_surface(env, mp, jsurface);
LABEL_RETURN:
ijkmp_dec_ref_p(&mp);
......@@ -296,7 +296,7 @@ static void
IjkMediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
MPTRACE("IjkMediaPlayer_native_setup");
IjkMediaPlayer *mp = ijkmp_create(message_loop);
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);
......@@ -390,7 +390,7 @@ static void message_loop_n(JNIEnv *env, IjkMediaPlayer *mp)
(*env)->DeleteGlobalRef(env, weak_thiz);
}
static void *message_loop(void *arg)
static int message_loop(void *arg)
{
MPTRACE("message_loop");
......@@ -407,7 +407,7 @@ static void *message_loop(void *arg)
(*g_jvm)->DetachCurrentThread(g_jvm);
MPTRACE("message_loop exit");
return NULL;
return 0;
}
// ----------------------------------------------------------------------------
......
......@@ -197,7 +197,7 @@ inline static int msg_queue_get(MessageQueue *q, AVMessage *msg, int block)
return ret;
}
inline void msg_queue_remove(MessageQueue *q, int what)
inline static void msg_queue_remove(MessageQueue *q, int what)
{
AVMessage **p_msg, *msg, *last_msg = q->first_msg;
SDL_LockMutex(q->mutex);
......
......@@ -29,15 +29,21 @@
// 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_SHOW_FPS
// #define FFP_SHOW_VDPS
// #define FFP_SHOW_AUDIO_DELAY
// #define FFP_SHOW_DEMUX_CACHE
static AVPacket flush_pkt;
static AVPacket eof_pkt;
......@@ -247,7 +253,7 @@ static void video_image_display2(FFPlayer *ffp)
g_fps_counter++;
int64_t avg_frame_time = g_fps_total_time / g_fps_counter;
double fps = 1.0f / avg_frame_time * 1000;
ALOGE("fps: [%f][%d] %"PRId64" ms/frame, fps=%f, +%"PRId64,
ALOGE("fps: [%f][%d] %"PRId64" ms/frame, fps=%f, +%"PRId64"\n",
vp->pts, g_fps_counter, (int64_t)avg_frame_time, fps, dur);
#endif
}
......@@ -263,9 +269,9 @@ static void stream_close(FFPlayer *ffp)
int i;
/* XXX: use a special url_shutdown call to abort parse cleanly */
is->abort_request = 1;
ALOGW("wait for read_tid");
ALOGW("wait for read_tid\n");
SDL_WaitThread(is->read_tid, NULL);
ALOGW("wait for video_refresh_tid");
ALOGW("wait for video_refresh_tid\n");
SDL_WaitThread(is->video_refresh_tid, NULL);
packet_queue_destroy(&is->videoq);
......@@ -436,9 +442,9 @@ static void stream_toggle_pause_l(FFPlayer *ffp, int pause_on)
}
#endif
set_clock(&is->vidclk, get_clock(&is->vidclk), is->vidclk.serial);
// ALOGE("stream_toggle_pause_l: pause -> start");
// ALOGE("stream_toggle_pause_l: pause -> start\n");
} else {
// ALOGE("stream_toggle_pause_l: %d", pause_on);
// ALOGE("stream_toggle_pause_l: %d\n", pause_on);
}
set_clock(&is->extclk, get_clock(&is->extclk), is->extclk.serial);
is->paused = is->audclk.paused = is->vidclk.paused = is->extclk.paused = pause_on;
......@@ -449,19 +455,19 @@ static void stream_toggle_pause_l(FFPlayer *ffp, int pause_on)
static void stream_update_pause_l(FFPlayer *ffp)
{
VideoState *is = ffp->is;
// ALOGE("stream_update_pause_l: (!%d && (%d || %d)", is->step, is->pause_req, is->buffering_on);
// ALOGE("stream_update_pause_l: (!%d && (%d || %d)\n", is->step, is->pause_req, is->buffering_on);
if (!is->step && (is->pause_req || is->buffering_on)) {
// ALOGE("stream_update_pause_l: 1");
// ALOGE("stream_update_pause_l: 1\n");
stream_toggle_pause_l(ffp, 1);
} else {
// ALOGE("stream_update_pause_l: 0");
// ALOGE("stream_update_pause_l: 0\n");
stream_toggle_pause_l(ffp, 0);
}
}
static void toggle_pause_l(FFPlayer *ffp, int pause_on)
{
// ALOGE("toggle_pause_l");
// ALOGE("toggle_pause_l\n");
VideoState *is = ffp->is;
is->pause_req = pause_on;
ffp->auto_start = !pause_on;
......@@ -480,7 +486,7 @@ static void step_to_next_frame_l(FFPlayer *ffp)
{
VideoState *is = ffp->is;
/* if the stream is paused unpause it, then step */
// ALOGE("step_to_next_frame");
// ALOGE("step_to_next_frame\n");
if (is->paused)
stream_toggle_pause_l(ffp, 0);
is->step = 1;
......@@ -488,7 +494,7 @@ static void step_to_next_frame_l(FFPlayer *ffp)
static double compute_target_delay(double delay, VideoState *is)
{
double sync_threshold, diff;
double sync_threshold, diff = 0.0f;
/* update delay to follow master synchronisation source */
if (get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER) {
......@@ -576,7 +582,7 @@ static void video_refresh(FFPlayer *opaque, double *remaining_time)
is->last_vis_time = time;
}
/*
ALOGE("remaining[1] %.3f = FFMIN(%.3f, %.3f + %.3f - %.3f)",
ALOGE("remaining[1] %.3f = FFMIN(%.3f, %.3f + %.3f - %.3f)\n",
*remaining_time,
is->last_vis_time,
ffp->rdftspeed,
......@@ -736,7 +742,7 @@ static void alloc_picture(FFPlayer *ffp)
video_open(ffp, 0, vp);
#endif
vp->bmp = SDL_VoutFFmpeg_CreateOverlay(vp->width, vp->height,
vp->bmp = SDL_Vout_CreateOverlay(vp->width, vp->height,
ffp->overlay_format,
ffp->vout);
#ifdef FFP_MERGE
......@@ -889,6 +895,26 @@ static int get_video_frame(FFPlayer *ffp, AVFrame *frame, AVPacket *pkt, int *se
return 0;
}
if (is->dropping_frame) {
if (pkt->flags & AV_PKT_FLAG_KEY) {
ALOGW("skip frame(fast): end\n");
is->dropping_frame = 0;
is->video_st->codec->skip_frame = ffp->skip_frame;
avcodec_flush_buffers(is->video_st->codec);
} else {
return 0;
}
}
if (is->frame_drops_early > 12) {
ALOGW("skip frame: start\n");
is->dropping_frame = 1;
is->frame_drops_early = 0;
is->video_st->codec->skip_frame = AVDISCARD_NONKEY;
avcodec_flush_buffers(is->video_st->codec);
return 0;
}
#ifdef FFP_SHOW_VDPS
int64_t start = SDL_GetTickHR();
#endif
......@@ -900,7 +926,7 @@ static int get_video_frame(FFPlayer *ffp, AVFrame *frame, AVPacket *pkt, int *se
g_vdps_counter++;
int64_t avg_frame_time = g_vdps_total_time / g_vdps_counter;
double fps = 1.0f / avg_frame_time * 1000;
ALOGE("vdps: [%f][%d] %"PRId64" ms/frame, vdps=%f, +%"PRId64,
ALOGE("vdps: [%f][%d] %"PRId64" ms/frame, vdps=%f, +%"PRId64"\n",
frame->pts, g_vdps_counter, (int64_t)avg_frame_time, fps, dur);
#endif
......@@ -1470,6 +1496,7 @@ static int audio_decode_frame(FFPlayer *ffp)
else
is->audio_clock = NAN;
is->audio_clock_serial = is->audio_pkt_temp_serial;
#ifdef FFP_SHOW_AUDIO_DELAY
#ifdef DEBUG
{
static double last_clock;
......@@ -1478,6 +1505,7 @@ static int audio_decode_frame(FFPlayer *ffp)
is->audio_clock, audio_clock0);
last_clock = is->audio_clock;
}
#endif
#endif
return resampled_data_size;
}
......@@ -1535,7 +1563,7 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
is->audio_buf_index = 0;
}
if (is->audio_pkt_temp_serial != is->audioq.serial) {
// ALOGE("aout_cb: flush");
// ALOGE("aout_cb: flush\n");
is->audio_buf_index = is->audio_buf_size;
memset(stream, 0, len);
stream += len;
......@@ -1655,7 +1683,8 @@ static int stream_component_open(FFPlayer *ffp, int stream_index)
return -1;
}
avctx->skip_loop_filter = AVDISCARD_ALL;
avctx->skip_frame = ffp->skip_frame;
avctx->skip_loop_filter = ffp->skip_loop_filter;
avctx->codec_id = codec->id;
avctx->workaround_bugs = ffp->workaround_bugs;
......@@ -1742,7 +1771,7 @@ static int stream_component_open(FFPlayer *ffp, int stream_index)
is->video_st = ic->streams[stream_index];
packet_queue_start(&is->videoq);
is->video_tid = SDL_CreateThreadEx(&is->_video_tid, video_thread, ffp);
is->video_tid = SDL_CreateThreadEx(&is->_video_tid, video_thread, ffp, "ff_video");
is->queue_attachments_req = 1;
break;
// FFP_MERGE: case AVMEDIA_TYPE_SUBTITLE:
......@@ -1915,7 +1944,7 @@ static int read_thread(void *arg)
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;
ALOGI("max_frame_duration: %.3f", is->max_frame_duration);
ALOGI("max_frame_duration: %.3f\n", is->max_frame_duration);
#ifdef FFP_MERGE
if (!window_title && (t = av_dict_get(ic->metadata, "title", NULL, 0)))
......@@ -2064,7 +2093,7 @@ static int read_thread(void *arg)
eof = 0;
SDL_LockMutex(ffp->is->play_mutex);
if (ffp->auto_start) {
// ALOGE("seek: auto_start");
// ALOGE("seek: auto_start\n");
is->pause_req = 0;
is->buffering_on = 1;
ffp->auto_start = 0;
......@@ -2101,7 +2130,7 @@ static int read_thread(void *arg)
))) {
#endif
if (!eof) {
// ALOGE("ffp_toggle_buffering: full");
// ALOGE("ffp_toggle_buffering: full\n");
ffp_toggle_buffering(ffp, 0);
}
/* wait 10 ms */
......@@ -2148,7 +2177,7 @@ static int read_thread(void *arg)
ffp->auto_start = 0;
// TODO: 0 it's a bit early to notify complete here
// ALOGE("ffp_toggle_buffering: eof");
// ALOGE("ffp_toggle_buffering: eof\n");
ffp_toggle_buffering(ffp, 0);
toggle_pause(ffp, 1);
ffp_notify_msg1(ffp, FFP_MSG_COMPLETED);
......@@ -2176,7 +2205,7 @@ static int read_thread(void *arg)
} else if (ic->pb && ic->pb->error) {
// TODO: 9 notify error until a/v finished
last_error = ic->pb->error;
ALOGE("av_read_frame error: %d", ic->pb->error);
ALOGE("av_read_frame error: %d\n", ic->pb->error);
ffp_notify_msg2(ffp, FFP_MSG_ERROR, last_error);
break;
}
......@@ -2206,15 +2235,14 @@ static int read_thread(void *arg)
}
do {
int buf_percent = INT_MAX;
int buf_size_percent = INT_MAX;
int buf_time_percent = INT_MAX;
int buf_size_percent = -1;
int buf_time_percent = -1;
int hwm_in_bytes = ffp->high_water_mark_in_bytes;
int hwm_in_ms = ffp->high_water_mark_in_ms;
if (hwm_in_ms > 0) {
int cached_duration_in_ms = INT_MAX;
int64_t audio_cached_duration = INT_MAX;
int64_t video_cached_duration = INT_MAX;
int cached_duration_in_ms = -1;
int64_t audio_cached_duration = -1;
int64_t video_cached_duration = -1;
if (is->audio_st && is->audio_st->time_base.den > 0 && is->audio_st->time_base.num > 0)
audio_cached_duration = is->audioq.duration * av_q2d(is->audio_st->time_base) * 1000;
......@@ -2222,11 +2250,20 @@ static int read_thread(void *arg)
if (is->video_st && is->video_st->time_base.den > 0 && is->video_st->time_base.num > 0)
video_cached_duration = is->videoq.duration * av_q2d(is->video_st->time_base) * 1000;
cached_duration_in_ms = IJKMIN(video_cached_duration, audio_cached_duration);
if (cached_duration_in_ms < INT_MAX) {
if (video_cached_duration >= 0 && audio_cached_duration >= 0) {
cached_duration_in_ms = IJKMAX(video_cached_duration, audio_cached_duration);
} else if (video_cached_duration >= 0) {
cached_duration_in_ms = video_cached_duration;
} else if (audio_cached_duration >= 0) {
cached_duration_in_ms = audio_cached_duration;
}
if (cached_duration_in_ms >= 0) {
buf_time_percent = av_rescale(cached_duration_in_ms, 1005, hwm_in_ms * 10);
if (last_buffered_time_percentage != buf_time_percent) {
// ALOGE("time cache=%%%d (%d/%d)", buf_time_percent, cached_duration_in_ms, hwm_in_ms);
#ifdef FFP_SHOW_DEMUX_CACHE
ALOGE("time cache=%%%d (%d/%d)\n", buf_time_percent, cached_duration_in_ms, hwm_in_ms);
#endif
last_buffered_time_percentage = buf_time_percent;
ffp_notify_msg3(ffp, FFP_MSG_BUFFERING_TIME_UPDATE, cached_duration_in_ms, hwm_in_ms);
}
......@@ -2237,15 +2274,22 @@ static int read_thread(void *arg)
if (hwm_in_bytes > 0) {
buf_size_percent = av_rescale(cached_size, 1005, hwm_in_bytes * 10);
if (last_buffered_size_percentage != buf_size_percent) {
// ALOGE("size cache=%%%d (%d/%d)",buf_size_percent, cached_size, hwm_in_bytes);
#ifdef FFP_SHOW_DEMUX_CACHE
ALOGE("size cache=%%%d (%d/%d)\n", buf_size_percent, cached_size, hwm_in_bytes);
#endif
last_buffered_size_percentage = buf_size_percent;
ffp_notify_msg3(ffp, FFP_MSG_BUFFERING_TIME_UPDATE, cached_size, hwm_in_bytes);
ffp_notify_msg3(ffp, FFP_MSG_BUFFERING_BYTES_UPDATE, cached_size, hwm_in_bytes);
}
}
buf_percent = IJKMIN(buf_size_percent, buf_time_percent);
if (buf_percent >= 100)
ffp_toggle_buffering(ffp, 0);
if (buf_time_percent >= 0) {
// alwas depend on cache duration if valid
if (buf_time_percent >= 100)
ffp_toggle_buffering(ffp, 0);
} else {
if (buf_size_percent >= 100)
ffp_toggle_buffering(ffp, 0);
}
} while(0);
// FIXME: 0 notify progress
......@@ -2318,13 +2362,13 @@ static VideoState *stream_open(FFPlayer *ffp, const char *filename, AVInputForma
is->play_mutex = SDL_CreateMutex();
ffp->is = is;
is->video_refresh_tid = SDL_CreateThreadEx(&is->_video_refresh_tid, video_refresh_thread, ffp);
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->read_tid = SDL_CreateThreadEx(&is->_read_tid, read_thread, ffp);
is->read_tid = SDL_CreateThreadEx(&is->_read_tid, read_thread, ffp, "ff_read");
if (!is->read_tid) {
is->abort_request = true;
SDL_WaitThread(is->video_refresh_tid, NULL);
......@@ -2462,8 +2506,8 @@ FFPlayer *ffp_create()
if (!ffp)
return NULL;
ffp_reset_internal(ffp);
msg_queue_init(&ffp->msg_queue);
ffp_reset_internal(ffp);
return ffp;
}
......@@ -2505,6 +2549,37 @@ void ffp_set_format_option(FFPlayer *ffp, const char *name, const char *value)
av_dict_set(&ffp->format_opts, name, value, 0);
}
void ffp_set_codec_option(FFPlayer *ffp, const char *name, const char *value)
{
if (!ffp)
return;
av_dict_set(&ffp->codec_opts, name, value, 0);
}
void ffp_set_sws_option(FFPlayer *ffp, const char *name, const char *value)
{
if (!ffp)
return;
av_dict_set(&ffp->sws_opts, name, value, 0);
}
void ffp_set_overlay_format(FFPlayer *ffp, int chroma_fourcc)
{
switch (chroma_fourcc) {
case SDL_FCC_I420:
case SDL_FCC_YV12:
case SDL_FCC_RV16:
case SDL_FCC_RV32:
ffp->overlay_format = chroma_fourcc;
break;
default:
ALOGE("ffp_set_overlay_format: unknown chroma fourcc: %d\n", chroma_fourcc);
break;
}
}
int ffp_prepare_async_l(FFPlayer *ffp, const char *file_name)
{
assert(ffp);
......@@ -2523,7 +2598,7 @@ int ffp_prepare_async_l(FFPlayer *ffp, const char *file_name)
int ffp_start_from_l(FFPlayer *ffp, long msec)
{
// ALOGE("ffp_start_at_l");
// ALOGE("ffp_start_at_l\n");
assert(ffp);
VideoState *is = ffp->is;
if (!is)
......@@ -2537,7 +2612,7 @@ int ffp_start_from_l(FFPlayer *ffp, long msec)
int ffp_start_l(FFPlayer *ffp)
{
// ALOGE("ffp_start_l");
// ALOGE("ffp_start_l\n");
assert(ffp);
VideoState *is = ffp->is;
if (!is)
......@@ -2549,7 +2624,7 @@ int ffp_start_l(FFPlayer *ffp)
int ffp_pause_l(FFPlayer *ffp)
{
// ALOGE("ffp_pause_l");
// ALOGE("ffp_pause_l\n");
assert(ffp);
VideoState *is = ffp->is;
if (!is)
......@@ -2598,7 +2673,7 @@ int ffp_seek_to_l(FFPlayer *ffp, long msec)
// FIXME: 9 seek by bytes
// FIXME: 9 seek out of range
// FIXME: 9 seekable
// ALOGE("stream_seek %"PRId64"(%d) + %"PRId64", ", seek_pos, (int)msec, start_time);
// ALOGE("stream_seek %"PRId64"(%d) + %"PRId64", \n", seek_pos, (int)msec, start_time);
stream_seek(is, seek_pos, 0, 0);
return 0;
}
......@@ -2618,10 +2693,10 @@ long ffp_get_current_position_l(FFPlayer *ffp)
int64_t pos = 0;
double pos_clock = get_master_clock(is);
if (isnan(pos_clock)) {
// ALOGE("pos = seek_pos: %d", (int)is->seek_pos);
// ALOGE("pos = seek_pos: %d\n", (int)is->seek_pos);
pos = fftime_to_milliseconds(is->seek_pos);
} else {
// ALOGE("pos = pos_clock: %f", pos_clock);
// ALOGE("pos = pos_clock: %f\n", pos_clock);
pos = pos_clock * 1000;
}
......@@ -2629,7 +2704,7 @@ long ffp_get_current_position_l(FFPlayer *ffp)
return 0;
int64_t adjust_pos = pos - start_diff;
// ALOGE("pos=%ld", (long)adjust_pos);
// ALOGE("pos=%ld\n", (long)adjust_pos);
return (long)adjust_pos;
}
......@@ -2650,7 +2725,7 @@ long ffp_get_duration_l(FFPlayer *ffp)
return 0;
int64_t adjust_duration = duration - start_diff;
// ALOGE("dur=%ld", (long)adjust_duration);
// ALOGE("dur=%ld\n", (long)adjust_duration);
return (long)adjust_duration;
}
......@@ -2658,13 +2733,15 @@ void ffp_toggle_buffering_l(FFPlayer *ffp, int buffering_on)
{
VideoState *is = ffp->is;
if (buffering_on && !is->buffering_on) {
ALOGD("ffp_toggle_buffering_l: start");
ALOGD("ffp_toggle_buffering_l: start\n");
is->buffering_on = 1;
is->frame_drops_early = 0;
stream_update_pause_l(ffp);
ffp_notify_msg1(ffp, FFP_MSG_BUFFERING_START);
} else if (!buffering_on && is->buffering_on){
ALOGD("ffp_toggle_buffering_l: end");
ALOGD("ffp_toggle_buffering_l: end\n");
is->buffering_on = 0;
is->frame_drops_early = 0;
stream_update_pause_l(ffp);
ffp_notify_msg1(ffp, FFP_MSG_BUFFERING_END);
}
......
......@@ -36,8 +36,13 @@ 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_format_option(FFPlayer *ffp, const char *name, const char *value);
void ffp_set_codec_option(FFPlayer *ffp, const char *name, const char *value);
void ffp_set_sws_option(FFPlayer *ffp, const char *name, const char *value);
void ffp_set_overlay_format(FFPlayer *ffp, int chroma_fourcc);
/* 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);
......
......@@ -28,8 +28,8 @@
#include "ff_ffplay_config.h"
#include "ff_ffmsg_queue.h"
#define DEFAULT_HIGH_WATER_MARK_IN_MS (5 * 1000)
#define DEFAULT_HIGH_WATER_MARK_IN_BYTES (256 * 1024)
#define DEFAULT_HIGH_WATER_MARK_IN_MS (10 * 1000)
#define DEFAULT_HIGH_WATER_MARK_IN_BYTES (128 * 1024)
#define MAX_QUEUE_SIZE (15 * 1024 * 1024)
#define MIN_FRAMES 50000
......@@ -44,7 +44,7 @@
/* If a frame duration is longer than this, it will not be duplicated to compensate AV sync */
#define AV_SYNC_FRAMEDUP_THRESHOLD 0.1
/* no AV correction is done if too big error */
#define AV_NOSYNC_THRESHOLD 10.0
#define AV_NOSYNC_THRESHOLD 100.0
/* maximum audio speed change to get correct sync */
#define SAMPLE_CORRECTION_PERCENT_MAX 10
......@@ -58,7 +58,8 @@
#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.0029 // 172.0 fps at most (High Level 5.2 1,920×1,080@172.0)
// 172.0 fps at most (High Level 5.2 1,920×1,080@172.0)
#define REFRESH_RATE 0.03
/* 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 */
......@@ -264,6 +265,8 @@ typedef struct VideoState {
int buffering_on;
int pause_req;
int dropping_frame;
} VideoState;
/* options specified by the user */
......@@ -429,6 +432,9 @@ typedef struct FFPlayer {
int high_water_mark_in_ms;
int high_water_mark_in_bytes;
int max_buffer_size;
int skip_loop_filter;
int skip_frame;
} FFPlayer;
#define fftime_to_milliseconds(ts) (av_rescale(ts, 1000, AV_TIME_BASE));
......@@ -457,7 +463,7 @@ inline static void ffp_reset_internal(FFPlayer *ffp)
ffp->start_time = AV_NOPTS_VALUE;
ffp->duration = AV_NOPTS_VALUE;
ffp->workaround_bugs = 1;
ffp->fast = 0;
ffp->fast = 1;
ffp->genpts = 0;
ffp->lowres = 0;
ffp->idct = FF_IDCT_AUTO;
......@@ -500,6 +506,9 @@ inline static void ffp_reset_internal(FFPlayer *ffp)
ffp->high_water_mark_in_bytes = DEFAULT_HIGH_WATER_MARK_IN_BYTES;
ffp->max_buffer_size = MAX_QUEUE_SIZE;
ffp->skip_loop_filter = AVDISCARD_ALL;
ffp->skip_frame = AVDISCARD_NONREF;
msg_queue_flush(&ffp->msg_queue);
}
......
/*
* ijkplayer.c
*
* Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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"
#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);
pthread_mutex_destroy(&mp->mutex);
av_freep(&mp->data_source);
memset(mp, 0, sizeof(IjkMediaPlayer));
av_freep(&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();
}
IjkMediaPlayer *ijkmp_create(int (*msg_loop)(void*))
{
IjkMediaPlayer *mp = (IjkMediaPlayer *) av_mallocz(sizeof(IjkMediaPlayer));
if (!mp)
goto fail;
mp->ffplayer = ffp_create();
if (!mp)
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_overlay_format(IjkMediaPlayer *mp, int chroma_fourcc)
{
if (!mp)
return;
MPTRACE("ijkmp_set_overlay_format(%.4s(0x%x))\n", (char*)&chroma_fourcc, chroma_fourcc);
if (mp->ffplayer) {
ffp_set_overlay_format(mp->ffplayer, chroma_fourcc);
}
MPTRACE("ijkmp_set_overlay_format()=void\n");
}
void ijkmp_set_format_option(IjkMediaPlayer *mp, const char *name, const char *value)
{
assert(mp);
MPTRACE("ijkmp_set_format_option()\n");
pthread_mutex_lock(&mp->mutex);
ffp_set_format_option(mp->ffplayer, name, value);
pthread_mutex_unlock(&mp->mutex);
MPTRACE("ijkmp_set_format_option()=void\n");
}
void ijkmp_set_codec_option(IjkMediaPlayer *mp, const char *name, const char *value)
{
assert(mp);
MPTRACE("ijkmp_set_codec_option()\n");
pthread_mutex_lock(&mp->mutex);
ffp_set_codec_option(mp->ffplayer, name, value);
pthread_mutex_unlock(&mp->mutex);
MPTRACE("ijkmp_set_codec_option()=void\n");
}
void ijkmp_set_sws_option(IjkMediaPlayer *mp, const char *name, const char *value)
{
assert(mp);
MPTRACE("ijkmp_set_sws_option()\n");
pthread_mutex_lock(&mp->mutex);
ffp_set_sws_option(mp->ffplayer, name, value);
pthread_mutex_unlock(&mp->mutex);
MPTRACE("ijkmp_set_sws_option()=void\n");
}
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_reset_l(IjkMediaPlayer *mp)
{
assert(mp);
ijkmp_shutdown_l(mp);
ffp_reset_internal(mp->ffplayer);
av_freep(&mp->data_source);
mp->mp_state = MP_STATE_IDLE;
}
void ijkmp_reset(IjkMediaPlayer *mp)
{
assert(mp);
MPTRACE("ijkmp_reset()\n");
pthread_mutex_lock(&mp->mutex);
ijkmp_reset_l(mp);
pthread_mutex_unlock(&mp->mutex);
MPTRACE("ijkmp_reset()=void\n");
}
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_fetch_and_sub(&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);
av_freep(&mp->data_source);
mp->data_source = av_strdup(url);
if (!mp->data_source)
return EIJK_OUT_OF_MEMORY;
mp->mp_state = 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_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);
mp->mp_state = MP_STATE_ASYNC_PREPARING;
msg_queue_start(&mp->ffplayer->msg_queue);
ijkmp_inc_ref(mp);
mp->msg_thread = SDL_CreateThreadEx(&mp->_msg_thread, mp->msg_loop, mp, "ff_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) {
mp->mp_state = 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;
}
mp->mp_state = 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, 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;
}
static long ijkmp_get_current_position_l(IjkMediaPlayer *mp)
{
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);
int retval = ijkmp_get_duration_l(mp);
pthread_mutex_unlock(&mp->mutex);
return retval;
}
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;
}
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) {
mp->mp_state = MP_STATE_PREPARED;
} else {
// FIXME: 1: onError() ?
ALOGE("FFP_MSG_PREPARED: expecting mp_state==MP_STATE_ASYNC_PREPARING\n");
}
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_from_beginning = 1;
mp->mp_state = 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->mp_state == MP_STATE_COMPLETED) {
if (mp->restart_from_beginning) {
ALOGD("ijkmp_get_msg: FFP_REQ_START: restart from beginning\n");
retval = ffp_start_from_l(mp->ffplayer, 0);
if (retval == 0)
mp->mp_state = MP_STATE_STARTED;
} else {
ALOGD("ijkmp_get_msg: FFP_REQ_START: restart from seek pos\n");
retval = ffp_start_l(mp->ffplayer);
if (retval == 0)
mp->mp_state = MP_STATE_STARTED;
}
mp->restart_from_beginning = 0;
} else {
ALOGD("ijkmp_get_msg: FFP_REQ_START: start on fly\n");
retval = ffp_start_l(mp->ffplayer);
if (retval == 0)
mp->mp_state = 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 retval = ffp_pause_l(mp->ffplayer);
if (retval == 0)
mp->mp_state = 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)) {
if (0 == ffp_seek_to_l(mp->ffplayer, msg->arg1)) {
ALOGD("ijkmp_get_msg: FFP_REQ_SEEK: seek to %d\n", (int)msg->arg1);
mp->restart_from_beginning = 0;
}
}
pthread_mutex_unlock(&mp->mutex);
break;
}
if (continue_wait_next_msg)
continue;
return retval;
}
return -1;
}
/*
* ijkplayer.h
*
* Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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 <stdbool.h>
#include "ff_ffmsg_queue.h"
#include "ijkutil/ijkutil.h"
#ifndef MPTRACE
#define MPTRACE ALOGW
#endif
struct IjkMediaPlayer;
typedef struct FFPlayer FFPlayer;
typedef struct SDL_Vout 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
typedef struct IjkMediaPlayer IjkMediaPlayer;
void ijkmp_global_init();
void ijkmp_global_uninit();
// ref_count is 1 after open
IjkMediaPlayer *ijkmp_create(int (*msg_loop)(void*));
void ijkmp_set_overlay_format(IjkMediaPlayer *mp, int chroma_fourcc);
void ijkmp_set_format_option(IjkMediaPlayer *mp, const char *name, const char *value);
void ijkmp_set_codec_option(IjkMediaPlayer *mp, const char *name, const char *value);
void ijkmp_set_sws_option(IjkMediaPlayer *mp, const char *name, const char *value);
// 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);
bool ijkmp_is_playing(IjkMediaPlayer *mp);
long ijkmp_get_current_position(IjkMediaPlayer *mp);
long ijkmp_get_duration(IjkMediaPlayer *mp);
void ijkmp_reset(IjkMediaPlayer *mp);
void *ijkmp_set_weak_thiz(IjkMediaPlayer *mp, void *weak_thiz);
/* return < 0 if aborted, 0 if no packet and > 0 if packet. */
int ijkmp_get_msg(IjkMediaPlayer *mp, AVMessage *msg, int block);
#endif
/*
* ijkplayer_internal.h
*
* Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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 <assert.h>
#include "ijksdl/ijksdl.h"
#include "ff_fferror.h"
#include "ff_ffplay.h"
#include "ijkplayer.h"
typedef 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_from_beginning;
int seek_req;
long seek_msec;
} IjkMediaPlayer;
#endif
......@@ -27,6 +27,7 @@ LOCAL_C_INCLUDES += $(realpath $(LOCAL_PATH)/..)
LOCAL_C_INCLUDES += $(MY_APP_FFMPEG_INCLUDE_PATH)
LOCAL_SRC_FILES += ijksdl_aout.c
LOCAL_SRC_FILES += ijksdl_audio.c
LOCAL_SRC_FILES += ijksdl_error.c
LOCAL_SRC_FILES += ijksdl_mutex.c
LOCAL_SRC_FILES += ijksdl_stdinc.c
......@@ -34,6 +35,8 @@ LOCAL_SRC_FILES += ijksdl_thread.c
LOCAL_SRC_FILES += ijksdl_timer.c
LOCAL_SRC_FILES += ijksdl_vout.c
LOCAL_SRC_FILES += dummy/ijksdl_vout_dummy.c
LOCAL_SRC_FILES += ffmpeg/ijksdl_vout_overlay_ffmpeg.c
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
......
......@@ -24,7 +24,7 @@
#include "android_audiotrack.h"
#include <assert.h>
#include "ijkutil/ijkutil_android.h"
#include "ijkutil/ijkutil.h"
#include "../ijksdl_inc_internal.h"
#include "../ijksdl_audio.h"
......
......@@ -21,14 +21,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef IJKSDL__IJKSDL_ANDROID_H
#define IJKSDL__IJKSDL_ANDROID_H
#ifndef IJKSDL_ANDROID__IJKSDL_ANDROID_H
#define IJKSDL_ANDROID__IJKSDL_ANDROID_H
#include "ijksdl.h"
#include "../ijksdl.h"
#include "android/ijksdl_aout_android_audiotrack.h"
#include "ijksdl_aout_android_audiotrack.h"
#include "android/ijksdl_vout_android_nativewindow.h"
#include "android/ijksdl_vout_android_surface.h"
#include "ijksdl_vout_android_nativewindow.h"
#include "ijksdl_vout_android_surface.h"
#endif
......@@ -152,7 +152,7 @@ int aout_open_audio_n(JNIEnv *env, SDL_Aout *aout, SDL_AudioSpec *desired, SDL_A
opaque->pause_on = 1;
opaque->abort_request = 0;
opaque->audio_tid = SDL_CreateThreadEx(&opaque->_audio_tid, aout_thread, aout);
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_audiotrack_free(env, opaque->atrack);
......
......@@ -26,7 +26,7 @@
#include <stdint.h>
#include "../ijksdl_inc_internal.h"
#include "ijkutil/ijkutil_android.h"
#include "ijkutil/ijkutil.h"
enum {
HAL_PIXEL_FORMAT_RGBA_8888 = 1,
......
......@@ -28,7 +28,7 @@
#include "ijkutil/ijkutil.h"
#include "../ijksdl_vout.h"
#include "../ijksdl_vout_internal.h"
#include "../ffmpeg/ijksdl_inc_ffmpeg.h"
#include "../ffmpeg/ijksdl_vout_overlay_ffmpeg.h"
#include "android_nativewindow.h"
typedef struct SDL_VoutSurface_Opaque {
......@@ -39,6 +39,19 @@ typedef struct SDL_Vout_Opaque {
ANativeWindow *native_window;
} SDL_Vout_Opaque;
static SDL_VoutOverlay *vout_create_overlay_l(int width, int height, Uint32 format, SDL_Vout *vout)
{
return SDL_VoutFFmpeg_CreateOverlay(width, height, format, vout);
}
static SDL_VoutOverlay *vout_create_overlay(int width, int height, Uint32 format, SDL_Vout *vout)
{
SDL_LockMutex(vout->mutex);
SDL_VoutOverlay *overlay = vout_create_overlay_l(width, height, format, vout);
SDL_UnlockMutex(vout->mutex);
return overlay;
}
static void vout_free_l(SDL_Vout *vout)
{
if (!vout)
......@@ -48,6 +61,7 @@ static void vout_free_l(SDL_Vout *vout)
if (opaque) {
if (opaque->native_window) {
ANativeWindow_release(opaque->native_window);
opaque->native_window = NULL;
}
}
......@@ -94,6 +108,7 @@ SDL_Vout *SDL_VoutAndroid_CreateForANativeWindow()
SDL_Vout_Opaque *opaque = vout->opaque;
opaque->native_window = NULL;
vout->create_overlay = vout_create_overlay;
vout->free_l = vout_free_l;
vout->display_overlay = voud_display_overlay;
......
/*****************************************************************************
* ijksdl_dummy.h
*****************************************************************************
*
* copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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
/*****************************************************************************
* ijksdl_vout_dummy.c
*****************************************************************************
*
* copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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 "ijkutil/ijkutil.h"
#include "../ijksdl_vout.h"
#include "../ijksdl_vout_internal.h"
typedef struct SDL_VoutSurface_Opaque {
SDL_Vout *vout;
} SDL_VoutSurface_Opaque;
typedef struct SDL_Vout_Opaque {
} SDL_Vout_Opaque;
static void vout_free_l(SDL_Vout *vout)
{
if (!vout)
return;
SDL_Vout_Opaque *opaque = vout->opaque;
if (opaque) {
}
SDL_Vout_FreeInternal(vout);
}
static int voud_display_overlay_l(SDL_Vout *vout, SDL_VoutOverlay *overlay)
{
return 0;
}
static int voud_display_overlay(SDL_Vout *vout, SDL_VoutOverlay *overlay)
{
SDL_LockMutex(vout->mutex);
int retval = voud_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 = vout_free_l;
vout->display_overlay = voud_display_overlay;
return vout;
}
/*****************************************************************************
* ijksdl_vout_dummy.h
*****************************************************************************
*
* copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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
......@@ -147,6 +147,7 @@ SDL_VoutOverlay *SDL_VoutFFmpeg_CreateOverlay(int width, int height, Uint32 form
int buf_width = width; // must be aligned to 16 bytes pitch for arm-neon image-convert
int buf_height = height;
switch (format) {
case SDL_FCC_I420:
case SDL_FCC_YV12: {
ff_format = AV_PIX_FMT_YUV420P;
buf_width = IJKALIGN(width, 16); // 1 bytes per pixel for Y-plane
......@@ -205,21 +206,32 @@ int SDL_VoutFFmpeg_ConvertFrame(
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;
av_frame_ref(opaque->linked_frame, frame);
overlay_fill(overlay, opaque->linked_frame, opaque->planes);
FFSWAP(Uint8*, overlay->pixels[1], overlay->pixels[2]);
} else {
// ALOGE("copy draw frame");
overlay_fill(overlay, opaque->frame, opaque->planes);
dest_pic.data[2] = overlay->pixels[1];
dest_pic.data[1] = overlay->pixels[2];
dest_pic.data[1] = overlay->pixels[1];
dest_pic.data[2] = overlay->pixels[2];
}
if (need_swap_uv) {
if (use_linked_frame) {
FFSWAP(Uint8*, overlay->pixels[1], overlay->pixels[2]);
} else {
FFSWAP(Uint8*, dest_pic.data[1], dest_pic.data[2]);
}
}
break;
case SDL_FCC_RV32:
......
......@@ -29,7 +29,7 @@
#include "ijksdl_inc_ffmpeg.h"
// TODO: 9 alignment to speed up memcpy when display
SDL_VoutOverlay *SDL_VoutFFmpeg_CreateOverlay(int width, int height, Uint32 format, SDL_Vout *display);
SDL_VoutOverlay *SDL_VoutFFmpeg_CreateOverlay(int width, int height, Uint32 format, SDL_Vout *vout);
int SDL_VoutFFmpeg_ConvertFrame(
SDL_VoutOverlay *overlay, AVFrame *frame,
......
......@@ -22,6 +22,7 @@
*/
#include "ijksdl_aout.h"
#include <stdlib.h>
int SDL_AoutOpenAudio(SDL_Aout *aout, SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
{
......
/*****************************************************************************
* ijksdl_audio.c
*****************************************************************************
*
* copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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;
}
......@@ -29,6 +29,18 @@
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 */
......@@ -75,4 +87,6 @@ typedef struct SDL_AudioSpec
void *userdata;
} SDL_AudioSpec;
void SDL_CalculateAudioSpec(SDL_AudioSpec * spec);
#endif
......@@ -24,6 +24,7 @@
#include "ijksdl_mutex.h"
#include <errno.h>
#include <assert.h>
#include <sys/time.h>
#include "ijksdl_inc_internal.h"
SDL_mutex *SDL_CreateMutex(void)
......@@ -35,6 +36,7 @@ SDL_mutex *SDL_CreateMutex(void)
if (pthread_mutex_init(&mutex->id, NULL) != 0) {
free(mutex);
return NULL;
}
return mutex;
......@@ -75,6 +77,7 @@ SDL_cond *SDL_CreateCond(void)
if (pthread_cond_init(&cond->id, NULL) != 0) {
free(cond);
return NULL;
}
return cond;
......
......@@ -24,6 +24,7 @@
#ifndef IJKSDL__IJKSDL_STDINC_H
#define IJKSDL__IJKSDL_STDINC_H
#include <stddef.h>
#include <stdint.h>
typedef int8_t Sint8;
......
......@@ -26,23 +26,28 @@
#include "ijksdl_inc_internal.h"
#include "ijksdl_thread.h"
#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);
thread->retval = thread->func(thread->data);
return NULL;
}
SDL_Thread *SDL_CreateThreadEx(SDL_Thread *thread, int (*fn)(void *), void *data)
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)
{
......
......@@ -38,10 +38,11 @@ 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);
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);
......
......@@ -24,6 +24,15 @@
#include "ijksdl_timer.h"
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#if defined(__APPLE__)
#include <mach/mach_time.h>
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;
#endif
void SDL_Delay(Uint32 ms)
{
......@@ -43,8 +52,23 @@ void SDL_Delay(Uint32 ms)
Uint64 SDL_GetTickHR(void)
{
Uint64 clock;
#if defined(__ANDROID__)
struct timespec now;
clock_gettime(CLOCK_MONOTONIC_HR, &now);
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);
}
......@@ -22,9 +22,12 @@
*/
#include "ijksdl_vout.h"
#include <stdlib.h>
#include <assert.h>
#if defined(__ANDROID__)
#include <android/native_window_jni.h>
#endif
void SDL_VoutFree(SDL_Vout *vout)
{
......@@ -54,6 +57,15 @@ int SDL_VoutDisplayYUVOverlay(SDL_Vout *vout, SDL_VoutOverlay *overlay)
return -1;
}
SDL_VoutOverlay *SDL_Vout_CreateOverlay(int width, int height, Uint32 format, SDL_Vout *vout)
{
if (vout && vout->create_overlay)
return vout->create_overlay(width, height, format, vout);
return NULL;
}
int SDL_VoutLockYUVOverlay(SDL_VoutOverlay *overlay)
{
if (overlay && overlay->lock)
......
......@@ -50,6 +50,7 @@ typedef struct SDL_Vout {
SDL_mutex *mutex;
SDL_Vout_Opaque *opaque;
SDL_VoutOverlay *(*create_overlay)(int width, int height, Uint32 format, SDL_Vout *vout);
void (*free_l)(SDL_Vout *vout);
int (*display_overlay)(SDL_Vout *vout, SDL_VoutOverlay *overlay);
} SDL_Vout;
......@@ -58,6 +59,7 @@ void SDL_VoutFree(SDL_Vout *vout);
void SDL_VoutFreeP(SDL_Vout **pvout);
int SDL_VoutDisplayYUVOverlay(SDL_Vout *vout, SDL_VoutOverlay *overlay);
SDL_VoutOverlay *SDL_Vout_CreateOverlay(int width, int height, Uint32 format, SDL_Vout *vout);
int SDL_VoutLockYUVOverlay(SDL_VoutOverlay *overlay);
int SDL_VoutUnlockYUVOverlay(SDL_VoutOverlay *overlay);
void SDL_VoutFreeYUVOverlay(SDL_VoutOverlay *overlay);
......
......@@ -25,7 +25,7 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS += -std=c99
LOCAL_SRC_FILES += loghelp.c
LOCAL_SRC_FILES += android/loghelp.c
LOCAL_MODULE := ijkutil_c
include $(BUILD_STATIC_LIBRARY)
......
......@@ -24,8 +24,7 @@
#ifndef IJKUTIL__IJKUTIL_ANDROID_H
#define IJKUTIL__IJKUTIL_ANDROID_H
#include "ijkutil.h"
#include "android/jnihelp.h"
#include "jnihelp.h"
#define JNI_CHECK_GOTO(condition__, env__, exception__, msg__, label__) \
do { \
......
......@@ -21,7 +21,7 @@
#include <string.h>
#include <assert.h>
#include "../loghelp.h"
#include "loghelp.h"
/**
* Equivalent to ScopedLocalRef, but for C_JNIEnv instead. (And slightly more powerful.)
......
......@@ -21,8 +21,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef IJKUTIL__LOGHELP_H
#define IJKUTIL__LOGHELP_H
#ifndef IJKUTIL_ANDROID__LOGHELP_H
#define IJKUTIL_ANDROID__LOGHELP_H
#include <android/log.h>
......@@ -32,8 +32,8 @@ extern "C" {
#define IJK_LOG_TAG "IJKMEDIA"
#define IJK_LOG_UNKNOWN ANDROID_LOG_UNKNOWN;
#define IJK_LOG_DEFAULT ANDROID_LOG_DEFAULT;
#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
......
/*****************************************************************************
* ijklog.h
*****************************************************************************
*
* copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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 IJKUTIL__IJKLOG_H
#define IJKUTIL__IJKLOG_H
#if defined(__ANDROID__)
#include "android/loghelp.h"
#elif defined(__APPLE__)
#include "ios/loghelp.h"
#endif
#endif
......@@ -25,7 +25,8 @@
#define IJKUTIL__IJKUTIL_H
#include <stdlib.h>
#include "loghelp.h"
#include <memory.h>
#include "ijklog.h"
#ifndef IJKMAX
#define IJKMAX(a, b) ((a) > (b) ? (a) : (b))
......@@ -45,7 +46,7 @@
return (retval__); \
}
inline void *mallocz(size_t size)
inline static void *mallocz(size_t size)
{
void *mem = malloc(size);
if (!mem)
......@@ -55,7 +56,7 @@ inline void *mallocz(size_t size)
return mem;
}
inline void freep(void **mem)
inline static void freep(void **mem)
{
if (mem && *mem) {
free(*mem);
......@@ -63,4 +64,10 @@ inline void freep(void **mem)
}
}
#if defined(__ANDROID__)
#include "android/ijkutil_android.h"
#elif defined(__APPLE__)
#include "ios/ijkutil_ios.h"
#endif
#endif
/*****************************************************************************
* ijkutil_ios.h
*****************************************************************************
*
* copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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 IJKUTIL__IOS_ANDROID_H
#define IJKUTIL__IOS_ANDROID_H
#endif
/*****************************************************************************
* loghelper.h
*****************************************************************************
*
* copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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 IJKUTIL_IOS__LOGHELP_H
#define IJKUTIL_IOS__LOGHELP_H
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#define IJK_LOG_TAG "IJKMEDIA"
#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 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 ALOG(level, TAG, ...) ((void)printf(__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)
#ifdef __cplusplus
}
#endif
#endif
#! /bin/sh
IJK_FFMPEG_UPSTREAM=git://git.videolan.org/ffmpeg.git
IJK_FFMPEG_FORK=https://github.com/bbcallen/FFmpeg.git
IJK_FFMPEG_COMMIT=ijk-r0.0.5-dev
IJK_FFMPEG_LOCAL_REPO=extra/ffmpeg
set -e
TOOLS=tools
echo "== pull ffmpeg base =="
sh $TOOLS/pull-repo-base.sh $IJK_FFMPEG_UPSTREAM $IJK_FFMPEG_LOCAL_REPO
echo "== pull ffmpeg fork =="
sh $TOOLS/pull-repo-ref.sh $IJK_FFMPEG_FORK android/ffmpeg-armv7a ${IJK_FFMPEG_LOCAL_REPO}
cd android/ffmpeg-armv7a
git checkout ${IJK_FFMPEG_COMMIT}
cd -
#! /bin/sh
IJK_FFMPEG_UPSTREAM=git://git.videolan.org/ffmpeg.git
IJK_FFMPEG_FORK=https://github.com/bbcallen/FFmpeg.git
IJK_FFMPEG_COMMIT=ijk-r0.0.5-dev
IJK_FFMPEG_LOCAL_REPO=extra/ffmpeg
set -e
TOOLS=tools
echo "== pull gas-preprocessor base =="
sh $TOOLS/pull-repo-base.sh git://git.libav.org/gas-preprocessor.git ${IJK_FFMPEG_LOCAL_REPO}
echo "== pull ffmpeg base =="
sh $TOOLS/pull-repo-base.sh $IJK_FFMPEG_UPSTREAM ${IJK_FFMPEG_LOCAL_REPO}
echo "== pull ffmpeg fork armv7 =="
sh $TOOLS/pull-repo-ref.sh $IJK_FFMPEG_FORK ios/ffmpeg-armv7 ${IJK_FFMPEG_LOCAL_REPO}
cd ios/ffmpeg-armv7
git checkout ${IJK_FFMPEG_COMMIT}
cd -
echo "== pull ffmpeg fork armv7s =="
sh $TOOLS/pull-repo-ref.sh $IJK_FFMPEG_FORK ios/ffmpeg-armv7s ${IJK_FFMPEG_LOCAL_REPO}
cd ios/ffmpeg-armv7s
git checkout ${IJK_FFMPEG_COMMIT}
cd -
echo "== pull ffmpeg fork i386 =="
sh $TOOLS/pull-repo-ref.sh $IJK_FFMPEG_FORK ios/ffmpeg-i386 ${IJK_FFMPEG_LOCAL_REPO}
cd ios/ffmpeg-i386
git checkout ${IJK_FFMPEG_COMMIT}
cd -
#! /bin/sh
IJK_FFMPEG_COMMIT=ijk-r0.0.5-dev
IJK_FFMPEG_LOCAL_REPO=extra/ffmpeg
set -e
echo "== pull ffmpeg base =="
if [ ! -d ${IJK_FFMPEG_LOCAL_REPO} ]; then
git clone git://git.videolan.org/ffmpeg.git ${IJK_FFMPEG_LOCAL_REPO}
else
cd ${IJK_FFMPEG_LOCAL_REPO}
git pull
cd -
fi
echo "== pull ffmpeg fork =="
if [ ! -d "android/ffmpeg-armv7a" ]; then
git clone --reference "${IJK_FFMPEG_LOCAL_REPO}" https://github.com/bbcallen/FFmpeg.git android/ffmpeg-armv7a
cd android/ffmpeg-armv7a
# do not depend on the reference repo
git repack -a
else
echo "== pull ffmpeg base =="
cd android/ffmpeg-armv7a
git fetch --all
fi
git checkout ${IJK_FFMPEG_COMMIT}
cd -
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:IJKMediaDemo/IJKMediaDemo.xcodeproj">
</FileRef>
<FileRef
location = "group:IJKMediaPlayer/IJKMediaPlayer.xcodeproj">
</FileRef>
</Workspace>
此差异已折叠。
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:IJKMediaDemo.xcodeproj">
</FileRef>
</Workspace>
//
// IJKAppDelegate.h
// IJKMediaDemo
//
// Created by ZhangRui on 13-9-19.
// Copyright (c) 2013年 bilibili. All rights reserved.
//
#import <UIKit/UIKit.h>
@class IJKVideoViewController;
@interface IJKAppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) IJKVideoViewController *viewController;
@end
//
// IJKAppDelegate.m
// IJKMediaDemo
//
// Created by ZhangRui on 13-9-19.
// Copyright (c) 2013年 bilibili. All rights reserved.
//
#import "IJKAppDelegate.h"
#import "IJKMoviePlayerViewController.h"
@implementation IJKAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[IJKVideoViewController alloc] initView];
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.
[[IJKMediaModule sharedModule] applicationWillResignActive:application];
}
- (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.
[[IJKMediaModule sharedModule] applicationDidEnterBackground:application];
}
- (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.
[[IJKMediaModule sharedModule] applicationDidBecomeActive:application];
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
[[IJKMediaModule sharedModule] applicationWillTerminate:application];
}
@end
//
// IJKCommon.h
// IJKMediaDemo
//
// Created by ZhangRui on 13-9-23.
// Copyright (c) 2013年 bilibili. All rights reserved.
//
#import <Foundation/Foundation.h>
#define IOS_OLDER_THAN_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] < 6.0 )
#define IOS_NEWER_OR_EQUAL_TO_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 6.0 )
//
// IJKMediaControl.h
// IJKMediaDemo
//
// Created by ZhangRui on 13-9-22.
// Copyright (c) 2013年 bilibili. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface IJKMediaControl : UIControl
- (void)showNoFade;
- (void)showAndFade;
- (void)hide;
- (void)refreshMediaControl;
@property(nonatomic,weak) id<IJKMediaPlayback> 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
//
// IJKMediaControl.m
// IJKMediaDemo
//
// Created by ZhangRui on 13-9-22.
// Copyright (c) 2013年 bilibili. All rights reserved.
//
#import "IJKMediaControl.h"
@implementation IJKMediaControl
- (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)refreshMediaControl
{
NSTimeInterval duration = self.delegatePlayer.duration;
NSTimeInterval position = self.delegatePlayer.currentPlaybackTime;
NSInteger intDuration = duration + 0.5;
NSInteger intPosition = position + 0.5;
self.currentTimeLabel.text = [NSString stringWithFormat:@"%02d:%02d", intPosition / 60, intPosition % 60];
if (intDuration > 0) {
self.totalDurationLabel.text = [NSString stringWithFormat:@"%02d:%02d", intDuration / 60, intDuration % 60];
self.mediaProgressSlider.value = position;
self.mediaProgressSlider.maximumValue = duration;
} else {
self.totalDurationLabel.text = @"--:--";
self.mediaProgressSlider.value = 0.0f;
self.mediaProgressSlider.maximumValue = 1.0f;
}
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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>tv.danmaku.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
//
// Prefix header for all source files of the 'test' target in the 'test' project
//
#import <Availability.h>
#ifndef __IPHONE_3_0
#warning "This project uses features only available in iOS SDK 3.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <MediaPlayer/MediaPlayer.h>
#import "IJKMediaPlayer/IJKMediaPlayer.h"
#endif
\ No newline at end of file
//
// IJKMoviePlayerController.h
// IJKMediaDemo
//
// Created by ZhangRui on 13-9-21.
// Copyright (c) 2013年 bilibili. All rights reserved.
//
#import <UIKit/UIKit.h>
@class IJKMediaControl;
@interface IJKVideoViewController : UIViewController
@property(atomic, retain) id<IJKMediaPlayback> player;
- (id)initView;
- (IBAction)onClickMediaControl:(id)sender;
- (IBAction)onClickOverlay:(id)sender;
- (IBAction)onClickBack:(id)sender;
- (IBAction)onClickPlay:(id)sender;
- (IBAction)onClickPause:(id)sender;
@property(nonatomic,strong) IBOutlet IJKMediaControl *mediaControl;
@end
//
// IJKMoviePlayerController.m
// IJKMediaDemo
//
// Created by ZhangRui on 13-9-21.
// Copyright (c) 2013年 bilibili. All rights reserved.
//
#import "IJKMoviePlayerViewController.h"
#import "IJKMediaControl.h"
#import "IJKCommon.h"
@implementation IJKVideoViewController
- (id)initView
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return [self initWithNibName:@"IJKMoviePlayerViewController" bundle:nil];
} else {
return [self initWithNibName:@"IJKMoviePlayerViewController" bundle:nil];
}
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (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];
// NSURL *theMovieURL = [NSURL URLWithString:@"rtsp://l.m.cztv.com:554/hdmi/hntv1hd.stream"];
// NSURL *theMovieURL = [NSURL URLWithString:@"http://edge.v.iask.com/115151121.hlv?KID=sina,viask&Expires=1380297600&ssig=SjfwCmaiLe"];
NSURL *theMovieURL = [NSURL URLWithString:@"http://edge.v.iask.com/115279108.hlv?KID=sina,viask&Expires=1380297600&ssig=KpcdjFjrhW"];
// NSURL *theMovieURL = [NSURL URLWithString:@"http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8"];
self.player = [[IJKFFMoviePlayerController alloc] initWithContentURL:theMovieURL];
self.player.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
self.player.view.frame = self.view.bounds;
self.view.autoresizesSubviews = YES;
[self.view addSubview:self.player.view];
[self.view addSubview:self.mediaControl];
self.mediaControl.delegatePlayer = self.player;
[self.player prepareToPlay];
[self.player play];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationLandscapeLeft;
}
- (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)onClickBack:(id)sender
{
exit(0);
}
- (IBAction)onClickPlay:(id)sender
{
[self.player play];
[self.mediaControl refreshMediaControl];
}
- (IBAction)onClickPause:(id)sender
{
[self.player pause];
[self.mediaControl refreshMediaControl];
}
@end
/* Localized versions of Info.plist keys */
//
// main.m
// IJKMediaDemo
//
// Created by ZhangRui on 13-9-19.
// Copyright (c) 2013年 bilibili. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "IJKAppDelegate.h"
int main(int argc, char *argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([IJKAppDelegate class]));
}
}
/*
* IJKFFMoviePlayerController.h
*
* Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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"
@interface IJKFFMoviePlayerController : NSObject <IJKMediaPlayback>
- (id)initWithContentURL:(NSURL *)aUrl;
- (void)prepareToPlay;
- (void)play;
- (void)pause;
- (void)stop;
- (BOOL)isPlaying;
@end
/*
* IJKFFMoviePlayerController.m
*
* Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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 "IJKFFMoviePlayerDef.h"
#import "IJKMediaPlayback.h"
@implementation IJKFFMoviePlayerController {
NSURL *_url;
IjkMediaPlayer *_mediaPlayer;
IJKFFMoviePlayerMessagePool *_msgPool;
NSInteger _videoWidth;
NSInteger _videoHeight;
NSInteger _sampleAspectRatioNumerator;
NSInteger _sampleAspectRatioDenominator;
}
@synthesize view = _view;
@synthesize currentPlaybackTime;
@synthesize duration;
@synthesize playableDuration;
@synthesize isPreparedToPlay;
@synthesize playbackState = _playbackState;
@synthesize loadState = _loadState;
- (id)initWithContentURL:(NSURL *)aUrl
{
self = [super init];
if (self) {
ijkmp_global_init();
_url = aUrl;
_mediaPlayer = ijkmp_ios_create(media_player_msg_loop);
_msgPool = [[IJKFFMoviePlayerMessagePool alloc] init];
ijkmp_set_weak_thiz(_mediaPlayer, (__bridge_retained void *) self);
IJKSDLGLView *glView = [[IJKSDLGLView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self->_view = glView;
ijkmp_ios_set_glview(_mediaPlayer, glView);
ijkmp_set_overlay_format(_mediaPlayer, SDL_FCC_I420);
}
return self;
}
- (void)prepareToPlay
{
if (!_mediaPlayer)
return;
ijkmp_set_data_source(_mediaPlayer, [[_url absoluteString] UTF8String]);
ijkmp_prepare_async(_mediaPlayer);
}
- (void)play
{
if (!_mediaPlayer)
return;
ijkmp_start(_mediaPlayer);
}
- (void)pause
{
if (!_mediaPlayer)
return;
ijkmp_pause(_mediaPlayer);
}
- (void)stop
{
if (!_mediaPlayer)
return;
ijkmp_stop(_mediaPlayer);
}
- (BOOL)isPlaying
{
if (!_mediaPlayer)
return NO;
return ijkmp_is_playing(_mediaPlayer);
}
- (void)setCurrentPlaybackTime:(NSTimeInterval)aCurrentPlaybackTime
{
if (!_mediaPlayer)
return;
ijkmp_seek_to(_mediaPlayer, aCurrentPlaybackTime * 1000);
}
- (NSTimeInterval)currentPlaybackTime
{
if (!_mediaPlayer)
return 0.0f;
NSTimeInterval ret = ijkmp_get_current_position(_mediaPlayer);
return ret / 1000;
}
- (NSTimeInterval)duration
{
if (!_mediaPlayer)
return 0.0f;
NSTimeInterval ret = ijkmp_get_duration(_mediaPlayer);
return ret / 1000;
}
- (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", avmsg->arg1);
_playbackState = MPMoviePlaybackStateStopped;
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMoviePlayerPlaybackDidFinishNotification object:self];
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMoviePlayerPlaybackDidFinishNotification
object:self
userInfo:@{
MPMoviePlayerPlaybackDidFinishReasonUserInfoKey: @(MPMovieFinishReasonPlaybackError),
@"error": @(avmsg->arg1)}];
break;
}
case FFP_MSG_PREPARED:
NSLog(@"FFP_MSG_PREPARED:");
isPreparedToPlay = YES;
[[NSNotificationCenter defaultCenter] postNotificationName:IJKMediaPlaybackIsPreparedToPlayDidChangeNotification object:self];
break;
case FFP_MSG_COMPLETED: {
_playbackState = MPMoviePlaybackStateStopped;
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMoviePlayerPlaybackDidFinishNotification object:self];
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMoviePlayerPlaybackDidFinishNotification
object:self
userInfo:@{MPMoviePlayerPlaybackDidFinishReasonUserInfoKey: @(MPMovieFinishReasonPlaybackError)}];
break;
}
case FFP_MSG_VIDEO_SIZE_CHANGED:
NSLog(@"FFP_MSG_VIDEO_SIZE_CHANGED: %d, %d", avmsg->arg1, avmsg->arg2);
if (avmsg->arg1 > 0)
_videoWidth = avmsg->arg1;
if (avmsg->arg2 > 0)
_videoHeight = avmsg->arg2;
// TODO: notify size changed
break;
case FFP_MSG_SAR_CHANGED:
NSLog(@"FFP_MSG_SAR_CHANGED: %d, %d", avmsg->arg1, avmsg->arg2);
if (avmsg->arg1 > 0)
_sampleAspectRatioNumerator = avmsg->arg1;
if (avmsg->arg2 > 0)
_sampleAspectRatioDenominator = avmsg->arg2;
break;
case FFP_MSG_BUFFERING_START: {
NSLog(@"FFP_MSG_BUFFERING_START:");
_loadState = MPMovieLoadStateStalled;
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMoviePlayerLoadStateDidChangeNotification
object:self];
break;
}
case FFP_MSG_BUFFERING_END: {
NSLog(@"FFP_MSG_BUFFERING_END:");
_loadState = MPMovieLoadStatePlaythroughOK;
[[NSNotificationCenter defaultCenter]
postNotificationName:IJKMoviePlayerLoadStateDidChangeNotification
object:self];
break;
}
case FFP_MSG_BUFFERING_UPDATE:
// NSLog(@"FFP_MSG_BUFFERING_UPDATE: %d, %d", avmsg->arg1, avmsg->arg2);
break;
case FFP_MSG_BUFFERING_BYTES_UPDATE:
// NSLog(@"FFP_MSG_BUFFERING_BYTES_UPDATE: %d", avmsg->arg1);
break;
case FFP_MSG_BUFFERING_TIME_UPDATE:
// NSLog(@"FFP_MSG_BUFFERING_TIME_UPDATE: %d", avmsg->arg1);
break;
case FFP_MSG_SEEK_COMPLETE:
// NSLog(@"FFP_MSG_SEEK_COMPLETE:");
break;
default:
// NSLog(@"unknown FFP_MSG_xxx(%d)", 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];
}
}
return 0;
}
}
@end
/*
* IJKFFMoviePlayerDef.h
*
* Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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 <Foundation/Foundation.h>
#include "ijkplayer/ios/ijkplayer_ios.h"
@interface IJKFFMoviePlayerMessage : NSObject {
@public
AVMessage _msg;
}
@end
@interface IJKFFMoviePlayerMessagePool : NSObject
- (IJKFFMoviePlayerMessagePool *)init;
- (IJKFFMoviePlayerMessage *) obtain;
- (void) recycle:(IJKFFMoviePlayerMessage *)msg;
@end
/*
* IJKFFMoviePlayerDef.m
*
* Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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;
@synchronized(self) {
if ([_array count] <= 10)
[_array addObject:msg];
}
}
@end
\ No newline at end of file
/*
* IJKMPMoviePlayerController.h
*
* Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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"
@interface IJKMPMoviePlayerController : MPMoviePlayerController <IJKMediaPlayback>
- (id)initWithContentURL:(NSURL *)aUrl;
@end
/*
* IJKMediaModule.h
*
* Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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 <Foundation/Foundation.h>
@interface IJKMediaModule : NSObject
+ (IJKMediaModule *) sharedModule;
- (void) lockApp;
- (void) unlockApp;
- (BOOL) tryLockActiveApp;
- (void)applicationWillResignActive:(UIApplication *)application;
- (void)applicationDidEnterBackground:(UIApplication *)application;
- (void)applicationDidBecomeActive:(UIApplication *)application;
- (void)applicationWillTerminate:(UIApplication *)application;
@end
此差异已折叠。
此差异已折叠。
/*
* IJKMediaPlayback.m
*
* Copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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 IJKMediaPlaybackIsPreparedToPlayDidChangeNotification = @"IJKMediaPlaybackIsPreparedToPlayDidChangeNotification";
NSString *const IJKMoviePlayerLoadStateDidChangeNotification = @"IJKMoviePlayerLoadStateDidChangeNotification";
NSString *const IJKMoviePlayerPlaybackDidFinishNotification = @"IJKMoviePlayerPlaybackDidFinishNotification";
NSString *const IJKMoviePlayerPlaybackStateDidChangeNotification = @"IJKMoviePlayerPlaybackStateDidChangeNotification";
\ No newline at end of file
//
// Prefix header for all source files of the 'IJKMediaPlayer' target in the 'IJKMediaPlayer' project
//
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <MediaPlayer/MediaPlayer.h>
#import <AudioUnit/AudioUnit.h>
#import <CoreAudio/CoreAudioTypes.h>
#import <AudioToolbox/AudioToolbox.h>
#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/EAGLDrawable.h>
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES2/gl.h>
#import <OpenGLES/ES2/glext.h>
#endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册