2013-07-23 5 views
6

मैं ffmpeg लाइब्रेरी का उपयोग कर छवियों से एक वीडियो बनाने की कोशिश कर रहा हूं। छवियों का आकार 1920x1080 है और इसे .mkv कंटेनर का उपयोग करके H.264 के साथ एन्कोड किया जाना चाहिए। मैं विभिन्न समस्याओं में आया हूं, सोच रहा हूं कि मैं समाधान के करीब आ रहा हूं, लेकिन यह मैं वास्तव में अटक गया हूं। मेरे द्वारा उपयोग की जाने वाली सेटिंग्स के साथ, मेरे वीडियो के पहले एक्स फ्रेम (लगभग 40, वीडियो और वीडियो के लिए उपयोग की जाने वाली छवियों के आधार पर) लगभग एन्कोड नहीं किए गए हैं। avcodec_encode_video2 कोई त्रुटि नहीं लौटाता है (वापसी मान 0 है) got_picture_ptr = 0. परिणाम एक ऐसा वीडियो है जो वास्तव में अपेक्षित दिखता है, लेकिन पहले सेकंड अजीब तरह से अजीब हैं।ffmpeg libav और libx264 का उपयोग कर छवियों से एक वीडियो बनाना?

तो यह है कि कैसे मैं वीडियो फ़ाइल बनाने है:

// m_codecContext is an instance variable of type AVCodecContext * 
// m_formatCtx is an instance variable of type AVFormatContext * 

// outputFileName is a valid filename ending with .mkv 
AVOutputFormat *oformat = av_guess_format(NULL, outputFileName, NULL); 
if (oformat == NULL) 
{ 
    oformat = av_guess_format("mpeg", NULL, NULL); 
} 

// oformat->video_codec is AV_CODEC_ID_H264 
AVCodec *codec = avcodec_find_encoder(oformat->video_codec); 

m_codecContext = avcodec_alloc_context3(codec); 
m_codecContext->codec_id = oformat->video_codec; 
m_codecContext->codec_type = AVMEDIA_TYPE_VIDEO; 
m_codecContext->gop_size = 30; 
m_codecContext->bit_rate = width * height * 4 
m_codecContext->width = width; 
m_codecContext->height = height; 
m_codecContext->time_base = (AVRational){1,frameRate}; 
m_codecContext->max_b_frames = 1; 
m_codecContext->pix_fmt = AV_PIX_FMT_YUV420P; 

m_formatCtx = avformat_alloc_context(); 
m_formatCtx->oformat = oformat; 
m_formatCtx->video_codec_id = oformat->video_codec; 

snprintf(m_formatCtx->filename, sizeof(m_formatCtx->filename), "%s", outputFileName); 

AVStream *videoStream = avformat_new_stream(m_formatCtx, codec); 
if(!videoStream) 
{ 
    printf("Could not allocate stream\n"); 
} 
videoStream->codec = m_codecContext; 

if(m_formatCtx->oformat->flags & AVFMT_GLOBALHEADER) 
{ 
    m_codecContext->flags |= CODEC_FLAG_GLOBAL_HEADER; 
} 

avcodec_open2(m_codecContext, codec, NULL) < 0); 
avio_open(&m_formatCtx->pb, outputFileName.toStdString().c_str(), AVIO_FLAG_WRITE); 
avformat_write_header(m_formatCtx, NULL); 

यह कैसे फ्रेम जोड़ रहे हैं है:

void VideoCreator::writeImageToVideo(const QSharedPointer<QImage> &img, int frameIndex) 
{ 
    AVFrame *frame = avcodec_alloc_frame(); 

    /* alloc image and output buffer */ 

    int size = m_codecContext->width * m_codecContext->height; 
    int numBytes = avpicture_get_size(m_codecContext->pix_fmt, m_codecContext->width, m_codecContext->height); 

    uint8_t *outbuf = (uint8_t *)malloc(numBytes); 
    uint8_t *picture_buf = (uint8_t *)av_malloc(numBytes); 

    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 = frameIndex;//(1.0/30.0) * 90.0 * frameIndex; 

    frame->pts = pts;//av_rescale_q(m_codecContext->coded_frame->pts, m_codecContext->time_base, formatCtx->streams[0]->time_base); //(1.0/30.0) * 90.0 * frameIndex; 

    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; // Set the time stamp 

     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); 
    printf("\n"); 
} 

और इस सफाई है:

int numBytes = avpicture_get_size(m_codecContext->pix_fmt, m_codecContext->width, m_codecContext->height); 
int got_packet_ptr = 1; 

int ret; 
//  for(; got_packet_ptr != 0; i++) 
while (got_packet_ptr) 
{ 
    uint8_t *outbuf = (uint8_t *)malloc(numBytes); 

    AVPacket packet; 
    av_init_packet(&packet); 
    packet.data = outbuf; 
    packet.size = numBytes; 

    ret = avcodec_encode_video2(m_codecContext, &packet, NULL, &got_packet_ptr); 
    if (got_packet_ptr) 
    { 
     av_interleaved_write_frame(m_formatCtx, &packet); 
    } 

    av_free_packet(&packet); 
    free(outbuf); 
} 

av_write_trailer(formatCtx); 

avcodec_close(m_codecContext); 
av_free(m_codecContext); 
printf("\n"); 

मुझे लगता है कि यह पीटीएस और डीटीएस मूल्यों से बंधे जा सकते हैं, लेकिन मैंने ई की कोशिश की है VERYTHING। फ्रेम सूचकांक सबसे अधिक समझ में आता है। छवियां सही हैं, मैं उन्हें बिना किसी समस्या के फाइलों में सहेज सकता हूं। मैं विचारों से बाहर चला रहा हूँ। इस किसी भी मदद की है

इस पर उत्पादन होता है: मैं अगर वहाँ कोई है जो मुझे की तुलना में बेहतर जानता था ...

चीयर्स, marikaner

अद्यतन था अविश्वसनीय रूप से आभारी होगा वीडियो एन्कोडिंग का अंत:

[libx264 @ 0x7fffc00028a0] frame I:19 Avg QP:14.24 size:312420 
[libx264 @ 0x7fffc00028a0] frame P:280 Avg QP:19.16 size:148867 
[libx264 @ 0x7fffc00028a0] frame B:181 Avg QP:21.31 size: 40540 
[libx264 @ 0x7fffc00028a0] consecutive B-frames: 24.6% 75.4% 
[libx264 @ 0x7fffc00028a0] mb I I16..4: 30.9% 45.5% 23.7% 
[libx264 @ 0x7fffc00028a0] mb P I16..4: 4.7% 9.1% 4.5% P16..4: 23.5% 16.6% 12.6% 0.0% 0.0% skip:28.9% 
[libx264 @ 0x7fffc00028a0] mb B I16..4: 0.6% 0.5% 0.3% B16..8: 26.7% 11.0% 5.5% direct: 3.9% skip:51.5% L0:39.4% L1:45.0% BI:15.6% 
[libx264 @ 0x7fffc00028a0] final ratefactor: 19.21 
[libx264 @ 0x7fffc00028a0] 8x8 transform intra:48.2% inter:47.3% 
[libx264 @ 0x7fffc00028a0] coded y,uvDC,uvAC intra: 54.9% 53.1% 30.4% inter: 25.4% 13.5% 4.2% 
[libx264 @ 0x7fffc00028a0] i16 v,h,dc,p: 41% 29% 11% 19% 
[libx264 @ 0x7fffc00028a0] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 16% 26% 31% 3% 4% 3% 7% 3% 6% 
[libx264 @ 0x7fffc00028a0] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 30% 26% 14% 4% 5% 4% 7% 4% 7% 
[libx264 @ 0x7fffc00028a0] i8c dc,h,v,p: 58% 26% 13% 3% 
[libx264 @ 0x7fffc00028a0] Weighted P-Frames: Y:17.1% UV:3.6% 
[libx264 @ 0x7fffc00028a0] ref P L0: 63.1% 21.4% 11.4% 4.1% 0.1%  
[libx264 @ 0x7fffc00028a0] ref B L0: 85.7% 14.3% 
[libx264 @ 0x7fffc00028a0] kb/s:27478.30 

उत्तर

2

लीब शायद शुरुआती फ्रेम की प्रसंस्करण में देरी कर रहा है। एक अच्छी प्रैक्टिस है कि आप सभी फ्रेमों को संसाधित करने के बाद किसी देरी वाले फ्रेम की जांच करें।

int i=NUMBER_OF_FRAMES_PREVIOUSLY_ENCODED 
for(; got_packet_ptr; i++) 
    ret = avcodec_encode_video2(m_codecContext, &packet, NULL, &got_packet_ptr); 
//Write the packets to a container after this. 

बिंदु फ्रेम के स्थान पर एक शून्य सूचक पारित एन्कोड करने की और जब तक पैकेट आप प्राप्त गैर खाली है ऐसा करने के लिए जारी रखने के लिए है: यह इस प्रकार किया जाता है। कोड उदाहरण के लिए this link देखें - "विलंबित फ्रेम प्राप्त करें" के अंतर्गत भाग।

एक आसान तरीका निर्धारित करने के लिए ख फ्रेम की संख्या होने के लिए 0.

m_codecContext->max_b_frames = 0; 

मुझे पता है कि अगर यह ठीक काम करता है चलो होगा।

इसके अलावा, आपने libx264 API का उपयोग नहीं किया है। आप एन्कोडिंग वीडियो के लिए libx264 एपीआई का उपयोग कर सकते हैं, उनके पास एक सरल और क्लीनर वाक्यविन्यास है। इसके अलावा यह आपको सेटिंग्स और बेहतर प्रदर्शन पर अधिक नियंत्रण प्रदान करता है।

एमकेवी कंटेनर में वीडियो स्ट्रीम लिखने के लिए, आपको अभी भी libav पुस्तकालयों का उपयोग करना होगा। हालांकि।

+0

अपना समय लेने के लिए बहुत बहुत धन्यवाद। दुर्भाग्यवश न तो बी फ्रेम की संख्या निर्धारित करना और न ही देरी वाले फ्रेम लिखना चाल चल रहा है। हालांकि स्पष्ट रूप से फ्रेम में देरी हो रही है, क्योंकि कार्यक्रम लूप में प्रवेश करता है। वीडियो वास्तव में कम अजीब लगता है, लेकिन अभी भी सही नहीं है। ऐसा लगता है कि 2 सेकंड के बाद एक छेद है जहां 2 सेकंड के दौरान केवल 2 छवियां दिखायी जाती हैं जैसे कि बीच में फ्रेम गायब थे। – marikaner

+0

क्या आप परिणामस्वरूप वीडियो में फ्रेम की संख्या और छवियों की कुल संख्या को एन्कोड करने के इच्छुक हैं? आप केवल av_interleaved_write() पर कॉल की संख्या देख सकते हैं (आपके अपडेट के अनुसार 480 होना चाहिए)। इसके अलावा, फ्रेम इंडेक्स गणना क्या है? –

+0

हां, छवियों की संख्या जो मैं एन्कोड करने के लिए इंडेंट कर रहा हूं 480 है। फ्रेम इंडेक्स केवल एक पूर्णांक है जो प्रत्येक फ्रेम के साथ 0 से 47 9 तक बढ़ाया जाता है। av_interleaved_write() को वास्तविक फ्रेम का उपयोग करके avcodec_encode_video2 के 442 बार और NULL का उपयोग करके avcodec_encode_video2 के 38 बार बाद कहा जाता है। – marikaner

संबंधित मुद्दे