Я использую Пример Oboe RhytmGame в качестве руководства для реализации декодирования гобоя и mp3 с использованием FFmpeg
в моем приложении. Так как я довольно новичок в NDK и новичке в C ++, я все еще борюсь с некоторыми базовыми понятиями c, с которыми я сталкиваюсь. Моя проблема: в приведенном выше примере обрабатываются только файлы из папки ресурсов, используя собственную реализацию AssetManager Android. Поскольку я ищу доступ к файлам на внешнем хранилище, я должен изменить это, но мне неясно, как это сделать.
Вот где я застрял: у меня есть класс 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;
}
}
Я пытался просто заменить AAsset на FILE, но, конечно, этого не происходит. Я знаю, как открывать и читать файлы, но мне неясно, что именно здесь ожидается, и как я могу преобразовать методы в 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