设置如下:
- 多播服务器 1000Mbs、UDP、Mpeg2-TS 第 1 部分 (H.222) 流式传输直播电视频道。
- 四核 1.5Ghz Android 4.2.2 GLES 2.0 渲染器。
- FFMpeg 库。
- 在 Windows 8.1 上运行的 Eclipse Kepler、Android SDK/NDK 等。
- 输出屏幕 1920 x 1080,我使用 2048 x 1024 的纹理,每秒帧数在 35 到 45 帧之间。
应用程序:
- 当媒体图像准备好时,渲染器线程连续运行并通过将片段上传到 gpu 来更新单个纹理。
- 媒体处理程序线程,从服务器/或本地存储下载和处理媒体。
- 视频线程,一个用于缓冲 UDP 数据包,另一个用于将数据包解码为帧。
我将 ffmpeg 连接到 UDP 流就好了,数据包正在被缓冲并且看起来解码得很好。数据包缓冲区很多,没有下/溢出。我面临的问题是它似乎正在分割帧(即每这么多帧中只播放 1 帧)。我知道我需要区分 I/P/B 帧,但目前,举起手来,我不知道。我什至尝试了一种黑客来检测 I 帧无济于事。另外,我只将帧渲染到不到屏幕的四分之一。所以我没有使用全屏解码。
解码后的帧也存储在单独的缓冲区中以消除页面撕裂。我也改变了缓冲区的数量,从 1 到 10 没有运气。
根据我对 OpenMax IL 的发现,它是否仅处理 MPeg2-TS 第 3 部分(H.264 和 AAC),但您可以使用自己的解码器。我知道您可以向其中添加自己的解码组件。值得我尝试这条路线还是应该继续使用ffmpeg?
帧解码器(只有渲染器会在准备好后转换和缩放帧) /* * 此函数将运行数据包并继续解码 * 直到帧首先准备好,或者没有数据包 */
while (packetsUsed[decCurrent])
{
hack_for_i_frame:
i = avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packets[decCurrent]);
packetsUsed[decCurrent] = 0; // finished with this one
i = packets[decCurrent].flags & 0x0001;
decCurrent++;
if (decCurrent >= MAXPACKETS) decCurrent = 0;
if (frameFinished)
{
ready_pFrame = pFrame;
frameReady = true; // notify renderer
frameCounter++;
if (frameCounter>=MAXFRAMES) frameCounter = 0;
pFrame = pFrames[frameCounter];
return 0;
}
else if (i)
goto hack_for_i_frame;
}
return 0;
数据包阅读器(作为 pthread 生成) void *mainPacketReader(void *voidptr) { int res;
while ( threadState == TS_RUNNING )
{
if (packetsUsed[prCurrent])
{
LOGE("Packet buffer overflow, dropping packet...");
av_read_frame( pFormatCtx, &packet );
}
else if ( av_read_frame( pFormatCtx, &packets[prCurrent] ) >= 0 )
{
if ( packets[prCurrent].stream_index == videoStream )
{
packetsUsed[prCurrent] = 1; // flag as used
prCurrent++;
if ( prCurrent >= MAXPACKETS )
{
prCurrent = 0;
}
}
// here check if the packet is audio and add to audio buffer
}
}
return NULL;
渲染器只是简单地这样做 // 在调用这个函数之前已经绑定了纹理
if ( frameReady == false ) return;
AVFrame *temp; // set to frame 'not' currently being decoded
temp = ready_pFrame;
sws_scale(sws_ctx,(uint8_t const* const *)temp->data,
temp->linesize, 0, pCodecCtx->height,
pFrameRGB->data, pFrameRGB->linesize);
glTexSubImage2D(GL_TEXTURE_2D, 0,
XPOS, YPOS, WID, HGT,
GL_RGBA, GL_UNSIGNED_BYTE, buffer);
frameReady = false;
过去,libvlc 也有音频同步问题,所以我决定使用 ffmpeg 并从头开始做所有的驴工作。
如果有人对如何停止视频播放的断断续续有任何指示(在 VLC 播放器中效果很好)或可能有另一条路线,我们将不胜感激。
编辑我删除了 I-frame 的 hack(完全没用)。将 sws_scale 函数从渲染器移至数据包解码器。我独自离开了 udp 数据包读取器线程。
与此同时,我还将数据包读取器线程和数据包解码器线程的优先级更改为实时。既然这样做了,我就不会丢弃大量丢弃的数据包。