[Libav-user] Problem Encoding H264 Video
Marika Marszalkowski
marikaner at gmail.com
Tue Jul 23 10:54:38 CEST 2013
I should have added that oformat->video_codec is AV_CODEC_ID_H264, of
course.
Best,
Marika
On Mon, Jul 22, 2013 at 8:00 PM, Marika Marszalkowski
<marikaner at gmail.com>wrote:
> Hello everyone,
>
> I have been trying to create an encoded h264 Video from multiple images
> (QImage), but I can't really achieve this.
>
> This list is my last resort and I totally hope there is someone out there
> who can help me with this not as complicated problem. I am not sure what
> the exact problem is - the video is created, but it is kind of jumpy, so
> that an image is shown and it stays there for two second and then there is
> a very short sequence (like half a second) and it's not moving again. Also
> the first 40 encoded frames, return 0 (SUCCESS) but got_packet_ptr is 0.
>
> So this is how I create the video with its header:
>
> AVCodec *codec = avcodec_find_encoder(oformat->video_codec);
>
>
> m_codecContext = avcodec_alloc_context3(codec);
>
> m_codecContext->gop_size = 30;
>
> m_codecContext->sample_fmt = AV_SAMPLE_FMT_NONE;
>
> m_codecContext->bit_rate = width * height;
>
> m_codecContext->width = width;
>
> m_codecContext->height = height;
>
> m_codecContext->time_base = (AVRational){1,frameRate};
>
> m_codecContext->pix_fmt = AV_PIX_FMT_YUV420P;
>
>
> formatCtx = avformat_alloc_context();
>
> if(!formatCtx)
>
> {
>
> printf("Error allocating format context\n");
>
> }
>
> formatCtx->oformat = oformat;
>
> formatCtx->video_codec_id = oformat->video_codec;
>
> snprintf(formatCtx->filename, sizeof(formatCtx->filename), "%s", outputFileName.toStdString().c_str());
>
>
> AVStream *videoStream = av_new_stream(formatCtx, 0);
>
> if(!videoStream)
>
> {
>
> printf("Could not allocate stream\n");
>
> }
>
> videoStream->codec = m_codecContext;
>
>
> if(formatCtx->oformat->flags & AVFMT_GLOBALHEADER)
>
> {
>
> m_codecContext->flags |= CODEC_FLAG_GLOBAL_HEADER;
>
> }
>
>
> avcodec_open2(m_codecContext, codec, NULL);
>
> avio_open(&formatCtx->pb, outputFileName.toStdString().c_str(), AVIO_FLAG_WRITE);
>
> avformat_write_header(formatCtx, NULL);
>
>
>
> and this is how I add the frames:
>
>
>
> AVFrame *frame = avcodec_alloc_frame();
>
> int size = m_codecContext->width * m_codecContext->height;
>
> int numBytes = avpicture_get_size(m_codecContext->pix_fmt, m_codecContext->width, m_codecContext->height);
>
>
> QSharedPointer<BlendImage> img = imageData;
>
> uint8_t *outbuf = (uint8_t *)malloc(numBytes);
>
> uint8_t *picture_buf = (uint8_t *)av_malloc(numBytes);
>
> if (true)
>
> {
>
> int ret = av_image_fill_arrays(frame->data, frame->linesize, picture_buf, m_codecContext->pix_fmt, m_codecContext->width, m_codecContext->height, 1);
>
>
> frame->data[0] = picture_buf;
>
> frame->data[1] = frame->data[0] + size;
>
> frame->data[2] = frame->data[1] + size/4;
>
> frame->linesize[0] = m_codecContext->width;
>
> frame->linesize[1] = m_codecContext->width/2;
>
> frame->linesize[2] = m_codecContext->width/2;
>
>
> fflush(stdout);
>
> for (int y = 0; y < m_codecContext->height; y++)
>
> {
>
> for (int x = 0; x < m_codecContext->width; x++)
>
> {
>
> unsigned char b = img->bits()[(y * m_codecContext->width + x) * 4 + 0];
>
> unsigned char g = img->bits()[(y * m_codecContext->width + x) * 4 + 1];
>
> unsigned char r = img->bits()[(y * m_codecContext->width + x) * 4 + 2];
>
> unsigned char Y = (0.257 * r) + (0.504 * g) + (0.098 * b) + 16;
>
> frame->data[0][y * frame->linesize[0] + x] = Y;
>
>
> if (y % 2 == 0 && x % 2 == 0)
>
> {
>
> unsigned char V = (0.439 * r) - (0.368 * g) - (0.071 * b) + 128;
>
> unsigned char U = -(0.148 * r) - (0.291 * g) + (0.439 * b) + 128;
>
>
> frame->data[1][y/2 * frame->linesize[1] + x/2] = U;
>
> frame->data[2][y/2 * frame->linesize[2] + x/2] = V;
>
> }
>
> }
>
> }
>
> int pts = (1.0 / 30.0) * 9000.0 * frameIndex;
>
> frame->pts = pts;
>
>
> int got_packet_ptr;
>
> AVPacket packet;
>
> av_init_packet(&packet);
>
> packet.data = outbuf;
>
> packet.size = numBytes;
>
> packet.stream_index = formatCtx->streams[0]->index;
>
> packet.flags |= AV_PKT_FLAG_KEY;
>
> packet.pts = packet.dts = pts;
>
> m_codecContext->coded_frame->pts = pts;
>
>
> ret = avcodec_encode_video2(m_codecContext, &packet, frame, &got_packet_ptr);
>
>
> if (got_packet_ptr != 0)
>
> {
>
> m_codecContext->coded_frame->pts = pts;
>
>
> if (m_codecContext->coded_frame->pts != (0x8000000000000000LL))
>
> pts = av_rescale_q(m_codecContext->coded_frame->pts, m_codecContext->time_base, formatCtx->streams[0]->time_base);
>
> packet.pts = pts;
>
> if(m_codecContext->coded_frame->key_frame)
>
> {
>
> packet.flags |= AV_PKT_FLAG_KEY;
>
> }
>
>
> std::cout << "pts: " << packet.pts << ", dts: " << packet.dts << std::endl;
>
> av_interleaved_write_frame(formatCtx, &packet);
>
> av_free_packet(&packet);
>
> }
>
> }
>
> free(picture_buf);
>
> free(outbuf);
>
> av_free(frame);
>
>
>
> and of course in the end:
>
>
> av_write_trailer(formatCtx);
>
> fclose(m_file);
>
> avcodec_close(m_codecContext);
>
> av_free(m_codecContext);
>
>
>
> I think this has something to do with the PTS/DTS values. PTS values start at 120 (as the first 40 frames are omitted) and are increased by 3 ((1.0 / 30.0) * 9000.0 * frameIndex) and the DTS values start at -6 also being increased by 3 per frame. But it might also be the settings or anything else. I feel like I have tried everything I was able to find on the internet and it's still wrong. I am desperate, help would be soooo appreciated!
>
>
> Cheers,
>
> Marika
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://ffmpeg.org/pipermail/libav-user/attachments/20130723/05ea40a3/attachment.html>
More information about the Libav-user
mailing list