2012-12-12 18 views
7

Załóż, że mam cały plik wideo w pamięci i chcę użyć libav do odkodowania całych ramek. Jak mam to zrobić? Chodzi o to, że mogę to zrobić czytając bezpośrednio z pliku przy użyciu funkcji avformat_open_input(), ale muszę to zrobić z pliku, który jest przechowywany w pamięci.Dekodowanie pliku wideo z pamięci przy użyciu libav

realizacja My AVIOContext:

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

}; 

Mój bieżący kod:

[...] 

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) 

[...] 

Dzięki z góry

Didac Pérez

Odpowiedz

3

Można tworzyć własne AVIOContext. Musisz zadzwonić pod numer ::avio_alloc_context, a następnie ustawić go na AVFormatContext::pb. Aby uzyskać szczegółowe informacje, zapoznaj się z moją odpowiedzią na How can libavformat be used without using other libav libraries?

+0

Dzięki za pomoc, wypróbuję ją już teraz. –

+0

Mam obecnie utworzony własny tekst AVIOC, ale aplikacja ulega awarii w avformat_find_stream_info() –