2015-06-05 7 views
5

Attualmente sto riscontrando problemi nel tentativo di incapsulare pacchetti nali H264 raw in un contenitore mp4. Invece di scriverli su disco, voglio avere il risultato archiviato in memoria. Ho seguito questo approccio Raw H264 frames in mpegts container using libavcodec ma finora non ho avuto successo.Buffer di uscita I/O FFMPEG

Innanzitutto, è questo il modo giusto per scrivere in memoria? Ho una piccola struttura nella mia intestazione

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

dove inizializzo il buffer e il byte. Ho poi inizializzo mia AVIOContext variabile

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

dove outptr è un puntatore nullo per l'output IOOutput, e write_packet aspetto simile al seguente

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; 
} 

Ho quindi impostare

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

sul mio AVFormatContext * variabile fc.

Poi, quando ho codificare i pacchetti nali ho da un telaio, li scrittura sul AVFormatContext via av_interleaved_write_frame e quindi ottenere il contenuto mp4 tramite

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

e quindi ripristinare il bytesSet variabile, quindi durante la i byte di operazione successiva di scrittura verranno inseriti all'inizio del buffer. C'è un modo migliore per farlo? È davvero un modo valido per farlo? FFMPEG esegue qualche operazione di lettura se richiamo solo av_interleaved_write_frame e avformat_write_header per aggiungere pacchetti?

Grazie mille in anticipo!

EDIT

Ecco il codice per quanto riguarda il processo di multiplex - nella mia funzione di codifica ho qualcosa di simile

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); 

E le funzioni di creare e scrivere simile a questa

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

Potreste essere interessati a dare un'occhiata a questa patch FFmpeg: https://ffmpeg.org/pipermail/ffmpeg-devel/2014-November/164996.html Anche se non riesco a trovare il doc vero e proprio"/ esempi/avio_writing.c "nel gif di FFmpeg ... – Gediminas

risposta

3

Vedere la documentazione AVFormatContext.pb. Si imposta correttamente, ma non si dovrebbe toccare AVFormatContext.flags. Inoltre, assicurati di averlo impostato prima di chiamare avformat_write_header().

Quando si dice "non funziona", cosa non funziona esattamente? La richiamata non è invocata? I dati in esso contenuti non sono del tipo/formato previsto? Qualcos'altro? Se tutto ciò che si vuole fare è scrivere pacchetti raw nal, allora si possono semplicemente prendere i dati codificati direttamente dal codificatore (nell'AVPacket), cioè i dati nali non elaborati. Se usi direttamente l'API di libx264, ti dà persino ogni singolo nal in modo da non doverlo analizzare.

+0

Grazie mille per la tua risposta! Quindi non ho bisogno di impostare manualmente AVFMT_FLAG_CUSTOM_IO, corretto?Finora non ho avuto successo nella codifica dei pacchetti nal in un contenitore mp4, e ho pensato che forse i dati non sono stati scritti correttamente nel buffer - e non sapevo se questa fosse la strada da percorrere, o se io potrebbe utilizzare alcune classi FFMPEG come AVStream per eseguire l'attività. Al momento, creo un AVPacket, lo inizializzo, copio tutti i nal in memoria, lo assegno al pacchetto e quindi utilizzo av_interleaved_write_frame. Questo non sembra funzionare comunque. – peacer212

+0

Dovrebbe funzionare, quindi mi chiedo del tuo altro codice. Puoi mostrare il codice che avvolge i nali grezzi in AVPacket e li scrive? Inoltre, puoi mostrare alcuni strumenti diagnostici come la frequenza con cui è stato richiamato il callback write_packet() e quali sono i valori tipici per buf_size in questi callback per le lunghezze nue date? –

+0

Ciao, ho modificato il post originale e aggiunto la parte di muxing - grazie mille per il tuo aiuto! Dopo un po 'di test ho scoperto che ottengo il seguente errore: [mp4 @ 0x101076c00] muxer non supporta l'output non ricercabile! Il che significa che ho bisogno di implementare la funzione seek in avio_alloc_context, corretto? Come posso farlo se sovrascrivo costantemente il mio buffer? – peacer212

Problemi correlati