在我的c ++ / Qt项目中尝试使用我的覆盆子pi(armv7)上的libav连接到我的家庭中央电视台几周后,我能够正确显示我的相机一段时间(至少20分钟)几乎没有任何NAL控制台中的警告(但有关无效NAL单元的警告)。但是,最终我只是开始在控制台中看到一个灰色的屏幕和许多NAL警告,我必须关闭并重新打开连接才能正确显示我的相机。我已多次搜索互联网,以确保我正确理解av_parser_parse2,我想我是。
我已经粘贴了下面的3个主要功能,希望有人能告诉我 - 使用libav解码h264流是否比我目前理解的更多?
谢谢。
void MainWindow::playStreamToScreen(MainWindow* app)
{
avcodec_register_all();
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!codec) {
qDebug() << "codec not found\n";
return;
}
c = avcodec_alloc_context3(codec);
/* if(codec->capabilities & CODEC_CAP_TRUNCATED)
c->flags |= CODEC_FLAG_TRUNCATED;
if(codec->capabilities & CODEC_FLAG2_CHUNKS)
c->flags |= CODEC_FLAG2_CHUNKS;*//* We may send incomplete frames */
picture = av_frame_alloc();
pFrameRGB=av_frame_alloc();
int numBytes=avpicture_get_size(pix_fmt_dst, myWidth, myHeight);
buffer= (uint8_t*)malloc(numBytes);
if(avpicture_fill((AVPicture *)pFrameRGB, buffer, pix_fmt_dst,
myWidth, myHeight) < 0)
{
qDebug() << "failed fill picture";
}
if (avcodec_open2(c, codec, NULL) < 0) {
qDebug() << "could not open codec\n";
return;
}
frame = 0;
if(parser == NULL)parser = av_parser_init(AV_CODEC_ID_H264);
if(parser == NULL)
{
qDebug() << "after init parser is null";
return;
}
parser->flags |= PARSER_FLAG_ONCE;
struct timeval t;
float inv_fps2;// = 4;
int ii = 0;
inv_fps2 = 1e6/9.98;//av_q2d(c->time_base);
qDebug() << "before timebase";
c->time_base = (AVRational){1,10};
c->bit_rate = 251000;
c->width = 352;
c->height = 288;
c->pix_fmt = AV_PIX_FMT_YUV420P;
if(img_convert_ctx == NULL)
{
img_convert_ctx = sws_getCachedContext ( img_convert_ctx, c->width, c->height,
AV_PIX_FMT_YUV420P, myWidth, myHeight, AV_PIX_FMT_RGB555,
SWS_LANCZOS | SWS_ACCURATE_RND , NULL, NULL, NULL );
}
running = true;
int retval;
gettimeofday(&t, 0);
}
void MainWindow::display_frame(AVCodecContext* cc, AVFrame *frame, SwsContext* img_convert_ctx, MainWindow* app)
{
sws_scale ( img_convert_ctx, frame->data, frame->linesize, 0,
288, pFrameRGB->data, pFrameRGB->linesize );
app->currentImage = QImage(pFrameRGB->data[0], app->myWidth, app->myHeight, pFrameRGB->linesize[0], QImage::Format_RGB555) .copy();// - See more at: http://www.mzan.com/article/30784549-best-simplest-way-to-display-ffmpeg-frames-in-qt5-solved.shtml#sthash.RvAFLQsc.dpuf
QImage img2 = app->currentImage.scaled(app->width(), app->height(), Qt::KeepAspectRatio);
QMetaObject::invokeMethod(app->myLabel, "setImage", Qt::QueuedConnection, Q_ARG(QImage, img2));
app->myLabel->setFixedSize(app->width(), app->height());
}
void MainWindow::socketReadyRead()
{
if(connectingToLive && i == 0)
{
qDebug() << "starting live stream";
i++;
this->playStreamToScreen(this);
}
else if(connectingToLive && i > 0)
{
QByteArray temp;
int inbuf_start = 0;
int inbuf_len = 0;
temp.append(socket->readAll());//reads from network here
inbuf_len = temp.size();
inbuf_start = 0;
int out_size;
while (inbuf_len)
{
av_init_packet(&packet2);
packet2.data = 0;
packet2.size = 0;
len = av_parser_parse2(parser, c, &packet2.data, &packet2.size,
(uint8_t*)temp.constData()+ inbuf_start, inbuf_len,
AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
inbuf_start += len;
inbuf_len -= len;
if(packet2.size == 0 && len >= 0)
{
break;
}
else if(len)
{
retval = avcodec_decode_video2(c, picture, &got_picture, &packet2);
if (got_picture && retval > 0)
{
display_frame(c, picture, img_convert_ctx, this);
}
}
}
}
}