Установка выглядит следующим образом:
Приложение:
Я подключаю ffmpeg к потоку UDP просто отлично, и пакеты буферизуются и, казалось бы, прекрасно декодируются. Пакетных буферов достаточно, нет перегрузок. Проблема, с которой я сталкиваюсь, заключается в том, что она, похоже, разбивает кадры (т.е. воспроизводит только 1 из каждых стольких кадров). Я понимаю, что мне нужно различать кадры I / P / B, но в данный момент, подняв руки, я не понимаю. Я даже пытался взломать, чтобы обнаружить I кадры безрезультатно. Плюс, я рендеринг только кадры менее чем на четверть экрана. Так что я не использую полноэкранное декодирование.
Декодированные кадры также хранятся в отдельных буферах, чтобы вырезать разрывы страниц. Количество буферов я тоже изменил, с 1 на 10 без удачи.
Из того, что я нашел в OpenMax IL, он обрабатывает только MPeg2-TS Part 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-рамки (совершенно бесполезный). Переместите функцию sws_scale из средства визуализации в декодер пакетов. И я оставил поток чтения пакетов udp в покое.
В то же время я также изменил приоритет потоков чтения пакетов и потоков декодера пакетов в режиме реального времени. С тех пор, как я это делаю, я не теряю кучу пропущенных пакетов.
(после окончательного выяснения, где была кнопка ответа)
Взлом I-Frame был совершенно бесполезен, и чтобы сэкономить на перегрузке потока в рендере, 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;
}