当前位置:网站首页>Overview of demoplayer program framework design of ijkplayer
Overview of demoplayer program framework design of ijkplayer
2022-06-13 06:27:00 【That's right】
First step Read this source code for a walk , The following preparations are needed
JNI Methods and java How does the method correspond to ?
Android JNI Principle analysis
http://gityuan.com/2016/05/28/android-jni/
JNI Development :
Android The use of notes CMake Conduct JNI Development (Android Studio)
https://anacz.blog.csdn.net/article/details/84202451
JNI Learning notes
Android JNI Study ( 3、 ... and )——Java And Native Mutual invocation
https://www.jianshu.com/p/b71aeb4ed13d
ijkplayer A brief analysis of the framework – From construction to onPrepared
http://yydcdut.com/2019/03/16/ijkplayer-from-constructor-to-prepare/
The following articles can be used as advanced materials .
H264 Detailed explanation of codec protocol
https://blog.csdn.net/qq_19923217/article/details/83348095
https://www.jianshu.com/p/0c296b05ef2a
Support h265 Hard solution and soft solution of Consider the compatibility of hard solutions
Android NDK MediaCodec stay ijkplayer Practice in
https://www.cnblogs.com/jukan/p/9845673.html
The second step DemoPlayer Source code
Source code github Address : https://github.com/YBill/IjkPlayerProject_2.git
The third step Source code walkthrough is the framework description
- 1> Program entry
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import com.bill.ijkplayerproject_2.util.PageJumpUtil;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); ///> There are two on the interface botton
}
public void handleAudioTest(View view) {
///> onClick() Event activation handleAudioTest
PageJumpUtil.gotoAudioTestActivity(this);
}
public void handleVideoTest(View view) {
///> onClick() Event activation handleVideoTest
//PageJumpUtil.gotoVideoSettingActivity(this);
PageJumpUtil.gotoVideoTestActivity(this);
}
}
- 2> Intermediate activation Intent The process
public class PageJumpUtil {
public static void gotoAudioTestActivity(Activity activity) {
Intent intent = new Intent(activity, AudioTestActivity.class); ///> Audio test Activity
activity.startActivity(intent);
}
public static void gotoVideoTestActivity(Activity activity) {
Intent intent = new Intent(activity, VideoTestActivity.class); ///> Video test Activity
activity.startActivity(intent);
}
public static void gotoVideoSettingActivity(Activity activity) {
Intent intent = new Intent(activity, VideoSettingActivity.class);
activity.startActivity(intent);
}
}
- 3> Video startup process
///> VideoTestActivity.java in app start-up
public class VideoTestActivity extends AppCompatActivity {
private boolean mBackPressed;
private IjkVideoView mVideoView; ///> be based on ijkPlayer-java Medium IMediaPlayer interface Encapsulate the implementation of IjkVideoView class
private AndroidMediaController mMediaController; ///> be based on Androidsdk Of MediaController Realization Demo The interface applied in , Interface content IMediaController in .
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_test);
mVideoView = findViewById(R.id.ijk_video_view);
mMediaController = new AndroidMediaController(this, true);
mVideoView.setMediaController(mMediaController);
mMediaController.setPrevNextListeners(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(VideoTestActivity.this, " next ", Toast.LENGTH_SHORT).show();
}
}, new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(VideoTestActivity.this, " the previous ", Toast.LENGTH_SHORT).show();
}
});
IjkMediaPlayer.loadLibrariesOnce(null); ///> 1>. Use ijkplayer-java Player class methods encapsulated in
IjkMediaPlayer.native_profileBegin("libijkplayer.so"); ///> 2>. load ijkplayer.so The library files
mVideoView.setVideoPath("https://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f30.mp4"); ///> 3>. Create player 、 And put the player in the ready playing state
// mVideoView.setVideoPath("https://wdl.wallstreetcn.com/41aae4d2-390a-48ff-9230-ee865552e72d");
// mVideoView.setVideoPath("http://o6wf52jln.bkt.clouddn.com/ actor .mp3");
mVideoView.start(); ///> 4>. start-up VideoView Components , Start the player to play
}
@Override
public void onBackPressed() {
mBackPressed = true;
super.onBackPressed();
}
@Override
protected void onStop() {
super.onStop();
if (mBackPressed || !mVideoView.isBackgroundPlayEnabled()) {
mVideoView.stopPlayback();
mVideoView.release(true);
mVideoView.stopBackgroundPlay();
} else {
mVideoView.enterBackground();
}
IjkMediaPlayer.native_profileEnd();
}
}
///> mVideoView.setVideoPath(Uri *) In the method , The final call ijkVideoView.java The implementation is as follows
private void setVideoURI(Uri uri, Map<String, String> headers) {
mUri = uri;
mHeaders = headers;
mSeekWhenPrepared = 0;
openVideo(); ///> This method creates a player 、 And configure the control callback
requestLayout();
invalidate();
}
///> Open video method , Create... In this method ijkplayer player 、 And set the callback of the relevant user control program
@TargetApi(Build.VERSION_CODES.M)
private void openVideo() {
try {
mMediaPlayer = createPlayer(PlayerConfig.getInstance().getPlayer()); ///> 1. Create player , This method configures the parameters to select the player type ExoPlayer、AndroidPlayer or ijkPlayer
// a context for the subtitle renderers
final Context context = getContext();
// REMOVED: SubtitleController
// REMOVED: mAudioSession
/** The video is ready to play */
mMediaPlayer.setOnPreparedListener(mPreparedListener);
/** Video interface size change monitoring */
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
/** Video playback completed listening */
mMediaPlayer.setOnCompletionListener(mCompletionListener);
/** Video error monitoring */
mMediaPlayer.setOnErrorListener(mErrorListener);
/** Video and other information monitoring */
mMediaPlayer.setOnInfoListener(mInfoListener);
/** Video buffer monitor */
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
mMediaPlayer.setOnSeekCompleteListener(mSeekCompleteListener);
mMediaPlayer.setOnTimedTextListener(mOnTimedTextListener);
mCurrentBufferPercentage = 0;
String scheme = mUri.getScheme();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
PlayerConfig.getInstance().getUsingMediaDataSource() &&
(TextUtils.isEmpty(scheme) || scheme.equalsIgnoreCase("file"))) {
IMediaDataSource dataSource = new FileMediaDataSource(new File(mUri.toString()));
mMediaPlayer.setDataSource(dataSource);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
mMediaPlayer.setDataSource(mAppContext, mUri, mHeaders);
} else {
mMediaPlayer.setDataSource(mUri.toString());
}
bindSurfaceHolder(mMediaPlayer, mSurfaceHolder);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setScreenOnWhilePlaying(true);
mPrepareStartTime = System.currentTimeMillis();
mMediaPlayer.prepareAsync();
// REMOVED: mPendingSubtitleTracks
// we don't set the target state here either, but preserve the
// target state that was there before.
mCurrentState = STATE_PREPARING; ///> 2. Set the player status to Preparation stage
attachMediaController();
} catch (IOException ex) {
Log.w(TAG, "Unable to open content: " + mUri, ex);
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
} catch (IllegalArgumentException ex) {
Log.w(TAG, "Unable to open content: " + mUri, ex);
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
} finally {
// REMOVED: mPendingSubtitleTracks.clear();
}
}
///> ijkVideoView.java Medium VideoView Method
public void start() {
if (isInPlaybackState()) {
mMediaPlayer.start(); ///> 3. Start the player to play
mCurrentState = STATE_PLAYING; ///> 4. Set the status to play
}
mTargetState = STATE_PLAYING;
}
- 4> Player packaging method
this Demo Used in the program IjkMediaPlayer The class evolution route is as follows .
This is ijkplayer The source code provides ijkplayer-java In file Demo Program , This program encapsulates IjkMediaPlayer class .
public interface IMediaPlayer {
}
————————————————————————————————
||
\/
public abstract class AbstractMediaPlayer implements IMediaPlayer {
}
____________________________________________________________________
||
\/
public final class IjkMediaPlayer extends AbstractMediaPlayer {
}
_________________________________________________________________
The implementation logic of the class is as follows , What we care about now is Java How the program relates to ijkplayer In the source code C Language programs are associated with ?
The first part In the materials prepared for you , It has been mentioned , We combine this Demo Smooth out the interrelationship .
- 4.1> Let's look at it first IjkMediaPlayer in Start the player implementation method .
public final class IjkMediaPlayer extends AbstractMediaPlayer {
@Override
public void start() throws IllegalStateException {
stayAwake(true);
_start(); ///> This method calls native _start() function
}
private native void _start() throws IllegalStateException; ///> Statement here native void _start() function , Function implementation ?
@Override
public void stop() throws IllegalStateException {
stayAwake(false);
_stop();
}
private native void _stop() throws IllegalStateException;
@Override
public void pause() throws IllegalStateException {
stayAwake(false);
_pause();
}
private native void _pause() throws IllegalStateException;
}
- 4.2> jni Dynamic registration of interface methods
This part needs to see ijkplayer Source program file ijkplayer\ijkplayer_jni.c file , Yes JNI Method
The contents of the registration function are as follows :
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv* env = NULL;
g_jvm = vm;
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
assert(env != NULL);
pthread_mutex_init(&g_clazz.mutex, NULL );
// FindClass returns LocalReference
IJK_FIND_JAVA_CLASS(env, g_clazz.clazz, JNI_CLASS_IJKPLAYER);
(*env)->RegisterNatives(env, g_clazz.clazz, g_methods, NELEM(g_methods) ); ///> Dynamic registration jni Interface method
ijkmp_global_init();
ijkmp_global_set_inject_callback(inject_callback);
FFmpegApi_global_init(env);
return JNI_VERSION_1_4;
}
///> ijkplayer Registered jni The method is as follows :
static JNINativeMethod g_methods[] = {
{
"_setDataSource",
"(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
(void *) IjkMediaPlayer_setDataSourceAndHeaders}, ///> IjkMediaPlayer_setDataSourceAndHeaders(JNIEnv *env, jobject thiz,
jstring path,jobjectArray keys, jobjectArray values);
{
"_setDataSourceFd", "(I)V", (void *) IjkMediaPlayer_setDataSourceFd }, ///> _setDataSourceFd(), Set the local file as the playback source JNI Interface
{
"_setDataSource",
"(Ltv/danmaku/ijk/media/player/misc/IMediaDataSource;)V",
(void *) IjkMediaPlayer_setDataSourceCallback }, ///> _setDataSource(), Set the network file playback source JNI Interface
{
"_setVideoSurface", "(Landroid/view/Surface;)V", (void *) IjkMediaPlayer_setVideoSurface },
{
"_prepareAsync", "()V", (void *) IjkMediaPlayer_prepareAsync },
{
"_start", "()V", (void *) IjkMediaPlayer_start }, ///> _start() Start player method , C The implementation of the language is analyzed next .
{
"_stop", "()V", (void *) IjkMediaPlayer_stop },
{
"seekTo", "(J)V", (void *) IjkMediaPlayer_seekTo },
{
"_pause", "()V", (void *) IjkMediaPlayer_pause },
{
"isPlaying", "()Z", (void *) IjkMediaPlayer_isPlaying },
{
"getCurrentPosition", "()J", (void *) IjkMediaPlayer_getCurrentPosition },
{
"getDuration", "()J", (void *) IjkMediaPlayer_getDuration },
{
"_release", "()V", (void *) IjkMediaPlayer_release },
{
"_reset", "()V", (void *) IjkMediaPlayer_reset },
{
"setVolume", "(FF)V", (void *) IjkMediaPlayer_setVolume },
{
"getAudioSessionId", "()I", (void *) IjkMediaPlayer_getAudioSessionId },
{
"native_init", "()V", (void *) IjkMediaPlayer_native_init },
{
"native_setup", "(Ljava/lang/Object;)V", (void *) IjkMediaPlayer_native_setup },
{
"native_finalize", "()V", (void *) IjkMediaPlayer_native_finalize },
{
"_setOption", "(ILjava/lang/String;Ljava/lang/String;)V", (void *) IjkMediaPlayer_setOption },
{
"_setOption", "(ILjava/lang/String;J)V", (void *) IjkMediaPlayer_setOptionLong },
{
"_getColorFormatName", "(I)Ljava/lang/String;", (void *) IjkMediaPlayer_getColorFormatName },
{
"_getVideoCodecInfo", "()Ljava/lang/String;", (void *) IjkMediaPlayer_getVideoCodecInfo },
{
"_getAudioCodecInfo", "()Ljava/lang/String;", (void *) IjkMediaPlayer_getAudioCodecInfo },
{
"_getMediaMeta", "()Landroid/os/Bundle;", (void *) IjkMediaPlayer_getMediaMeta },
{
"_setLoopCount", "(I)V", (void *) IjkMediaPlayer_setLoopCount },
{
"_getLoopCount", "()I", (void *) IjkMediaPlayer_getLoopCount },
{
"_getPropertyFloat", "(IF)F", (void *) ijkMediaPlayer_getPropertyFloat },
{
"_setPropertyFloat", "(IF)V", (void *) ijkMediaPlayer_setPropertyFloat },
{
"_getPropertyLong", "(IJ)J", (void *) ijkMediaPlayer_getPropertyLong },
{
"_setPropertyLong", "(IJ)V", (void *) ijkMediaPlayer_setPropertyLong },
{
"_setStreamSelected", "(IZ)V", (void *) ijkMediaPlayer_setStreamSelected },
{
"native_profileBegin", "(Ljava/lang/String;)V", (void *) IjkMediaPlayer_native_profileBegin },
{
"native_profileEnd", "()V", (void *) IjkMediaPlayer_native_profileEnd },
{
"native_setLogLevel", "(I)V", (void *) IjkMediaPlayer_native_setLogLevel },
};
///> ijkplayer_jni.c Your player starts
static void
IjkMediaPlayer_start(JNIEnv *env, jobject thiz)
{
MPTRACE("%s\n", __func__);
IjkMediaPlayer *mp = jni_get_media_player(env, thiz);
JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: start: null mp", LABEL_RETURN);
ijkmp_start(mp);
LABEL_RETURN:
ijkmp_dec_ref_p(&mp);
}
///> ijkplayer.c File to start the
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 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); ///> Through the event mode of message queue 、 Notify the player .
return 0;
}
this _start() So many interfaces are analyzed , The main point of this article is _setDataSource() Interface implementation , Because I need to tidy up ijkplayer This part of the code .
Step four Go to school _setDataSource() Interface implementation code
4.1>. The next step is from java Code entry starts , How users use this _setDataSource() Interface .
public void setVideoPath(String path) {
setVideoURI(Uri.parse(path)); ///> structure Uri
}
public void setVideoURI(Uri uri) {
setVideoURI(uri, null); ///> Map<String, String> headers This parameter is set to null
}
private void setVideoURI(Uri uri, Map<String, String> headers) {
mUri = uri;
mHeaders = headers;
mSeekWhenPrepared = 0;
openVideo();
requestLayout();
invalidate();
}
From this process, we can see that setting up the data source is only uri Assign values to the private Uri mUri in ; Next let's look at openVideo() How to use mUri Variable .
4.2>. Open the video
@TargetApi(Build.VERSION_CODES.M)
private void openVideo() {
if (mUri == null || mSurfaceHolder == null) {
// not ready for playback just yet, will try again later
return;
}
String scheme = mUri.getScheme();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
PlayerConfig.getInstance().getUsingMediaDataSource() &&
(TextUtils.isEmpty(scheme) || scheme.equalsIgnoreCase("file"))) {
IMediaDataSource dataSource = new FileMediaDataSource(new File(mUri.toString()));
mMediaPlayer.setDataSource(dataSource); ///> IMediaDataSource type
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
mMediaPlayer.setDataSource(mAppContext, mUri, mHeaders); ///> Context type
} else {
mMediaPlayer.setDataSource(mUri.toString()); ///> String type
}
}
///> The three corresponding methods for setting data sources , stay IjkMediaPlayer.java Implemented in , as follows .
public final class IjkMediaPlayer extends AbstractMediaPlayer {
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
@Override
public void setDataSource(Context context, Uri uri, Map<String, String> headers)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
final String scheme = uri.getScheme();
if (ContentResolver.SCHEME_FILE.equals(scheme)) {
setDataSource(uri.getPath());
return;
} else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
&& Settings.AUTHORITY.equals(uri.getAuthority())) {
// Redirect ringtones to go directly to underlying provider
uri = RingtoneManager.getActualDefaultRingtoneUri(context,
RingtoneManager.getDefaultType(uri));
if (uri == null) {
throw new FileNotFoundException("Failed to resolve default ringtone");
}
}
AssetFileDescriptor fd = null;
try {
///> file type
ContentResolver resolver = context.getContentResolver();
fd = resolver.openAssetFileDescriptor(uri, "r");
if (fd == null) {
return;
}
// Note: using getDeclaredLength so that our behavior is the same
// as previous versions when the content provider is returning
// a full file.
if (fd.getDeclaredLength() < 0) {
setDataSource(fd.getFileDescriptor());
} else {
setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getDeclaredLength());
}
return;
} catch (SecurityException ignored) {
} catch (IOException ignored) {
} finally {
if (fd != null) {
fd.close();
}
}
Log.d(TAG, "Couldn't open file on client side, trying server side");
setDataSource(uri.toString(), headers);
}
public void setDataSource(String path, Map<String, String> headers)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException
{
if (headers != null && !headers.isEmpty()) {
StringBuilder sb = new StringBuilder();
for(Map.Entry<String, String> entry: headers.entrySet()) {
sb.append(entry.getKey());
sb.append(":");
String value = entry.getValue();
if (!TextUtils.isEmpty(value))
sb.append(entry.getValue());
sb.append("\r\n");
setOption(OPT_CATEGORY_FORMAT, "headers", sb.toString());
setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "protocol_whitelist", "async,cache,crypto,file,http,https,ijkhttphook,ijkinject,ijklivehook,ijklongurl,ijksegment,ijktcphook,pipe,rtp,tcp,tls,udp,ijkurlhook,data");
}
}
setDataSource(path);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
@Override
public void setDataSource(FileDescriptor fd)
throws IOException, IllegalArgumentException, IllegalStateException {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1) {
int native_fd = -1;
try {
Field f = fd.getClass().getDeclaredField("descriptor"); //NoSuchFieldException
f.setAccessible(true);
native_fd = f.getInt(fd); //IllegalAccessException
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
_setDataSourceFd(native_fd);
} else {
ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(fd);
try {
_setDataSourceFd(pfd.getFd());
} finally {
pfd.close();
}
}
}
public void setDataSource(IMediaDataSource mediaDataSource)
throws IllegalArgumentException, SecurityException, IllegalStateException {
_setDataSource(mediaDataSource);
}
private native void _setDataSource(String path, String[] keys, String[] values)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
private native void _setDataSourceFd(int fd)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
private native void _setDataSource(IMediaDataSource mediaDataSource)
throws IllegalArgumentException, SecurityException, IllegalStateException;
}
This section is for JNI Three interfaces for method registration , I will focus on _setDataSource(String path, String[] keys, String[] values) Network part of C The realization of language .
4.3> go back to ijkplayer_jni.c In file , Find the corresponding C The realization of language
static void
IjkMediaPlayer_setDataSourceAndHeaders(
JNIEnv *env, jobject thiz, jstring path,
jobjectArray keys, jobjectArray values)
{
MPTRACE("%s\n", __func__);
int retval = 0;
const char *c_path = NULL;
IjkMediaPlayer *mp = jni_get_media_player(env, thiz);
JNI_CHECK_GOTO(path, env, "java/lang/IllegalArgumentException", "mpjni: setDataSource: null path", LABEL_RETURN);
JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: setDataSource: null mp", LABEL_RETURN);
c_path = (*env)->GetStringUTFChars(env, path, NULL );
JNI_CHECK_GOTO(c_path, env, "java/lang/OutOfMemoryError", "mpjni: setDataSource: path.string oom", LABEL_RETURN);
ALOGV("setDataSource: path %s", c_path);
retval = ijkmp_set_data_source(mp, c_path);
(*env)->ReleaseStringUTFChars(env, path, c_path);
IJK_CHECK_MPRET_GOTO(retval, env, LABEL_RETURN);
LABEL_RETURN:
ijkmp_dec_ref_p(&mp);
}
///>
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;
}
///> ijkplayer.c in
static int ijkmp_set_data_source_l(IjkMediaPlayer *mp, const char *url)
{
assert(mp);
assert(url);
// MPST_RET_IF_EQ(mp->mp_state, MP_STATE_IDLE);
MPST_RET_IF_EQ(mp->mp_state, MP_STATE_INITIALIZED);
MPST_RET_IF_EQ(mp->mp_state, MP_STATE_ASYNC_PREPARING);
MPST_RET_IF_EQ(mp->mp_state, MP_STATE_PREPARED);
MPST_RET_IF_EQ(mp->mp_state, MP_STATE_STARTED);
MPST_RET_IF_EQ(mp->mp_state, MP_STATE_PAUSED);
MPST_RET_IF_EQ(mp->mp_state, MP_STATE_COMPLETED);
MPST_RET_IF_EQ(mp->mp_state, MP_STATE_STOPPED);
MPST_RET_IF_EQ(mp->mp_state, MP_STATE_ERROR);
MPST_RET_IF_EQ(mp->mp_state, MP_STATE_END);
freep((void**)&mp->data_source);
mp->data_source = strdup(url); ///> Change the data source content
if (!mp->data_source)
return EIJK_OUT_OF_MEMORY;
ijkmp_change_state_l(mp, MP_STATE_INITIALIZED); ///> Change the player state to the initial state
return 0;
}
void ijkmp_change_state_l(IjkMediaPlayer *mp, int new_state)
{
mp->mp_state = new_state; ///> Notification status content
ffp_notify_msg1(mp->ffplayer, FFP_MSG_PLAYBACK_STATE_CHANGED); ///> Notification player
}
The above section completes the code reading of the data source setting section .
边栏推荐
- Wechat applet: click the event to obtain the current device information (basic)
- 推荐扩容工具,彻底解决C盘及其它磁盘空间不够的难题
- IOError(Errors.E050.format(name=name))
- View绘制整体流程简析
- Waterfall flow layout of uni app Homepage
- Fichier local second Search Tool everything
- Uniapp mobile terminal uses canvas to draw background convex arc
- 【案例】一个超级好用的工具 —— 给程序员用的计算器
- Recent problems
- 【Kernel】驱动编译的两种方式:编译成模块、编译进内核(使用杂项设备驱动模板)
猜你喜欢
1+1 > 2, share creators can help you achieve
Free screen recording software captura download and installation
App performance test: (III) traffic monitoring
Echart折线图:当多条折线图的name一样时也显示不同的颜色
MFS详解(七)——MFS客户端与web监控安装配置
JS to realize bidirectional data binding
【新手上路常见问答】关于技术管理
JetPack - - - Navigation
JVM Foundation
After clicking the uniapp e-commerce H5 embedded applet, the page prompts "the page iframe does not support referencing non business domain names"
随机推荐
Waterfall flow layout of uni app Homepage
Differences among concurrent, parallel, serial, synchronous and asynchronous
Recyclerview has data flicker problem using databinding
Wechat applet: basic review
楊輝三角形詳解
Wechat applet custom tabbar (session customer service) vant
Echart line chart: multiple line charts show only one line at a time
JetPack - - - LifeCycle、ViewModel、LiveData
Huawei developer certification and deveco studio compiler Download
Echart柱状图:echart实现堆叠柱状图
Applet export (use) public function, public data
Uni app upload file
1+1 > 2, share creators can help you achieve
The web server failed to start Port 7001 was already in use
Multiple reception occurs in the uniapp message delivery
El form form verification
JetPack - - - Navigation
[case] a super easy-to-use tool -- a calculator for programmers
synchronized浅析
Thread pool learning