android - FFmpeg:无法在 Android Q 上使用文件描述符进行搜索

标签 android ffmpeg file-descriptor android-10.0 scoped-storage

鉴于公共(public)文件路径在具有范围存储的 Android Q 中通常不可用,我试图弄清楚如何使我的 FFmpeg 音频解码器与文件描述符一起工作,而不会将文件复制到我的应用程序的私有(private)目录中。

我们可以使用 Android Q privacy changes 中描述的方法轻松获取文件描述符。 , 并且可以使用 Passing a native fd int to FFMPEG from openable URI 中描述的管道协议(protocol)打开文件描述符.但是,使用 av_seek_frame 无法搜索结果。并且使用 AVFormatContext 的 duration 成员也无法获得持续时间.

有没有办法使用 FFmpeg 查找文件描述符并检索持续时间?

最佳答案

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



我很好奇为什么有必要通过管道协议(protocol)打开文件描述符?
sView player自定义打开文件描述符 AVIO上下文 ,这是可搜索的,至少在较旧的测试版本的 Android 上是可搜索的。这是使用自定义 AVIOContext 打开 AVFormatContext 的伪代码。
    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 类定义的尝试。
//! 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;
};

关于android - FFmpeg:无法在 Android Q 上使用文件描述符进行搜索,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57445600/

相关文章:

java - 可以将图像作为 ByteBuffer 发送到我的 Servlet 吗?

通过网络安装打开时正确关闭文件描述符

android - 可以将 Beta 版应用程序作为 .apk 分发给亲朋好友进行测试并获得反馈吗?

java - Visual Studio - Cordova Android "transformClassesWithDexForDebug"错误

video - FFMPEG 转换为 MXF

delphi - ffmpeg 和 windows 命令行

objective-c - 如何使用 FFMPEG 混合不同格式的声音文件?

ios - 我可以关闭当前未使用的 UIAppFonts 的文件描述符吗?

子进程在使用父进程将数据写入管道之前读取数据

android - 将位图编码为 byte[] 数组时某些手机出现问题