После многих недель попыток подключиться к моей домашней системе видеонаблюдения в моем проекте c ++ / Qt с использованием libav на моем raspberry pi (armv7) я могу корректно отображать свою камеру в течение некоторого времени (по крайней мере, 20 минут), почти не имея предупреждений NAL в консоль (но некоторые предупреждения о недопустимом блоке NAL). Однако, в конце концов, я просто начну видеть только серый экран и множество предупреждений NAL на консоли, и мне придется закрыть и снова открыть соединение, чтобы моя камера отображалась правильно. Я много раз искал в интернете, чтобы убедиться, что я правильно понимаю av_parser_parse2 и думаю, что да.
Я вставил ниже три свои основные функции в надежде, что кто-нибудь мне скажет — есть ли еще что-то для декодирования потока h264 с использованием libav, чем я сейчас понимаю?
Спасибо.
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 hereinbuf_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);
}
}
}}
}
Задача ещё не решена.
Других решений пока нет …