<br />I'm having trouble reading video packets after seeking within a video. I seem to have no problem reading reading video packets if I just start at the begining of the stream and scan every packet in order, but the below code is not working.<br /><br />I'm calling this from a timer that I want to grab the video frame closest to the time timeMs. av_read_frame() is returning the value -541478725 the third time it gets called, which stops me from receiving and decoding the frame most of the time:<br /><br /><br /> QImage FfmpegMediaSource::getVideoFrame(int timeMs)<br /> {<br /> AVPacket packet;<br /><br /> //Seek to our goal time<br /> avcodec_flush_buffers(pCodecCtx);<br /> int64_t targetPts = timeMs * 1000;<br /> targetPts = av_rescale_q(targetPts, AV_TIME_BASE_Q,<br /> pFormatCtx->streams[videoStream]->time_base);<br /><br /> int err = av_seek_frame(pFormatCtx, videoStream, targetPts, AVSEEK_FLAG_BACKWARD);<br /><br /> qDebug() << "targetPts " << targetPts;<br /><br /> //Read frame<br /> while (true)<br /> {<br /> err = av_read_frame(pFormatCtx, &packet);<br /> if (err == AVERROR(EAGAIN))<br /> {<br /> qDebug() << "Error reading packet: " << err;<br /> continue;<br /> }<br /> else if (err != 0)<br /> {<br /> qDebug() << "Error reading packet: " << err;<br /> break;<br /> }<br /><br /> if (packet.stream_index != videoStream)<br /> continue;<br /><br /><br /> err = avcodec_send_packet(pCodecCtx, &packet);<br /> if (err == AVERROR(EAGAIN))<br /> {<br /> continue;<br /> }<br /> else if (err != 0)<br /> {<br /> qDebug() << "Error sending packet: " << err;<br /> }<br /><br /> int64_t packetPts = packet.pts == AV_NOPTS_VALUE ? packet.dts : packet.pts;<br /><br /> qDebug() << "packet Pts " << packetPts << " flags " << packet.flags;<br /><br /> if (packetPts >= targetPts)<br /> {<br /> if (targetPts != 0)<br /> {<br /> int j = 9;<br /> }<br /><br /> QImage img = readVideoFrame();<br /> return img;<br /> }<br /><br /> }<br /><br /> return QImage();<br /> }<br /><br /> QImage FfmpegMediaSource::readVideoFrame()<br /> {<br /> int err = 0;<br /> while (err >= 0)<br /> {<br /> err = avcodec_receive_frame(pCodecCtx, pFrame);<br /> if (err == AVERROR(EAGAIN) || err == AVERROR_EOF)<br /> {<br /> qDebug() << "Error decoding packet: " << err;<br /> break;<br /> }<br /> if (err < 0)<br /> {<br /> qDebug() << "Error decoding packet: " << err;<br /> break;<br /> }<br /><br /> // Convert the image from its native format to RGB<br /> sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,<br /> pFrame->linesize, 0, pCodecCtx->height,<br /> pFrameRGB->data, pFrameRGB->linesize);<br /><br /> // Save the frame to disk<br /> if (_videoFrame.isNull() || _videoFrame.width() != pCodecCtx->width || _videoFrame.height() != pCodecCtx->height)<br /> {<br /> _videoFrame = QImage(pCodecCtx->width, pCodecCtx->height, QImage::Format_RGB32);<br /> _videoFrame.fill(Qt::white);<br /> }<br /><br /> for (int j = 0; j < pCodecCtx->height; ++j)<br /> {<br /> memcpy(_videoFrame.scanLine(j), pFrameRGB->data[0] + j * pFrameRGB->linesize[0], pCodecCtx->width * 4);<br /> }<br /><br /> if (_dumpNextFrame)<br /> {<br /> _videoFrame.save("d:\\tmp\\videoFrameDump.png");<br /> _dumpNextFrame = false;<br /> }<br /><br /> return _videoFrame;<br /> }<br /><br /> return QImage();<br /> }<br /><br /><br /><br />On the other hand, the below code which is very similar is working. I run it just after opening the file and it saves the first hundred frames to disk correctly:<br /><br /> void FfmpegMediaSource::buildIndex()<br /> {<br /> //Scan through packets to find what's where<br /> AVPacket* packet;<br /> packet = av_packet_alloc();<br /><br /> int frame = 0;<br /><br /> int64_t keyPts = 0;<br /> while (av_read_frame(pFormatCtx, packet) >= 0)<br /> {<br /> int64_t pts = packet->pts == AV_NOPTS_VALUE ? packet->dts : packet->pts;<br /><br /> // Is this a packet from the video stream?<br /> if (packet->stream_index == videoStream)<br /> {<br /> AVRational time_base = pFormatCtx->streams[videoStream]->time_base;<br /> int presentationTime = pts * av_q2d(time_base) * 1000;<br /><br /> VideoFrame* videoFrame = new VideoFrame();<br /><br /> if (packet->flags & AV_PKT_FLAG_KEY)<br /> {<br /> _videoKeyPst.append(pts);<br /> videoFrame->isKeyframe = true;<br /> keyPts = pts;<br /> }<br /> else<br /> videoFrame->isKeyframe = false;<br /><br /> videoFrame->pts = pts;<br /> videoFrame->keyPts = keyPts;<br /> _videoFrameList.append(videoFrame);<br /> _videoPtsMap[pts] = videoFrame;<br /><br /><br /> if (frame < 100)<br /> {<br /> int err = avcodec_send_packet(pCodecCtx, packet);<br /> if (err != 0)<br /> {<br /> qDebug() << "Error sendsing packet: " << err;<br /> }<br /><br /> QImage img = readVideoFrame();<br /> if (!img.isNull())<br /> {<br /> QString filename = "d:\\tmp\\ffmpegRick2\\videoDump_";<br /> filename += QString::number(frame) + ".png";<br /> qDebug() << "Dumping " << filename;<br /> img.save(filename);<br /> }<br /> }<br /> frame++;<br /><br /> }<br /> else if (packet->stream_index == audioStream)<br /> {<br /> ...<br /> }<br /> }<br /><br /> av_packet_free(&packet);<br /><br /> av_seek_frame(pFormatCtx, videoStream, 0, 0);<br /> }<br /><br /><br /><br />Any idea what I'm doing wrong?<br /><br /><br /><br />
<div>
<pre>---
http://www.kitfox.com</pre>
</div>