Декодирование блоков NAL в ffmpeg с использованием C ++ - PullRequest
0 голосов
/ 10 февраля 2019

У меня есть рабочий код, который получает блоки NAL через RTP, используя JRTPLIB.Это сохраняет единицы NAL в файл, который я могу воспроизвести через VLC.

Я готов декодировать эти блоки NAL, используя ffmpeg.Я видел все потоки stackoverflow о блоках NAL и ffmpeg, и ни один из них не ответил точно, как это сделать.

Как я понимаю, RTP - это протокол, который может разбить блок NAL на более чем одинRTP пакет.Поэтому единицы NAL, которые я получаю, даже не завершены.Таким образом, я полагаю, что не могу передать их напрямую в ffmpeg.Я думаю, мне нужно как-то их накапливать, а затем отправлять в нужный формат в ffmpeg.

Взгляните на avcodec_decode_video2 функцию из библиотеки ffmpeg:

attribute_deprecated int avcodec_decode_video2  (   
    AVCodecContext *    avctx,
    AVFrame *   picture,
    int *   got_picture_ptr,
    const AVPacket *    avpkt 
)   

Вот чтосказано об avpkt:

avpkt: входной AVPacket, содержащий входной буфер.Вы можете создать такой пакет с помощью av_init_packet ()

Я думаю, есть способ превратить единицы NAL в AVPacket s.Я пытался найти что-то связанное с этим в документации, но не смог найти ничего полезного.

Я также читал этот урок: http://dranger.com/ffmpeg/tutorial01.html, но он говорит только о чтении из файлов, а ffmpeg делает некоторыеФоновая работа в конвертируемых кадрах в AVPacket с, поэтому я ничего не узнал об этой части.

ps: мой код записывает информацию VPS, SPS и PPS один раз в начале файла, а затем сохраняет только единицы NALпо порядку.

Итак: как декодировать единицы NAL с помощью ffmpeg?

ОБНОВЛЕНИЕ:

Вот код, который получает единицы NAL.Я попытался добавить 0x00000001 в начале каждого блока NAL.

const size_t BufSize = 98304;
uint8_t buf[4 + BufSize];//4 bytes for 0x00000001 at beggining
uint8_t* paddedBuf = buf + 4;
/* Adds the delimiters for a h264 bitstream*/
buf[0] = char(0x00);
buf[1] = char(0x00);
buf[2] = char(0x00);
buf[3] = char(0x01);
size_t size = 0;
size_t write_size = 0;

/* Get SPS, PPS, VPS manually start */
std::cout << "writing vps" << std::endl;

Client.SetObtainVpsSpsPpsPeriodly(false);
if(!Client.GetVPSNalu(paddedBuf, &size)) {
    if(write(fd, paddedBuf, size) < 0) {
        perror("write");
    }
} 
if(!Client.GetSPSNalu(paddedBuf, &size)) {
    if(write(fd, paddedBuf, size) < 0) {
        perror("write");
    }
} 
if(!Client.GetPPSNalu(paddedBuf, &size)) {
    if(write(fd, paddedBuf, size) < 0) {
        perror("write");
    }
} 
/* Get SPS, PPS, VPS manually end */


while(true) {
    if(!Client.GetMediaData("video", paddedBuf+write_size, &size, BufSize)) {
        if(ByeFromServerFlag) {
            printf("ByeFromServerFlag\n");
            break;
        }
        if(try_times > 5) {
            printf("try_times > 5\n");
            break;
        }
        try_times++;
        continue;
    }
    write_size += size;
    std::cout << "gonna decode frame" << std::endl;

    ffmpegDecoder->decodeFrame(paddedBuf,size);
    std::cout << "decoded frame" << std::endl;

Теперь функция decodeFrame, которая вызывает ошибку сегментации.Однако я даже не знаю, нормально ли то, что я делаю.

void  FfmpegDecoder::decodeFrame(uint8_t* frameBuffer, int frameLength)
{
    if (frameLength <= 0) return;

    int frameFinished = 0;

    AVPacket framePacket;
    av_init_packet(&framePacket);

    framePacket.size = frameLength;
    framePacket.data = frameBuffer;

    std::cout << "gonna decode video2" << std::endl;

    int ret = avcodec_decode_video2(m_pAVCodecContext, m_pAVFrame, &frameFinished, &framePacket); //GIVES SEGMENTATION FAULT HERE

Вот снимок этого кода и всего проекта , который можно скомпилировать, если вы перейдете в/dev и сделайте. /build, чтобы построить образ докера, затем ./run, чтобы ввести образ докера, затем вы просто делаете cmake . и make.Однако вы должны запускать бинарный файл вне docker с ~/orwell$ LD_LIBRARY_PATH=.:./jrtplib/src ./orwell_monitor, потому что внутри docker есть ошибка.

...