2012-12-12 18 views
7

Supose Ho un intero file video in memoria e voglio usare libav per decodificare l'intero frame. Come dovrei farlo? Il punto è che posso farlo leggendo direttamente da un file usando la funzione avformat_open_input() ma ho bisogno di farlo da un file che è memorizzato in memoria.Decodifica un file video dalla memoria usando libav

mio AVIOContext implementazione:

class AVIOMemContext 
{ 

public: 

    AVIOMemContext(char* videoData, const int videoLen) 
    { 
     // Output buffer 
     bufferSize = 32768; 
     buffer = static_cast<char*>(av_malloc(bufferSize)); 

     // Internal buffer 
     pos = 0; 
     this->videoData = videoData; 
     this->videoLen = videoLen; 

     ctx_ = avio_alloc_context((unsigned char*) buffer, bufferSize, AVIO_FLAG_READ, this, &AVIOMemContext::read, &AVIOMemContext::write, &AVIOMemContext::seek); 
    } 

    ~AVIOMemContext() 
    { 
     av_free(videoData); 
    } 

    static int read(void *opaque, unsigned char *buf, int buf_size) 
    { 
     AVIOMemContext* This = static_cast<AVIOMemContext*>(opaque); 

     // Read from pos to pos + buf_size 
     if (This->pos + buf_size > This->videoLen) 
     { 
      int len = This->videoLen - This->pos; 
      memcpy(buf, This->videoData + This->pos, len); 
      return len; 
     } 
     else 
     { 
      memcpy(buf, This->videoData + This->pos, buf_size); 
      return buf_size; 
     } 
    } 

    static int write(void *opaque, unsigned char *buf, int buf_size) 
    { 
     /* 
     AVIOMemContext* This = static_cast<AVIOMemContext*>(opaque); 
     return fwrite(buf, 1, buf_size, This->f_); 
     */ 

     return 0; 
    } 

    static int64_t seek(void *opaque, int64_t offset, int whence) 
    { 
     AVIOMemContext* This = static_cast<AVIOMemContext*>(opaque); 

     if (offset + whence > This->videoLen) 
     { 
      This->pos = This->videoLen; 

      return -1; 
     } 
     else 
     { 
      This->pos = offset + whence; 

      return 0; 
     } 
    } 

    AVIOContext *get_avio() 
    { 
     return ctx_; 
    } 

private: 

    // Output buffer 
    int bufferSize; 
    char* buffer; 

    // Internal buffer 
    int pos; 
    char* videoData; 
    int videoLen; 

    AVIOContext* ctx_; 

}; 

mio codice corrente:

[...] 

av_register_all(); 
avcodec_register_all(); 

AVFormatContext* context; 
AVCodec* pCodec; 
AVPacket packet; 
AVCodecContext* pCodecCtx; 
int video_stream_index; 
int res; 
int got_picture; 

// Init variables and objects 
context = avformat_alloc_context(); 

AVIOMemContext priv_ctx(videoData, videoLen); 
context->pb = priv_ctx.get_avio(); 

res = avformat_find_stream_info(context, NULL); 

if (res < 0) 
{ 
    // Error 
    avformat_free_context(context); 

    return 0; 
} 

// Obtain the video stream of the total set of streams 
for (unsigned int k = 0; k < context->nb_streams; ++k) 
{ 
    if (context->streams[k]->codec->codec_type == AVMEDIA_TYPE_VIDEO) 
     video_stream_index = k; 
    context->streams[k]->codec->time_base.den = 90000; 
} 

pCodecCtx = context->streams[video_stream_index]->codec; 
pCodec = avcodec_find_decoder(pCodecCtx->codec_id); 

avcodec_open(pCodecCtx, pCodec); 

//allocate video frame 
AVFrame *pFrame = avcodec_alloc_frame(); 

unsigned int nFrame = 0; 

while (av_read_frame(context, &packet) >= 0) 

[...] 

Grazie in anticipo,

Dídac Pérez

risposta

3

È possibile creare il proprio AVIOContext. Devi chiamare ::avio_alloc_context quindi impostarlo su AVFormatContext::pb. Per i dettagli, vedere la mia risposta a How can libavformat be used without using other libav libraries?

+0

Grazie per il vostro aiuto, proverò proprio ora. –

+0

Attualmente ho creato il mio proprio AVIOContext ma l'app si blocca in avformat_find_stream_info() –