【问题标题】:mpeg2 ts android ffmpeg openmaxmpeg2 ts android ffmpeg openmax
【发布时间】:2023-04-08 14:13:01
【问题描述】:

设置如下:

  1. 多播服务器 1000Mbs、UDP、Mpeg2-TS 第 1 部分 (H.222) 流式传输直播电视频道。
  2. 四核 1.5Ghz Android 4.2.2 GLES 2.0 渲染器。
  3. FFMpeg 库。
  4. Eclipse Kepler、Android SDK/NDK 等在 Windows 8.1 上运行。
  5. 输出屏幕 1920 x 1080,我使用的纹理为 2048 x 1024,每秒帧数在 35 到 45 之间。

应用程序:

  1. 渲染器线程持续运行,并在媒体图像准备就绪时通过将片段上传到 GPU 来更新单个纹理。
  2. 媒体处理程序线程,从服务器/或本地存储下载和处理媒体。
  3. 视频线程,一个用于缓冲 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 生成) 无效 *mainPacketReader(无效 *voidptr) { 整数;

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 数据包读取器线程。

与此同时,我还将数据包读取器线程和数据包解码器线程的优先级更改为实时。自从这样做后,我就不会丢弃大量丢弃的数据包。

【问题讨论】:

  • 现在全部修复。帧完成后,我将 sws_scale 函数移到帧解码器中,并删除了愚蠢的 I 帧 hack,现在我正在让 ts 流全速播放 (29fps)。
  • 您可以发布自己问题的答案并接受它

标签: android c++ ffmpeg mpeg2-ts openmax


【解决方案1】:

(在终于弄清楚答案按钮在哪里之后)

I-Frame hack 完全没用,为了节省渲染器中的线程过载,将 sws_scale 移到解码器线程中。

我还通过完全摆脱 sws_scale 并将每个单独的 YUV 帧上传到 gpu 并使用片段着色器转换为 rgb 来继续前进。

任何对将 YUV 转换为 RGB 的着色器感兴趣的人都在这里,非常简单:

顶点着色器

attribute vec4 qt_Vertex;
attribute vec2 qt_InUVCoords;
attribute vec4 qt_InColor;
uniform mat4 qt_OrthoMatrix;

varying vec2 qt_TexCoord0;
varying vec4 qt_OutColor;

void main(void)
{
    gl_Position = qt_OrthoMatrix * qt_Vertex;
    qt_TexCoord0 = qt_InUVCoords;
    qt_OutColor = qt_InColor;
}

片段着色器:

precision mediump float;

uniform sampler2D qt_TextureY;
uniform sampler2D qt_TextureU;
uniform sampler2D qt_TextureV;

varying vec4 qt_OutColor;

varying vec2 qt_TexCoord0;

const float num1 = 1.403;   // line 1

const float num2 = 0.344;   // line 2
const float num3 = 0.714;

const float num4 = 1.770;   // line 3
const float num5 = 1.0;

const float half1 = 0.5;

void main(void)
{
    float y = texture2D(qt_TextureY, qt_TexCoord0).r;
    float u = texture2D(qt_TextureU, qt_TexCoord0).r - half1;
    float v = texture2D(qt_TextureV, qt_TexCoord0).r - half1;

    gl_FragColor = vec4( y + num1 * v,
                         y - num2 * u - num3 * v,
                         y + num4 * u, num5) * qt_OutColor;
}

【讨论】:

    猜你喜欢
    • 2012-06-05
    • 2014-10-28
    • 1970-01-01
    • 1970-01-01
    • 2012-03-06
    • 2015-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多