我使用双簧管的 RhytmGame 示例作为指导,FFmpeg
在我的应用程序中实现双簧管和 mp3 解码。由于我对 NDK 和 C++ 初学者还很陌生,所以我仍然在为遇到的一些基本概念而苦恼。我的问题:上面提到的示例只处理资产文件夹中的文件,使用 Android 的 AssetManager 的本机实现。由于我希望访问外部存储上的文件,因此我必须更改此设置,但我不清楚如何执行此操作。
这就是我卡住的地方:我有一个FFmpegExtractor
类调用这个方法FFmpeg's avio.h
:
* Allocate and initialize an AVIOContext for buffered I/O. It must be later
* freed with avio_context_free().
*
* @param buffer Memory block for input/output operations via AVIOContext.
* The buffer must be allocated with av_malloc() and friends.
* It may be freed and replaced with a new buffer by libavformat.
* AVIOContext.buffer holds the buffer currently in use,
* which must be later freed with av_free().
* @param buffer_size The buffer size is very important for performance.
* For protocols with fixed blocksize it should be set to this blocksize.
* For others a typical size is a cache page, e.g. 4kb.
* @param write_flag Set to 1 if the buffer should be writable, 0 otherwise.
* @param opaque An opaque pointer to user-specific data.
* @param read_packet A function for refilling the buffer, may be NULL.
* For stream protocols, must never return 0 but rather
* a proper AVERROR code.
* @param write_packet A function for writing the buffer contents, may be NULL.
* The function may not change the input buffers content.
* @param seek A function for seeking to specified byte position, may be NULL.
*
* @return Allocated AVIOContext or NULL on failure.
*/
AVIOContext *avio_alloc_context(
unsigned char *buffer,
int buffer_size,
int write_flag,
void *opaque,
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
int64_t (*seek)(void *opaque, int64_t offset, int whence));
调用在这里:
bool FFMpegExtractor::createAVIOContext(AAsset *asset, uint8_t *buffer, uint32_t bufferSize,
AVIOContext **avioContext) {
constexpr int isBufferWriteable = 0;
*avioContext = avio_alloc_context(
buffer, // internal buffer for FFmpeg to use
bufferSize, // For optimal decoding speed this should be the protocol block size
isBufferWriteable,
asset, // Will be passed to our callback functions as a (void *)
read, // Read callback function
nullptr, // Write callback function (not used)
seek); // Seek callback function
if (*avioContext == nullptr){
LOGE("Failed to create AVIO context");
return false;
} else {
return true;
}
}
我正在寻找替换asset
,read
和seek
参数,以便我可以使用存储中的文件而不是 AAsset 对象。
这是read
上面传递的回调:
int read(void *opaque, uint8_t *buf, int buf_size) {
auto asset = (AAsset *) opaque;
int bytesRead = AAsset_read(asset, buf, (size_t)buf_size);
return bytesRead;
}
这是seek
回调:
int64_t seek(void *opaque, int64_t offset, int whence){
auto asset = (AAsset*)opaque;
// See https://www.ffmpeg.org/doxygen/3.0/avio_8h.html#a427ff2a881637b47ee7d7f9e368be63f
if (whence == AVSEEK_SIZE) return AAsset_getLength(asset);
if (AAsset_seek(asset, offset, whence) == -1){
return -1;
} else {
return 0;
}
}
我试过用 FILE 替换 AAsset,但当然不行。我知道如何打开和读取文件,但我不清楚这是否是这里所期望的,以及如何将 AAsset 中的方法转换为返回存储中文件所需值的操作。谁能指出我正确的方向?
编辑:因为它不适合这里是我在回复@BrianChen 的有用评论时提到的代码块:
bool FFMpegExtractor::openAVFormatContext(AVFormatContext *avFormatContext) {
int result = avformat_open_input(&avFormatContext,
"", /* URL is left empty because we're providing our own I/O */
nullptr /* AVInputFormat *fmt */,
nullptr /* AVDictionary **options */
);
不幸的是avformat_open_input()
产生了一个
Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x20 in tid 23767, pid 23513