2017-04-25 30 views
0

我目前正在嘗試使用ffmpeg的庫爲SFML編寫自定義SoundFileReader。我唯一可以用於avcodec和avformat的是類別InputStream,下面是SFML的一部分。我看過avformat_open_inputAVIOContext,我學會了如何使用具有緩衝區的自定義流,但是如何創建可與自定義讀取,查找和lseek函數配合使用的AVIOContextffmpeg avformat_open_input自定義流對象

class InputStream { 
    int64_t getSize() 
    int64_t read(void* data, int64_t size); 
    int64_t seek(int64_t position); 
    int64_t tell(); // Gets the stream position 
}; 

回答

1

你需要寫一組的回調函數,然後通過一個指針這些回調和不透明的參數去avio_alloc_context。請注意,這些回調不能拋出。

/// <summary> 
/// Reads up to buffer_capacity_bytes_count bytes into supplied buffer. 
/// Basically should work like ::read C method. 
/// </summary> 
/// <param name="opaque"> 
/// Opaque pointer to reader instance. Passing nullptr is not allowed. 
/// </param> 
/// <param name="p_buffer"> 
/// Pointer to data buffer. Passing nullptr is not allowed. 
/// </param> 
/// <param name="buffer_capacity_bytes_count"> 
/// Size of the buffer pointed to by p_buffer, in bytes. 
/// Passing value less than or equal to 0 is not allowed. 
/// </param> 
/// <returns> 
/// Non negative values containing amount of bytes actually read. 0 if EOF has been reached. 
/// -1 if an error occurred. 
/// </returns> 
static auto 
Read(void * const opaque, uint8_t * const p_buffer, int const buffer_capacity_bytes_count) noexcept 
{ 
    int result{-1}; 
    if(opaque && p_buffer && (0 <= buffer_capacity_bytes_count)) 
    { 
     auto & stream{*reinterpret_cast< InputStream * >(opaque)}; 
     try 
     { 
      auto const read_result{stream.read(p_buffer, buffer_capacity_bytes_count)}; 
      if((0 <= read_result) && (read_result <= buffer_capacity_bytes_count)) 
      { 
       result = read_result; 
      } 
     } 
     catch(...) 
     { 
      // print error or something 
     } 
    } 
    return(result); 
} 

/// <summary> 
/// Changes file pointer position or retrieves file size. 
/// Basically should work like ::lseek and ::fstat C methods. 
/// </summary> 
/// <param name="opaque"> 
/// Opaque pointer to reader instance. Passing nullptr is not allowed. 
/// </param> 
/// <param name="pos"> 
/// Target offset. When retrieving file size this should be 0. 
/// </param> 
/// <param name="whence"> 
/// Flag indicating operation. Valid values are SEEK_SET, SEEK_CUR, SEEK_END (as in C library), 
/// AVSEEK_SIZE and optional AVSEEK_FORCE bit. 
/// </param> 
/// <returns> 
/// Non-negative values containing offset of the file pointer or file size in bytes. 
/// Negative values if an error occurred. 
/// </returns> 
static auto 
Seek(void * const opaque, int64_t const pos, int const whence) noexcept 
{ 
    int64_t result{AVERROR(EBADF)}; 
    if(opaque) 
    { 
     auto & stream{*reinterpret_cast< InputStream * >(opaque)}; 
     try 
     { 
      auto const action{whence & (SEEK_SET | SEEK_CUR | SEEK_END | AVSEEK_SIZE)}; 
      auto const forced{0 != (whence & AVSEEK_FORCE)}; // can be ignored 
      switch(action) 
      { 
       case SEEK_SET: 
       case SEEK_CUR: 
       case SEEK_END: 
       { 
        // TODO perform seek... 
        break; 
       } 
       case AVSEEK_SIZE: 
       { 
        result = stream.getSize(); 
        break; 
       } 
      } 
     } 
     catch(...) 
     { 
      // print error or something 
     } 
    } 
    return(result); 
} 

... 

InputStream stream; 
auto const opaque{reinterpret_cast< void * >(::std::addressof(stream))}; 
auto p_io_context 
{ 
    ::avio_alloc_context 
    (
     static_cast< unsigned char * >(p_buffer) // ownership is not transferred 
    , buffer_size 
    , 0 // 0 if openning for reading, 1 if openning for writing 
    , opaque 
    , &Read 
    , nullptr // write callback function, not used if we open for reading 
    , &Seek 
    ) 
}; 
+0

嗯,我很高興我沒有發佈我的答案我得到,因爲這實際上有一個問題的修復程序,我剛剛遇到m4a文件。 'AVSEEK_SIZE'從哪個選項修復它。非常感謝! –