2015-06-05 7 views
5

मुझे वर्तमान में एक mp4 कंटेनर में कच्चे H264 नाल पैकेट को समाहित करने का प्रयास करने में समस्याएं हैं। हालांकि उन्हें डिस्क पर लिखने के बजाय, मैं परिणाम स्मृति में संग्रहीत करना चाहता हूं। मैंने इस दृष्टिकोण का पालन किया Raw H264 frames in mpegts container using libavcodec लेकिन अभी तक सफल नहीं हुआ है।एफएफएमपीईजी I/O आउटपुट बफर

सबसे पहले, क्या यह स्मृति को लिखने का सही तरीका है? मेरे हेडर

struct IOOutput { 
    uint8_t* outBuffer; 
    int bytesSet; 
}; 

जहां मैं बफर और बाइटसेट शुरू करता हूं, में एक छोटी सी संरचना है। मैं तो प्रारंभ मेरी AVIOContext चर

AVIOContext* pIOCtx = avio_alloc_context(pBuffer, iBufSize, 1, outptr, NULL, write_packet, NULL); 

जहां outptr IOOutput उत्पादन के लिए एक शून्य सूचक है, और write_packet निम्नलिखित

int write_packet (void *opaque, uint8_t *buf, int buf_size) { 
    IOOutput* out = reinterpret_cast<IOOutput*>(opaque); 
    memcpy(out->outBuffer+out->bytesSet, buf, buf_size); 
    out->bytesSet+=buf_size; 
    return buf_size; 
} 

मैं तो मेरे AVFormatContext पर

fc->pb = pIOCtx; 
fc->flags = AVFMT_FLAG_CUSTOM_IO; 

सेट की तरह दिखता है * एफसी चर।

फिर, जब भी मैं एनएएल पैकेट मैं एक फ्रेम से है सांकेतिक शब्दों में बदलना है, मैं उन्हें AVFormatContext को av_interleaved_write_frame के माध्यम से लिख सकते हैं और उसके बाद के माध्यम से

void getBufferContent(char* buffer) { 
    memcpy(buffer, output.outBuffer, output.bytesSet); 
    output.bytesSet=0; 
} 

mp4 सामग्री प्राप्त है और इस तरह के दौरान चर bytesSet रीसेट, तो अगले लेखन ऑपरेशन बाइट बफर की शुरुआत में डाला जाएगा। क्या ऐसा करने के लिए इससे अच्छा तरीका है? क्या यह वास्तव में ऐसा करने का एक वैध तरीका है? क्या पैफ जोड़ने के लिए एफएफएमपीईजी कोई रीडिंग ऑपरेशन करता है अगर मैं केवल av_interleaved_write_frame और avformat_write_header को कॉल करता हूं?

अग्रिम में बहुत बहुत धन्यवाद! मैं की तरह

int frame_size = x264_encoder_encode(obj->mEncoder, &obj->nals, &obj->i_nals, obj->pic_in, obj->pic_out); 
int total_size=0; 

for(int i=0; i<obj->i_nals;i++) 
    { 
     if (!obj->fc) { 
      obj->create(obj->nals[i].p_payload, obj->nals[i].i_payload); 
     } 

     if (obj->fc) { 
      obj->write_frame(obj->nals[i].p_payload, obj->nals[i].i_payload); 
     } 
    } 

// Here I get the output values 
int currentBufferSize = obj->output.bytesSet; 
char* mem = new char[currentBufferSize]; 
obj->getBufferContent(mem); 

और बना सकते हैं और लिखने कार्यों इस

int create(void *p, int len) { 

    AVOutputFormat *of = av_guess_format("mp4", 0, 0); 

    fc = avformat_alloc_context(); 

    // Add video stream 
    AVStream *pst = av_new_stream(fc, 0); 
    vi = pst->index; 

    void* outptr = (void*) &output; 

// Create Buffer 
    pIOCtx = avio_alloc_context(pBuffer, iBufSize, 1, outptr, NULL, write_packet, NULL); 

    fc->oformat = of; 
    fc->pb = pIOCtx; 
    fc->flags = AVFMT_FLAG_CUSTOM_IO; 

    pcc = pst->codec; 

    AVCodec c= {0}; 
    c.type= AVMEDIA_TYPE_VIDEO; 

    avcodec_get_context_defaults3(pcc, &c); 
    pcc->codec_type = AVMEDIA_TYPE_VIDEO; 

    pcc->codec_id = codec_id; 
    pcc->bit_rate = br; 
    pcc->width = w; 
    pcc->height = h; 
    pcc->time_base.num = 1; 
    pcc->time_base.den = fps; 
} 

void write_frame(const void* p, int len) { 

    AVStream *pst = fc->streams[ vi ]; 

    // Init packet 
    AVPacket pkt; 
    av_init_packet(&pkt); 
    pkt.flags |= (0 >= getVopType(p, len)) ? AV_PKT_FLAG_KEY : 0; 
    pkt.stream_index = pst->index; 
    pkt.data = (uint8_t*)p; 
    pkt.size = len; 

    pkt.dts = AV_NOPTS_VALUE; 
    pkt.pts = AV_NOPTS_VALUE; 

    av_interleaved_write_frame(fc, &pkt); 

} 
+0

आपको इस एफएफएमपीईजी पैच को देखने में रुचि हो सकती है: https://ffmpeg.org/pipermail/ffmpeg-devel/2014-November/164996.html हालांकि मुझे वास्तविक "डॉक्टर/उदाहरण/avio_writing.c "एफएफएमपीजी के गिट में ... – Gediminas

उत्तर

3
की तरह लग रहे कुछ है मेरे एनकोड समारोह में -

संपादित

यहाँ muxing प्रक्रिया के बारे में कोड है

AVFormatContext.pb दस्तावेज़ीकरण देखें। आपने इसे सही तरीके से सेट किया है, लेकिन आपको AVFormatContext.flags को स्पर्श नहीं करना चाहिए। साथ ही, सुनिश्चित करें कि आप avformat_write_header() को कॉल करने से पहले इसे सेट करते हैं।

जब आप कहते हैं कि "यह काम नहीं करता है", वास्तव में क्या काम नहीं करता है? क्या कॉलबैक नहीं बुलाया गया है? क्या इसमें डेटा अपेक्षित प्रकार/प्रारूप का नहीं है? कुछ और? यदि आप जो करना चाहते हैं वह कच्चे नाल पैकेट लिखना है, तो आप सीधे एन्कोडर (एवीपैकेट में) से एन्कोडेड डेटा ले सकते हैं, यह कच्चा नाल डेटा है। यदि आप सीधे libx264 की एपीआई का उपयोग करते हैं, तो यह आपको प्रत्येक नाल को व्यक्तिगत रूप से भी देता है ताकि आपको इसे पार्स करने की आवश्यकता न हो।

+0

आपकी प्रतिक्रिया के लिए बहुत बहुत धन्यवाद! तो मुझे AVFMT_FLAG_CUSTOM_IO मैन्युअल रूप से सेट करने की आवश्यकता नहीं है, सही?अब तक मुझे एक mp4 कंटेनर में नाल पैकेट एन्कोडिंग में सफलता नहीं मिली है, और मैंने सोचा कि शायद डेटा बफर में सही ढंग से लिखा नहीं गया है - और मुझे नहीं पता था कि यह जाने का तरीका है या नहीं कार्य को पूरा करने के लिए AVFream जैसे कुछ FFMPEG क्लास का उपयोग कर सकते हैं। अभी, मैं एक एवीपैकेट बनाता हूं, इसे शुरू करता हूं, सभी नाल को स्मृति में कॉपी करता हूं, इसे पैकेट पर असाइन करता हूं, और फिर av_interleaved_write_frame का उपयोग करता हूं। हालांकि यह काम नहीं कर रहा है। – peacer212

+0

यह काम करना चाहिए, इसलिए मुझे आपके अन्य कोड के बारे में आश्चर्य है। क्या आप उस कोड को दिखा सकते हैं जो कच्चे नालों को AVPackets में लपेटता है और उन्हें लिखता है? साथ ही, क्या आप कुछ डायग्नोस्टिक्स दिखा सकते हैं जैसे आपकी लेखन_पैकेट() कॉलबैक कितनी बार कॉल की जाती है, और दिए गए नाल लम्बाई के लिए इन कॉलबैक में buf_size के लिए सामान्य मान क्या हैं? –

+0

हाय, मैंने मूल पोस्ट संपादित किया और मक्सिंग भाग जोड़ा - आपकी मदद के लिए बहुत बहुत धन्यवाद! परीक्षण के थोड़ी देर बाद मुझे पता चला कि मुझे निम्न त्रुटि मिलती है: [mp4 @ 0x101076c00] muxer गैर तलाशने योग्य आउटपुट का समर्थन नहीं करता है! जिसका अर्थ है कि मुझे avio_alloc_context में तलाश फ़ंक्शन को कार्यान्वित करने की आवश्यकता है, सही? अगर मैं लगातार अपने बफर को ओवरराइट करता हूं तो मैं यह कैसे कर सकता हूं? – peacer212

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