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