У меня есть рабочий код, который получает блоки 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 есть ошибка.