mpeg2 ts android ffmpeg openmax

Установка выглядит следующим образом:

  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 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 в покое.

В то же время я также изменил приоритет потоков чтения пакетов и потоков декодера пакетов в режиме реального времени. С тех пор, как я это делаю, я не теряю кучу пропущенных пакетов.

0

Решение

(после окончательного выяснения, где была кнопка ответа)

Взлом 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;
}
0

Другие решения


По вопросам рекламы [email protected]