我通过live555打开本地的SDP文件,然后通过这个文件为我的IP Camera建立个传输会话,已经成功,DummySink中的 afterGettingFrame这回调函数能不间断的调用,我直接把表示每帧fReceiveBuffer和frameSize传入了FFMPEG的解码器,但是 avcodec_decode_video2总是调用失败。我查看了一些帧的fReceiveBuffer,里面没有插入相关的SPS和PPS,没有0x00000001的标记,因为解码器要解码IDR帧必须通过SPS和PPS正确初始化,才能够解码,我的SDP文件里面有PPS和SPS的Base64编码,我需要怎么处理这个SPS和PPS才能正确初始化解码器?不然解码器是无法解码H264的。FFMPEG中的AVCodecContext中的extradata也没有相关文档描述怎么用,听说是用来存放SPS和PPS的,如果是,该怎么用?我需要把SPS和PPS的Base64的编码解出来再传入吗?还是直接就传入(插入)SPS和PPS的Base64版本?
以下是我的代码片断:
void afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime, unsigned durationInMicroseconds) { if (fStreamId != NULL) envir() << "Stream \"" << fStreamId << "\"; "; envir() << fSubsession.mediumName() << "/" << fSubsession.codecName() << ":\tReceived " << frameSize << " bytes"; if (numTruncatedBytes > 0) envir() << " (with " << numTruncatedBytes << " bytes truncated)"; char uSecsStr[6 + 1]; // used to output the 'microseconds' part of the presentation time sprintf_s(uSecsStr, 7, "%06u", (unsigned)presentationTime.tv_usec); envir() << ".\tPresentation time: " << (int)presentationTime.tv_sec << "." << uSecsStr; gffmpeg->decodeFrame(fReceiveBuffer, frameSize, presentationTime.tv_sec, presentationTime.tv_usec); // Then continue, to request the next frame of data: continuePlaying(); }
void QFFmpeg::decodeFrame(uint8_t* frameBuffer, int frameLength, long second, long microSecond) { if (frameLength <= 0) return; int frameFinished = 0; AVPacket framePacket; av_init_packet(&framePacket); framePacket.size = frameLength; framePacket.data = frameBuffer; int ret = avcodec_decode_video2(m_pAVCodecContext, m_pAVFrame, &frameFinished, &framePacket); if (ret < 0) { qDebug() << "Decode error"; return; } if (frameFinished) { m_playMutex.lock(); m_videoWidth = m_pAVFrame->width; m_videoHeight = m_pAVFrame->height; m_pSwsContext = sws_getContext(m_videoWidth, m_videoHeight, AVPixelFormat::AV_PIX_FMT_YUV420P, m_videoWidth, m_videoHeight, AVPixelFormat::AV_PIX_FMT_RGB24, SWS_BICUBIC, 0, 0, 0); sws_scale(m_pSwsContext, (const uint8_t* const *)m_pAVFrame->data, m_pAVFrame->linesize, 0, m_videoHeight, m_pAVPicture.data, m_pAVPicture.linesize); char timestamp[100]; sprintf_s(timestamp, 100, "Time Stamp is: %ld.%ld", second, microSecond); //发送获取一帧图像信号 QImage image(m_pAVPicture.data[0], m_videoWidth, m_videoHeight, QImage::Format_RGB888); QPainter pen(&image); pen.setPen(Qt::white); pen.setFont(QFont("Times", 10, QFont::Bold)); pen.drawText(image.rect(), Qt::AlignBottom, QString(timestamp)); emit GetImage(image); m_playMutex.unlock(); } }
以下是解码器的初始化,都能正确返回
bool QFFmpeg::Init() { m_pAVCodec = avcodec_find_decoder(AV_CODEC_ID_H264); if (!m_pAVCodec) return false; m_pAVCodecContext = avcodec_alloc_context3(m_pAVCodec); if (avcodec_open2(m_pAVCodecContext, m_pAVCodec, NULL) < 0) return false; return true; }
先理解关键知识点,不知道有没有误导,H264的帧是以 NAL单元的单位来传送的,一个NAL单元包含一帧(I帧 或 P帧 或 B帧),这三种类型的帧可以百度。所谓的NAL单元就是去掉SPS、PPS的视频帧, I帧是关键帧,所有的解析都需要靠它,两个I帧之间被称为视频序列,I帧头部需要加入SPS和PPS,这两个之间需要0x00000001来分割, 0x00 0x00 0x00 0x01 + SPS的Base64解码形式 + 0x00 0x00 0x00 0x01 + PPS的解码形式 + 0x00 0x00 0x00 0x01 视频帧(IDR帧) 这样组成的一个buffer,FFMPEG的H264解码器才能成功解码。
问题已经解决,忘记结贴了。解决方案参考https://github.com/AlexiaChen/RtspMonitor
你好,我也遇到这个问题了,不知道您解决了吗,可以交流一下吗