本连续记录 IJKPLAYER 代码走读文章,其主要的目的是在 IPKPLAYER 中增加私有网络通讯协议
和私有解封装器。 本篇文章是成果输出记录,通过实例再次阐述 IJKPLAYER 的解协议、解封装的
实现逻辑。
并在本文中把实现过程做详细记录,供大家参考,以防个人备忘。
第一 H264 解封装ffmpeg实现过程分析
///> 源码文件路径 libavformat/h264dec.c
/*
1、找到nalu定位符0x00 0x00 0x01
2、解析nalu头
3、检查borbidden bit
4、判断ref idc是否和nalu type相符
5、预解析nalu
1、若是slice,则判断slice头的pps id是否已经存在
2、若是sps,则记录sps id
3、若是pps,则判断其sps id是否研究存在,记录pps id
6、若有sps、pps、slice(I/P/B/IDR),则表明是一个H.264/AVC的数据流
*/
static int h264_probe(AVProbeData *p)
{
uint32_t code = -1;
int sps = 0, pps = 0, idr = 0, res = 0, sli = 0;
int i, ret;
int pps_ids[MAX_PPS_COUNT+1] = {0};
int sps_ids[MAX_SPS_COUNT+1] = {0};
unsigned pps_id, sps_id;
GetBitContext gb;
for (i = 0; i + 2 < p->buf_size; i++) {
code = (code << 8) + p->buf[i];
if ((code & 0xffffff00) == 0x100) {
int ref_idc = (code >> 5) & 3; //解析nalu头
int type = code & 0x1F;
static const int8_t ref_zero[] = {
2, 0, 0, 0, 0, -1, 1, -1,
-1, 1, 1, 1, 1, -1, 2, 2,
2, 2, 2, 0, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2
};
if (code & 0x80) // forbidden_bit
return 0;
if (ref_zero[type] == 1 && ref_idc)
return 0;
if (ref_zero[type] == -1 && !ref_idc)
return 0;
if (ref_zero[type] == 2) {
if (!(code == 0x100 && !p->buf[i + 1] && !p->buf[i + 2]))
res++;
}
ret = init_get_bits8(&gb, p->buf + i + 1, p->buf_size - i - 1);
if (ret < 0)
return 0;
switch (type) {
case 1:
case 5:
get_ue_golomb_long(&gb);
if (get_ue_golomb_long(&gb) > 9U)
return 0;
pps_id = get_ue_golomb_long(&gb);
if (pps_id > MAX_PPS_COUNT)
return 0;
if (!pps_ids[pps_id])
break;
if (type == 1)
sli++;
else
idr++;
break;
case 7:
skip_bits(&gb, 14);
if (get_bits(&gb, 2))
return 0;
skip_bits(&gb, 8);
sps_id = get_ue_golomb_long(&gb);
if (sps_id > MAX_SPS_COUNT)
return 0;
sps_ids[sps_id] = 1;
sps++;
break;
case 8:
pps_id = get_ue_golomb_long(&gb);
if (pps_id > MAX_PPS_COUNT)
return 0;
sps_id = get_ue_golomb_long(&gb);
if (sps_id > MAX_SPS_COUNT)
return 0;
if (!sps_ids[sps_id])
break;
pps_ids[pps_id] = 1;
pps++;
break;
}
}
}
ff_tlog(NULL, "sps:%d pps:%d idr:%d sli:%d res:%d\n", sps, pps, idr, sli, res);
if (sps && pps && (idr || sli > 3) && res < (sps + pps + idr))
return AVPROBE_SCORE_EXTENSION + 1; // 1 more than .mpg
return 0;
}
FF_DEF_RAWVIDEO_DEMUXER(h264, "raw H.264 video", h264_probe, "h26l,h264,264,avc", AV_CODEC_ID_H264)
//> 1. 此宏定义在源码在 libavformat/rawdec.h 中,
#define FF_DEF_RAWVIDEO_DEMUXER(shortname, longname, probe, ext, id)\
FF_DEF_RAWVIDEO_DEMUXER2(shortname, longname, probe, ext, id, AVFMT_GENERIC_INDEX)
#define FF_DEF_RAWVIDEO_DEMUXER2(shortname, longname, probe, ext, id, flag)\
FF_RAWVIDEO_DEMUXER_CLASS(shortname)\
AVInputFormat ff_ ## shortname ## _demuxer = {\
.name = #shortname,\
.long_name = NULL_IF_CONFIG_SMALL(longname),\
.read_probe = probe,\
.read_header = ff_raw_video_read_header,\
.read_packet = ff_raw_read_partial_packet,\
.extensions = ext,\
.flags = flag,\
.raw_codec_id = id,\
.priv_data_size = sizeof(FFRawVideoDemuxerContext),\
.priv_class = &shortname ## _demuxer_class,\
};
//> 2. 此宏展开生成的源码如下:
AVInputFormat ff_h264_demuxer = {
.name = "h264",
.long_name = "raw H.264 video",
.read_probe = h264_probe,
.read_header = ff_raw_data_read_header,
.read_packet = ff_raw_read_partial_packet,
.extensions = "h26l,h264,264,avc",
.flags = AVFMT_GENERIC_INDEX,
.raw_codec_id = AV_CODEC_ID_H264,
.priv_data_size = 0,
.priv_class = &h264_demuxer_class,
};
#define FF_RAWVIDEO_DEMUXER_CLASS(name)\
static const AVClass name ## _demuxer_class = {\
.class_name = #name " demuxer",\
.item_name = av_default_item_name,\
.option = ff_rawvideo_options,\
.version = LIBAVUTIL_VERSION_INT,\
};
//> 3. 此宏展开生成的源码如下:
static const AVClass h264_demuxer_class = {
.class_name = "h264 demuxer",
.item_name = av_default_item_name,
.option = ff_rawvideo_options,
.version = LIBAVUTIL_VERSION_INT,
};
//> 此部分代码在 libavformat/rawdec.c 中
#define OFFSET(x) offsetof(FFRawVideoDemuxerContext, x)
#define DEC AV_OPT_FLAG_DECODING_PARAM
const AVOption ff_rawvideo_options[] = {
{ "framerate", "", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, DEC},
{ NULL },
};
通过此段源码的分析,我们得到 h264 裸数据解封装入口函数、和数据包读取函数的实现方法。
第二步 ijkplayer 中增加 H.264 解封装器的支持,因为默认没有打开.
IJKPLAYER 添加编译 h264 裸数据解封装方法:
脚本 compile_ffmpeg.sh 调用 tools/do-complie-ffmpeg.sh,在该文件中添加下面内容:
///> do-complie-ffmpeg.sh 文件内容
#--------------------
# with openssl
if [ -f "${FF_DEP_OPENSSL_LIB}/libssl.a" ]; then
echo "OpenSSL detected"
# FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-nonfree"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-openssl"
FF_CFLAGS="$FF_CFLAGS -I${FF_DEP_OPENSSL_INC}"
FF_DEP_LIBS="$FF_DEP_LIBS -L${FF_DEP_OPENSSL_LIB} -lssl -lcrypto"
fi
if [ -f "${FF_DEP_LIBSOXR_LIB}/libsoxr.a" ]; then
echo "libsoxr detected"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-libsoxr"
FF_CFLAGS="$FF_CFLAGS -I${FF_DEP_LIBSOXR_INC}"
FF_DEP_LIBS="$FF_DEP_LIBS -L${FF_DEP_LIBSOXR_LIB} -lsoxr"
fi
FF_CFG_FLAGS="$FF_CFG_FLAGS $COMMON_FF_CFG_FLAGS"
#--------------------
# Standard options:
FF_CFG_FLAGS="$FF_CFG_FLAGS --prefix=$FF_PREFIX"
# Advanced options (experts only):
FF_CFG_FLAGS="$FF_CFG_FLAGS --cross-prefix=${FF_CROSS_PREFIX}-"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-cross-compile"
FF_CFG_FLAGS="$FF_CFG_FLAGS --target-os=linux"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-pic"
# FF_CFG_FLAGS="$FF_CFG_FLAGS --disable-symver"
## <start>
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-demuxer=h264"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-protocol=udp"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-decoder=h264"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-parser=h264"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-hwaccel=h264_vaapi"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-hwaccel=h264_vaapi"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-hwaccel=h264_dxva2"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-demuxer=mjpeg"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-demuxer=rtsp"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-demuxer=rtp"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-encoder=h264"
## <end>
if [ "$FF_ARCH" = "x86" ]; then
FF_CFG_FLAGS="$FF_CFG_FLAGS --disable-asm"
else
# Optimization options (experts only):
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-asm"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-inline-asm"
fi
第三部分 增加私有协议
3.1> 在 对应硬件架构下编写私有协议
本次采用 ffmpeg-arm64\libavformat\tcp_ext.c 文件,文件是在tcp.c 文件基础上修改。
修改中需要注意的内容如下。
#define FAST_OPEN_FLAG 0x20000000
#define OFFSET(x) offsetof(TCPEXTContext, x)
#define D AV_OPT_FLAG_DECODING_PARAM
#define E AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
{ "listen", "Listen for incoming connections", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, .flags = D|E },
{ "timeout", "set timeout (in microseconds) of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
{ "connect_timeout", "set connect timeout (in microseconds) of socket", OFFSET(open_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
{ "listen_timeout", "Connection awaiting timeout (in milliseconds)", OFFSET(listen_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
{ "send_buffer_size", "Socket send buffer size (in bytes)", OFFSET(send_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
{ "recv_buffer_size", "Socket receive buffer size (in bytes)", OFFSET(recv_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
{ "ijkapplication", "AVApplicationContext", OFFSET(app_ctx_intptr), AV_OPT_TYPE_INT64, { .i64 = 0 }, INT64_MIN, INT64_MAX, .flags = D },
{ "addrinfo_one_by_one", "parse addrinfo one by one in getaddrinfo()", OFFSET(addrinfo_one_by_one), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E },
{ "addrinfo_timeout", "set timeout (in microseconds) for getaddrinfo()", OFFSET(addrinfo_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
{ "dns_cache_timeout", "dns cache TTL (in microseconds)", OFFSET(dns_cache_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
{ "dns_cache_clear", "clear dns cache", OFFSET(dns_cache_clear), AV_OPT_TYPE_INT, { .i64 = 0}, -1, INT_MAX, .flags = D|E },
{ "fastopen", "enable fastopen", OFFSET(fastopen), AV_OPT_TYPE_INT, { .i64 = 0}, 0, INT_MAX, .flags = D|E },
{ NULL }
};
static const AVClass tcpext_class = {
.class_name = "tcpext",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
... 省略实现的代码。
const URLProtocol ff_tcpext_protocol = {
.name = "tcpext",
.url_open = tcp_open,
.url_accept = tcp_accept,
.url_read = tcp_read,
.url_write = tcp_write,
.url_close = tcp_close,
.url_get_file_handle = tcp_get_file_handle,
.url_get_short_seek = tcp_get_window_size,
.url_shutdown = tcp_shutdown,
.priv_data_size = sizeof(TCPEXTContext),
.flags = URL_PROTOCOL_FLAG_NETWORK,
.priv_data_class = &tcpext_class,
};
3.2 ff_tcpext_protocol 静态结构体内容增加至\libavformat\protocols.c 文件中
extern const URLProtocol ff_rtmp_protocol;
extern const URLProtocol ff_rtmpe_protocol;
extern const URLProtocol ff_rtmps_protocol;
extern const URLProtocol ff_rtmpt_protocol;
extern const URLProtocol ff_rtmpte_protocol;
extern const URLProtocol ff_rtmpts_protocol;
extern const URLProtocol ff_rtp_protocol;
extern const URLProtocol ff_sctp_protocol;
extern const URLProtocol ff_srtp_protocol;
extern const URLProtocol ff_subfile_protocol;
extern const URLProtocol ff_tee_protocol;
extern const URLProtocol ff_tcp_protocol;
extern const URLProtocol ff_tls_gnutls_protocol;
extern const URLProtocol ff_tls_schannel_protocol;
extern const URLProtocol ff_tls_securetransport_protocol;
extern const URLProtocol ff_tls_openssl_protocol;
extern const URLProtocol ff_udp_protocol;
extern const URLProtocol ff_udplite_protocol;
extern const URLProtocol ff_unix_protocol;
extern const URLProtocol ff_librtmp_protocol;
extern const URLProtocol ff_librtmpe_protocol;
extern const URLProtocol ff_librtmps_protocol;
extern const URLProtocol ff_librtmpt_protocol;
extern const URLProtocol ff_librtmpte_protocol;
extern const URLProtocol ff_libssh_protocol;
extern const URLProtocol ff_libsmbclient_protocol;
extern const URLProtocol ff_tcpext_protocol; ///> 在此处添加
#include "libavformat/protocol_list.c"
const AVClass *ff_urlcontext_child_class_next(const AVClass *prev)
{
int i;
/* find the protocol that corresponds to prev */
for (i = 0; prev && url_protocols[i]; i++) {
if (url_protocols[i]->priv_data_class == prev) {
i++;
break;
}
}
/* find next protocol with priv options */
for (; url_protocols[i]; i++)
if (url_protocols[i]->priv_data_class)
return url_protocols[i]->priv_data_class;
return NULL;
}
3.3 修改 Makefile 文件内容,编译 tcp_ext.c 文件
OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o
OBJS-$(CONFIG_SCTP_PROTOCOL) += sctp.o
OBJS-$(CONFIG_SRTP_PROTOCOL) += srtpproto.o srtp.o
OBJS-$(CONFIG_SUBFILE_PROTOCOL) += subfile.o
OBJS-$(CONFIG_TEE_PROTOCOL) += teeproto.o tee_common.o
OBJS-$(CONFIG_TCP_PROTOCOL) += tcp.o
OBJS-$(CONFIG_TCPEXT_PROTOCOL) += tcp_ext.o ///> 参考 tcp 协议方式添加
OBJS-$(CONFIG_TLS_GNUTLS_PROTOCOL) += tls_gnutls.o tls.o
OBJS-$(CONFIG_TLS_OPENSSL_PROTOCOL) += tls_openssl.o tls.o
OBJS-$(CONFIG_TLS_SCHANNEL_PROTOCOL) += tls_schannel.o tls.o
OBJS-$(CONFIG_TLS_SECURETRANSPORT_PROTOCOL) += tls_securetransport.o tls.o
OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o
OBJS-$(CONFIG_UDPLITE_PROTOCOL) += udp.o
OBJS-$(CONFIG_UNIX_PROTOCOL) += unix.o
3.4 重要提示:
你的源码如果 git clone 下来代码,需要使用 git add 把修改的文件添加到版本中.
否则 ./compile-ffmpeg.sh clean 时后,代码就被清楚了,因为脚本是使用 git clean
处理的文件。
需要把 ijkplayer 中支持的硬件平台 libavformat 文件夹下的 Makefile 文件都修改,并
添加 tcp_ext.c 文件,否则 ./compile-ffmpeg.sh all 编译报错,因为是编译所以硬件架构so库.
3.5 重新编译 ffmpeg 和 ijkplayer 代码
///> 实现clean前面编译生成的内容.
robot@ubuntu:~/ljbPlayer/ijkplayer/android/contrib$ ./compile-ffmpeg.sh clean
///> 1. 编译 ffmpeg
robot@ubuntu:~/ljbPlayer/ijkplayer/android/contrib$ ./compile-ffmpeg.sh all
====================
[*] check archs
====================
FF_ALL_ARCHS = armv5 armv7a arm64 x86 x86_64
FF_ACT_ARCHS = armv5 armv7a arm64 x86 x86_64
====================
[*] check env armv5
====================
FF_ARCH=armv5
FF_BUILD_OPT=
--------------------
[*] make NDK standalone toolchain
--------------------
build on Linux x86_64
ANDROID_NDK=/home/robot/Android/Sdk/ndk/android-ndk-r14b/
IJK_NDK_REL=14.1.3816874
NDKr14.1.3816874 detected
--------------------
[*] check ffmpeg env
--------------------
--------------------
[*] configurate ffmpeg
--------------------
reuse configure
--------------------
[*] compile ffmpeg
--------------------
--------------------
[*] create files for shared ffmpeg
--------------------
--------------------
[*] Finished
--------------------
# to continue to build ijkplayer, run script below,
sh compile-ijk.sh
robot@ubuntu:~/ljbPlayer/ijkplayer/android/contrib$
///> 2. 编译 ijkplayer
robot@ubuntu:~/ljbPlayer/ijkplayer/android$ ./compile-ijk.sh all
profiler build: NO
[armeabi] Prebuilt : libijkffmpeg.so <= /home/robot/ljbPlayer/ijkplayer/android/contrib/build/ffmpeg-armv5/output/
[armeabi] Compile thumb : ijkplayer <= ff_cmdutils.c
[armeabi] Compile thumb : ijkplayer <= ff_ffplay.c
[armeabi] Compile thumb : ijkplayer <= ff_ffpipeline.c
[armeabi] Compile thumb : ijkplayer <= ijkmeta.c
[armeabi] Compile thumb : ijkplayer <= ijkplayer.c
[armeabi] Compile thumb : ijkplayer <= ffpipeline_ffplay.c
[armeabi] Compile thumb : ijkplayer <= ffpipenode_ffplay_vdec.c
[armeabi] Compile thumb : ijkplayer <= ffmpeg_api_jni.c
[armeabi] Compile thumb : ijkplayer <= ijkplayer_android.c
[armeabi] Compile thumb : ijkplayer <= ijkplayer_jni.c
[armeabi] Compile thumb : ijkplayer <= ffpipeline_android.c
[armeabi] Compile thumb : ijkplayer <= ffpipenode_android_mediacodec_vdec.c
[armeabi] Compile thumb : ijkplayer <= allformats.c
[armeabi] Compile thumb : ijkplayer <= ijklivehook.c
[armeabi] Compile thumb : ijkplayer <= ijkmediadatasource.c
...
[x86_64] Compile : ijksdl <= renderer.c
[x86_64] Compile : ijksdl <= renderer_rgb.c
[x86_64] Compile : ijksdl <= renderer_yuv420p.c
[x86_64] Compile : ijksdl <= renderer_yuv444p10le.c
[x86_64] Compile : ijksdl <= shader.c
[x86_64] Compile : ijksdl <= rgb.fsh.c
[x86_64] Compile : ijksdl <= yuv420p.fsh.c
[x86_64] Compile : ijksdl <= yuv444p10le.fsh.c
[x86_64] Compile : ijksdl <= mvp.vsh.c
[x86_64] Compile : ijksdl <= ijksdl_vout_dummy.c
[x86_64] Compile : ijksdl <= ijksdl_vout_overlay_ffmpeg.c
[x86_64] Compile : ijksdl <= image_convert.c
[x86_64] Compile : ijksdl <= android_nativewindow.c
[x86_64] Compile : ijksdl <= ijksdl_vout_android_surface.c
[x86_64] Compile : ijksdl <= ijksdl_vout_android_nativewindow.c
[x86_64] Compile : ijksdl <= ijksdl_vout_overlay_android_mediacodec.c
[x86_64] Install : libijkffmpeg.so => libs/x86_64/libijkffmpeg.so
[x86_64] SharedLibrary : libijksdl.so
[x86_64] Install : libijksdl.so => libs/x86_64/libijksdl.so
[x86_64] SharedLibrary : libijkplayer.so
[x86_64] Install : libijkplayer.so => libs/x86_64/libijkplayer.so
/home/robot/ljbPlayer/ijkplayer/android
///> 3.更换 ANDROID 工程中的库文件
robot@ubuntu:~/ljbPlayer/ijkplayer/android$ cp -r ijkplayer/ijkplayer-arm64/src/main/libs/arm64-v8a/libijk* /home/robot/Videos/IjkPlayerProject_2/app/src/main/jniLibs/arm64-v8a/
第 四 步 验证中应用的文件
首先通过 ffmpeg 生成 h264 格式文件。
FFMPEG 录制屏幕输出 mp4 文件的方法:
ffmpeg -video_size 1024x768 -framerate 25 -f x11grab -i :0.0+100,200 v-out.mp4
指的是从屏幕的左上角(x=100, y=200)的位置,录制分辨率为1024×768的视频。
从 mp4提取 h264 格式数据流的方法:
ffmpeg -i 20130312_133313.mp4 -codec copy -bsf h264_mp4toannexb -f h264 20130312_133313.264
说明:
-i 20130312_133313.mp4 :是输入的MP4文件
-codec copy:从MP4封装中进行拷贝
-bsf: h264_mp4toannexb:从MP4拷贝到annexB封装
-f h264:采用h.264格式
20130312_133313.264:输出的文件名称
第 五 步 验证结果日志
D/IJKMEDIA: IjkMediaPlayer_setDataSourceAndHeaders
V/IJKMEDIA: setDataSource: path tcpext://192.168.1.55:7777/v-out.h264
D/IJKMEDIA: ijkmp_set_data_source(url="tcpext://192.168.1.55:7777/v-out.h264")
ijkmp_set_data_source(url="tcpext://192.168.1.55:7777/v-out.h264")=0
I/IjkVideoView: type 2
D/IJKMEDIA: IjkMediaPlayer_setVideoSurface
ijkmp_set_android_surface(surface=0x7fd6646a78)
ffpipeline_set_surface()
ijkmp_set_android_surface(surface=0x7fd6646a78)=void
IjkMediaPlayer_prepareAsync
ijkmp_prepare_async()
I/IJKMEDIA: ===== versions =====
ijkplayer : k0.8.8-7-gf10b8d1a
FFmpeg : ff3.4--ijk0.8.7--20180103--001-1-gf921a673ba6
libavutil : 55.78.100
libavcodec : 57.107.100
libavformat : 57.83.100
libswscale : 4.8.100
libswresample: 2.9.100
===== options =====
player-opts : mediacodec = 0
player-opts : opensles = 0
player-opts : overlay-format = 842225234
player-opts : framedrop = 1
player-opts : start-on-prepared = 0
I/IJKMEDIA: format-opts : ijkapplication = 525242808320
format-opts : ijkiomanager = 525555707008
format-opts : http-detect-range-support = 0
codec-opts : skip_loop_filter = 48
===================
D/IJKMEDIA: ijkmp_prepare_async()=0
I/IJKMEDIA: SDL_RunThread: [20145] ff_read
DEBUG read_thread, LINE:3116 ,ffp->iformat_name:(null)
libavformat/utils.c / avformat_open_input , LINE:537
libavformat/format.c / av_probe_input_format2 , LINE:254
libavformat/format.c / av_probe_input_format3 , LINE:202
libavformat/format.c / av_probe_input_format3 , LINE:208 ,EXT name:(null)
libavformat/format.c / av_probe_input_format3, LINE:211, probeName:ijklivehook
libavformat/format.c / av_probe_input_format3 , LINE:247
libavformat/utils.c / init_input , LINE:415
D/IJKMEDIA: Opening 'tcpext://192.168.1.55:7777/v-out.h264' for reading
No default whitelist set
I/IJKMEDIA: libavformat/tcp.c / tcp_open , LINE:358 ,tcp open url:tcpext://192.168.1.55:7777/v-out.h264
I/tv.danmaku.ijk.media.player.IjkMediaPlayer: onNativeInvoke 131073
I/IJKMEDIA: SDL_RunThread: [20144] ff_vout
I/IJKMEDIA: SDL_RunThread: [20143] ff_msg_loop
D/IJKMEDIA: message_loop
FFP_MSG_FLUSH:
D/HwGalleryCacheManagerImpl: mIsEffect:false
I/tv.danmaku.ijk.media.player.IjkMediaPlayer: onNativeInvoke 131074
I/IJKMEDIA: libavformat/utils.c / init_input , LINE:421
libavformat/aviobuf.c / avio_read , LINE:637 ,size:2048
libavformat/aviobuf.c / avio_read , LINE:641 ,size:2048
libavformat/aviobuf.c / avio_read , LINE:666
libavformat/aviobuf.c / fill_buffer() , LINE:539 ,len:32768
libavformat/aviobuf.c / fill_buffer() , LINE:554
libavformat/aviobuf.c / fill_buffer() , LINE:567
I/zygote64: Do partial code cache collection, code=29KB, data=26KB
After code cache collection, code=29KB, data=26KB
Increasing code cache capacity to 128KB
D/OpenGLRenderer: HWUI Binary is enabled
W/InputMethodManager: startInputReason = 1
W/libEGL: EGLNativeWindowType 0x7a4ae48010 disconnect failed
D/OpenGLRenderer: endAllActiveAnimators on 0x7a4ae70400 (RippleDrawable) with handle 0x7a5d9ecf60
I/IJKMEDIA: libavformat/tcpext.c / tcp_read , LINE:756 recive len:1792 ///> 读取网络数据日志
I/IJKMEDIA: libavformat/aviobuf.c / fill_buffer() , LINE:584 ,bytes_read:1792
libavformat/aviobuf.c / avio_read , LINE:641 ,size:2048
libavformat/aviobuf.c / avio_read , LINE:641 ,size:256
libavformat/aviobuf.c / avio_read , LINE:666
libavformat/aviobuf.c / fill_buffer() , LINE:539 ,len:32768
libavformat/aviobuf.c / fill_buffer() , LINE:554
libavformat/aviobuf.c / fill_buffer() , LINE:567
I/IJKMEDIA: libavformat/tcpext.c / tcp_read , LINE:756 recive len:256
I/IJKMEDIA: libavformat/aviobuf.c / fill_buffer() , LINE:584 ,bytes_read:2048
libavformat/aviobuf.c / avio_read , LINE:641 ,size:256
libavformat/aviobuf.c / avio_read , LINE:679 ,size:0
libavformat/format.c / av_probe_input_buffer2 , LINE:331
libavformat/format.c / av_probe_input_format2 , LINE:254
libavformat/format.c / av_probe_input_format3 , LINE:202
libavformat/format.c / av_probe_input_format3 , LINE:208 ,EXT name:aac
libavformat/format.c / av_probe_input_format3, LINE:211, probeName:aac
libavformat/format.c / av_probe_input_format3 , LINE:208 ,EXT name:(null)
libavformat/format.c / av_probe_input_format3, LINE:211, probeName:concat
libavformat/format.c / av_probe_input_format3 , LINE:208 ,EXT name:(null)
libavformat/format.c / av_probe_input_format3 , LINE:208 ,EXT name:flac
libavformat/format.c / av_probe_input_format3, LINE:211, probeName:flac
libavformat/format.c / av_probe_input_format3 , LINE:208 ,EXT name:flv
libavformat/format.c / av_probe_input_format3, LINE:211, probeName:flv
libavformat/format.c / av_probe_input_format3 , LINE:208 ,EXT name:flv
libavformat/format.c / av_probe_input_format3, LINE:211, probeName:live_flv
libavformat/format.c / av_probe_input_format3 , LINE:208 ,EXT name:h26l,h264,264,avc ///> 此部分是解封装器 h264 内容。
libavformat/h264dec.c / h264_probe , LINE:40, buf_size:00000800
libavformat/h264dec.c code:ffffff00, index:0, buf:00
libavformat/h264dec.c code:ffff0000, index:1, buf:00
I/IJKMEDIA: libavformat/h264dec.c code:ff000000, index:2, buf:00
省略部分日志
libavformat/aviobuf.c / fill_buffer() , LINE:584 ,bytes_read:104704 /// 下面是解封装器输出结果
D/IJKMEDIA: user data:"x264 - core 155 r2917 0a84d98 - H.264/MPEG-4 AVC codec - Copyleft 2003-2018 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x1:0x111 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=0 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=4 threads=6 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00"
I/IJKMEDIA: libavformat/utils.c / avformat_find_stream_info() , LINE:3736
libavformat/utils.c / avformat_find_stream_info() , LINE:3747 ,read_size:104462
D/IJKMEDIA: nal_unit_type: 6, nal_ref_idc: 0
nal_unit_type: 7, nal_ref_idc: 3
D/IJKMEDIA: nal_unit_type: 8, nal_ref_idc: 3
D/IJKMEDIA: nal_unit_type: 5, nal_ref_idc: 3
I/IJKMEDIA: libavformat/utils.c / avformat_find_stream_info() , LINE:3839
D/IJKMEDIA: nal_unit_type: 6, nal_ref_idc: 0
nal_unit_type: 7, nal_ref_idc: 3
D/IJKMEDIA: nal_unit_type: 8, nal_ref_idc: 3
D/IJKMEDIA: nal_unit_type: 5, nal_ref_idc: 3
user data:"x264 - core 155 r2917 0a84d98 - H.264/MPEG-4 AVC codec - Copyleft 2003-2018 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x1:0x111 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=0 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=4 threads=6 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00"
I/IJKMEDIA: Reinit context to 1024x768, pix_fmt: yuv444p
D/IJKMEDIA: no picture
I/IJKMEDIA: libavformat/utils.c / avformat_find_stream_info() , LINE:3639
D/IJKMEDIA: Probe buffer size limit of 5000 bytes reached
W/IJKMEDIA: Stream #0: not enough frames to estimate rate; consider increasing probesize
I/IJKMEDIA: libavformat/utils.c / avformat_find_stream_info() , LINE:3858
libavformat/utils.c / avformat_find_stream_info() , LINE:3884
I/IJKMEDIA: libavformat/utils.c / avformat_find_stream_info() , LINE:3909
I/IJKMEDIA: libavformat/utils.c / avformat_find_stream_info() , LINE:3917
libavformat/utils.c / avformat_find_stream_info() , LINE:4009, probesize:5000
libavformat/utils.c / avformat_find_stream_info() , LINE:4042
libavformat/utils.c / avformat_find_stream_info() , LINE:4100
D/IJKMEDIA: After avformat_find_stream_info() pos: 104704 bytes read:104704 seeks:0 frames:1
I/IJKMEDIA: /home/robot/ljbPlayer/ijkplayer/android/ijkplayer/ijkplayer-arm64/src/main/jni/ijkmedia/ijkplayer/ff_ffplay.c / read_thread , LINE:3168
D/IJKMEDIA: FFP_MSG_FIND_STREAM_INFO:
I/IJKMEDIA: max_frame_duration: 10.000
Input #0, h264, from 'tcpext://192.168.1.55:7777/v-out.h264':
Duration:
N/A
, bitrate:
N/A
I/IJKMEDIA: Stream #0:0
D/IJKMEDIA: , 1, 1/1200000
I/IJKMEDIA: : Video: h264, 1 reference frame, yuv444p(progressive, left), 1024x768, 0/1
,
25 tbr,
1200k tbn,
50 tbc
/home/robot/ljbPlayer/ijkplayer/android/ijkplayer/ijkplayer-arm64/src/main/jni/ijkmedia/ijkplayer/ff_ffplay.c / read_thread , LINE:3216
DEBUG /home/robot/ljbPlayer/ijkplayer/android/ijkplayer/ijkplayer-arm64/src/main/jni/ijkmedia/ijkplayer/ff_ffplay.c, LINE:3239 ,CODEC_ID:28
/home/robot/ljbPlayer/ijkplayer/android/ijkplayer/ijkplayer-arm64/src/main/jni/ijkmedia/ijkplayer/ff_ffplay.c / read_thread , LINE:3241
D/IJKMEDIA: detected 8 logical cores
nal_unit_type: 7, nal_ref_idc: 3
nal_unit_type: 8, nal_ref_idc: 3
I/IJKMEDIA: VideoCodec: avcodec, h264
W/IJKMEDIA: fps: 25.000000 (normal)
D/IJKMEDIA: FFP_MSG_COMPONENT_OPEN:
I/IJKMEDIA: SDL_RunThread: [20161] ff_video_dec
D/IJKMEDIA: FFP_MSG_VIDEO_SIZE_CHANGED: 1024, 768
FFP_MSG_SAR_CHANGED: 0, 1
ijkmp_get_msg: FFP_MSG_PREPARED
FFP_MSG_PREPARED:
D/IJKMEDIA: FFP_MSG_VIDEO_ROTATION_CHANGED: 0
D/IJKMEDIA: ffp_toggle_buffering_l: start
D/IJKMEDIA: FFP_MSG_BUFFERING_START:
D/IjkVideoView: mLoadCost:9091
D/IjkVideoView: MEDIA_INFO_VIDEO_ROTATION_CHANGED: 0
E/: SurfaceView doesn't support rotation (0)!
D/IjkVideoView: MEDIA_INFO_BUFFERING_START:
D/IJKMEDIA: IjkMediaPlayer_start
ijkmp_start()
ijkmp_start()=0
D/IJKMEDIA: ijkmp_get_msg: FFP_REQ_START ///> 播放器启动播放输出日志
ijkmp_get_msg: FFP_REQ_START: start on fly
I/IJKMEDIA: /home/robot/ljbPlayer/ijkplayer/android/ijkplayer/ijkplayer-arm64/src/main/jni/ijkmedia/ijkplayer/ff_ffplay.c / read_thread , LINE:3349
/home/robot/ljbPlayer/ijkplayer/android/ijkplayer/ijkplayer-arm64/src/main/jni/ijkmedia/ijkplayer/ff_ffplay.c / read_thread , LINE:3521
D/IJKMEDIA: ijkmp_get_msg: FFP_REQ_START
ijkmp_get_msg: FFP_REQ_START: start on fly
I/IJKMEDIA: /home/robot/ljbPlayer/ijkplayer/android/ijkplayer/ijkplayer-arm64/src/main/jni/ijkmedia/ijkplayer/ff_ffplay.c / read_thread , LINE:3607
/home/robot/ljbPlayer/ijkplayer/android/ijkplayer/ijkplayer-arm64/src/main/jni/ijkmedia/ijkplayer/ff_ffplay.c / read_thread , LINE:3615
至此,在 ijkplayer 中添加私有协议、私有解封装器目标已经实现,存在的问题是
播放器启动播放时间太长,需要优化启动时间.
通过日志观察,耗时操作主要是 解码器类型识别部分,接下来我将针对函数进行优化。
libavformat/utils.c / avformat_find_stream_info()
相关学习研究过程,将还有 ijkplayer 代码走读方式分享出来。