FFmpeg:无法在Android Q上使用文件描述符进行搜索 [英] FFmpeg: seeking not possible with file descriptor on Android Q

查看:95
本文介绍了FFmpeg:无法在Android Q上使用文件描述符进行搜索的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

鉴于公共文件路径通常在带范围存储的Android Q中不可用,我试图找出如何使FFmpeg音频解码器与文件描述符一起工作,而无需将文件复制到应用程序的私有目录中.

Given the fact that public file paths will generally not be available in Android Q with scoped storage, I am attempting to figure out how to make my FFmpeg audio decoder work with file descriptors, without copying the file to my app's private directories.

我们可以使用 Android Q隐私更改,并且可以使用管道协议(如

We can easily get a file descriptor using the methods described in Android Q privacy changes, and it is possible to open the file descriptor using the pipe protocol as described in Passing a native fd int to FFMPEG from openable URI. However, the result is not seekable using av_seek_frame and also the duration is not available using the duration member of AVFormatContext.

是否可以使用FFmpeg搜索文件描述符并检索持续时间?

Is there way to seek with a file descriptor with FFmpeg and retrieve the duration?

推荐答案

可以按照描述使用管道协议打开文件描述符

it is possible to open the file descriptor using the pipe protocol as described

我很好奇为什么必须通过管道协议打开文件描述符? sView播放器通过自定义 AVIOContext 打开文件描述符,至少可以查找在较旧的Android测试版本上.这是使用自定义AVIOContext打开AVFormatContext的伪代码.

I'm curious why it is necessary opening file descriptor via pipe protocol? sView player opens file descriptor by custom AVIOContext, which is seekable, at least on older tested versions of Android. Here is a pseudo-code opening AVFormatContext with custom AVIOContext.

    int aFileDescriptor = myResMgr->openFileDescriptor(theFileToLoad);
    AVFormatContext* aFormatCtx = avformat_alloc_context();
    StAVIOContext myAvioContext;
    if(!myAvioContext.openFromDescriptor(aFileDescriptor, "rb")) {
       // error
    }

    aFormatCtx->pb = myAvioContext.getAvioContext();
    int avErrCode = avformat_open_input(&aFormatCtx, theFileToLoad, NULL, NULL);

下面是尝试提取简化的StAVIOFileContext类定义的尝试.

Below is an attempt to extract a simplified StAVIOFileContext class definition.

//! Wrapper over AVIOContext for passing the custom I/O.
class StAVIOContext {
public:
  //! Main constructor.
  StAVIOContext() {
    const int aBufferSize = 32768;
    unsigned char* aBufferIO = (unsigned char* )av_malloc(aBufferSize + AV_INPUT_BUFFER_PADDING_SIZE);
    AVIOContext* myAvioCtx = avio_alloc_context (aBufferIO, aBufferSize, 0, this, readCallback, writeCallback, seekCallback);
  }

  //! Destructor.
  virtual ~StAVIOContext() {
    close();
    if (myAvioCtx != NULL) { av_free (myAvioCtx); }
  }

  //! Close the file.
  void close() {
    if(myFile != NULL) {
        fclose(myFile);
        myFile = NULL;
    }
  }

  //! Associate a stream with a file that was previously opened for low-level I/O.
  //! The associated file will be automatically closed on destruction.
  bool openFromDescriptor(int theFD, const char* theMode) {
    close();
  #ifdef _WIN32
    myFile = ::_fdopen(theFD, theMode);
  #else
    myFile =  ::fdopen(theFD, theMode);
  #endif
    return myFile != NULL;
  }

  //! Access AVIO context.
  AVIOContext* getAvioContext() const { return myAvioCtx; }

public:

  //! Virtual method for reading the data.
  virtual int read (uint8_t* theBuf,
                    int theBufSize) {
    if(myFile == NULL) { return -1; }

    int aNbRead = (int )::fread(theBuf, 1, theBufSize, myFile);
    if(aNbRead == 0 && feof(myFile) != 0) { return AVERROR_EOF; }
    return aNbRead;
  }

  //! Virtual method for writing the data.
  virtual int write (uint8_t* theBuf,
                     int theBufSize) {
    if(myFile == NULL) { return -1; }
    return (int )::fwrite(theBuf, 1, theBufSize, myFile);
  }

  //! Virtual method for seeking to new position.
  virtual int64_t seek (int64_t theOffset,
                        int theWhence) {
    if(theWhence == AVSEEK_SIZE || myFile == NULL) { return -1; }
  #ifdef _WIN32
    bool isOk = ::_fseeki64(myFile, theOffset, theWhence) == 0;
  #else
    bool isOk =    ::fseeko(myFile, theOffset, theWhence) == 0;
  #endif
    if(!isOk) { return -1; }
  #ifdef _WIN32
    return ::_ftelli64(myFile);
  #else
    return ::ftello(myFile);
  #endif
  }

private:
  //! Callback for reading the data.
  static int readCallback(void* theOpaque,
                          uint8_t* theBuf,
                          int  theBufSize) {
    return theOpaque != NULL
         ? ((StAVIOContext* )theOpaque)->read(theBuf, theBufSize)
         : 0;
  }

  //! Callback for writing the data.
  static int writeCallback(void* theOpaque,
                           uint8_t* theBuf,
                           int theBufSize) {
    return theOpaque != NULL
         ? ((StAVIOContext* )theOpaque)->write(theBuf, theBufSize)
         : 0;
  }

  //! Callback for seeking to new position.
  static int64_t seekCallback(void*   theOpaque,
                              int64_t theOffset,
                              int     theWhence) {
    return theOpaque != NULL
        ? ((StAVIOContext* )theOpaque)->seek(theOffset, theWhence)
        : -1;
  }

protected:
  AVIOContext* myAvioCtx;
  FILE* myFile;
};

这篇关于FFmpeg:无法在Android Q上使用文件描述符进行搜索的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆