android - FFmpeg:无法在 Android Q 上使用文件描述符进行搜索
问题描述
鉴于公共文件路径在具有范围存储的 Android Q 中通常不可用,我试图弄清楚如何使我的 FFmpeg 音频解码器与文件描述符一起工作,而不会将文件复制到我的应用程序的私有目录中。
我们可以使用Android Q 隐私更改中描述的方法轻松获取文件描述符,并且可以使用管道协议打开文件描述符,如将本机 fd int 从可打开的 URI 传递给 FFMPEG 中所述。但是,av_seek_frame
使用 的持续时间成员无法搜索结果,并且持续时间也不可用AVFormatContext
。
有没有办法使用 FFmpeg 查找文件描述符并检索持续时间?
解决方案
可以使用所述管道协议打开文件描述符
我很好奇为什么有必要通过管道协议打开文件描述符? sView 播放器通过自定义AVIOContext打开文件描述符,这是可搜索的,至少在旧测试版本的 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;
};
推荐阅读
- swift - 核心数据:无法识别的选择器发送到实例错误
- installation - 尝试安装带有货物的软件包时出现“错误:指定的软件包没有二进制文件”?
- reactjs - 如何使用 onClick 方法通过 react-router 传递道具
- javascript - 无法重置表单输入字段(React JS 控制组件)
- python - while_loop 中的层初始化:“控制流构造中的变量初始化器”
- python - 从 FTP 目录打开压缩文件的简单方法
- python-3.x - 为什么这个 VAE 实现有时会添加一个 sigmoid 操作?
- php - WordPress:从我的内容模板中删除 get_the_title
- android - 通过 Intent 启动 Here 地图导航
- java - 无法在eclipse中观看表达式