首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >Android :如何替换AAsset以处理来自外部存储的文件以进行FFmpeg解码

Android :如何替换AAsset以处理来自外部存储的文件以进行FFmpeg解码
EN

Stack Overflow用户
提问于 2020-01-07 22:59:20
回答 1查看 475关注 0票数 2

我正在使用双簧管的RhytmGame例子作为一个指南来实现双簧管和mp3解码使用FFmpeg到我的应用程序。由于我对NDK相当陌生,而且还是C++初学者,所以我仍然很难理解我遇到的一些基本概念。我的问题是:上面提到的示例仅使用Android的AssetManager的本机实现处理来自资产文件夹的文件。由于我希望访问外部存储的文件,我必须改变这一点,但我不清楚如何做到这一点。

这就是我陷入困境的地方:我有一个FFmpegExtractor类,它在FFmpeg's avio.h中调用此方法

代码语言:javascript
运行
AI代码解释
复制
 * 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));

在这里打电话:

代码语言:javascript
运行
AI代码解释
复制
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;
    }
}

我希望替换assetreadseek参数,这样我就可以使用存储中的文件而不是AAsset对象。

这是上面传递的read回调:

代码语言:javascript
运行
AI代码解释
复制
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回调:

代码语言:javascript
运行
AI代码解释
复制
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,但这当然做不到。我知道如何打开和读取文件,但我不清楚这是否是这里所期望的,以及如何将AAsset中的方法转换为返回存储中文件所需值的操作。谁能给我指明正确的方向?

编辑:下面是我对@BrianChen的有益评论的回复中提到的代码块:

代码语言:javascript
运行
AI代码解释
复制
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

EN

回答 1

Stack Overflow用户

发布于 2020-01-09 23:15:01

这与使用AAsset是一样的。

代码语言:javascript
运行
AI代码解释
复制
// wrapper class for file stream 
class  MediaSource {
public:
    MediaSource() {
    }
    ~MediaSource() {
        source.close();
    }
    void open(const string& filePath) {
        source.open(filePath, ios::in | ios::binary);
    }
    int read(uint8_t *buffer, int buf_size) {
        // read data to buffer
        source.read((char *)buffer, buf_size)
        // return how many bytes were read
        return source.gcount();
    }
    int64_t seek(int64_t offset, int whence) {
        if (whence == AVSEEK_SIZE) {
            // FFmpeg needs file size.
            int oldPos = source.tellg();
            source.seekg(0,ios::end);
            int64_t length = source.tellg();
            // seek to old pos
            source.seekg(oldPos);
            return length;
        } else if (whence == SEEK_SET) {
            // set pos to offset
            source.seekg(offset);
        } else if (whence == SEEK_CUR) {
            // add offset to pos
            source.seekg(offset, ios::cur);
        } else {
            // do not support other flags, return -1
            return -1;
        }
        // return current pos
        return source.tellg();
    }
private:
    ifstream source;
};

// If FFmpeg needs to read the file, it will call this function.
// We need to fill the buffer with file's data.
int read(void *opaque, uint8_t *buffer, int buf_size) {
    MediaSource *source = (MediaSource *)opaque;
    return source->read(buffer, buf_size);
}

// If FFmpeg needs to seek in the file, it will call this function.
// We need to change the read pos.
int64_t seek(void *opaque, int64_t offset, int whence) {
    MediaSource *source = (MediaSource *)opaque;
    return source->seek(offset, whence);
}

// add MediaSource to class FFMpegExtractor
class FFMpegExtractor {
private:
    // add this line to declare of class FFMpegExtractor
    MediaSource* mSource;
};

FFMpegExtractor::FFMpegExtractor() {
    // add this line in constructor, new a instance
    mSource = new MediaSource;
}

FFMpegExtractor::~FFMpegExtractor() {
    // add this line in destructor, release instance
    delete mSource;
}

bool FFMpegExtractor::createAVIOContext(const string& filePath, uint8_t *buffer, uint32_t bufferSize,
                                        AVIOContext **avioContext) {

    mSource.open(filePath);
    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,
            mSource, // 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;
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59640862

复制
相关文章
jsonobject string转json_string转换为long
本文使用一个小例子展示在java中怎样将一个JSON格式的字符串转化为JSONObject对象。注意,我们使用的是 org.json.simple.JSONObject;
全栈程序员站长
2022/09/22
3.4K0
jsonobject string转json_string转换为long
integer转string java_Integer转换为String类型[通俗易懂]
Exception in thread “main” java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
全栈程序员站长
2022/11/01
2.1K0
string转换为jsonarray_jsonobject转jsonarray
如果用的是fastjson 则导包为 import com.alibaba.fastjson.JSONObject
全栈程序员站长
2022/09/22
2K0
string转换为jsonarray_jsonobject转jsonarray
java map 转string_java-将Map <String,Object>转换为Map <String,String>
Map map = new HashMap(); //Object is containing String
全栈程序员站长
2022/08/25
12.4K0
integer转换为string_go 字符串转int
str := “123” // string 转 int i, err := strconv.Atoi(str) if err == nil {   fmt.Printf(“i: %v\n”,i) } // string 转 int64 i64,err := strconv.ParseInt(str,10,64) if err == nil {   fmt.Printf(“i64: %v\n”,i64) } // string 转 int32 j,err := strconv.ParseInt(str,10,32) if err == nil {   fmt.Printf(“i32: %v\n”,int32(j)) }
全栈程序员站长
2022/11/06
3.5K0
PHP中的Array2String & String2Array
在用PHP开发时我们有时期望将一个数组(任意多维),在页面之间传递或者存入数据库。这时我们可以将Array转换为String传递或保存,取出用的时候在转换回来即可。 <?/*在Array和String
joshua317
2018/04/10
2K0
java把string转int类型_java把String类型转换为int类型的方法
这篇文章将为大家详细讲解有关java把String类型转换为int类型的方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
全栈程序员站长
2022/11/10
4.2K0
java把string转int类型_java把String类型转换为int类型的方法
iOS基础【string和Array 互转】&【 string与class互转】& 【json string 和Array互转】
在适配iOS13的时候,经常要对特定类进行特出处理,这个时候class与string之间的互相转换就经常需要使用。
公众号iOS逆向
2021/03/24
1.2K0
iOS基础【string和Array 互转】&【 string与class互转】& 【json string 和Array互转】
Java中将Map转String,String转Map
但很多时候并不能直接将Map对象的toString() 而是应该转换为JsonObject后再调用toString()后存入就正常了
JavaEdge
2021/02/22
14.5K0
jsonobject string转json_java jsonobject转string
这里的JSONObject对像是不是hutool这些工具类的哦,是java内部自带这个。
全栈程序员站长
2022/09/25
3.8K0
String转JsonArray转List[通俗易懂]
场景是查看学生详情时需要展示学生学历信息 比如某某年 哪个学校毕业 奖惩情况等等
全栈程序员站长
2022/08/31
3.2K0
javabyte数组转string_byte数组转string
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/179050.html原文链接:https://javaforall.cn
全栈程序员站长
2022/09/27
3K0
IntPtr 转 string
假设有 intPtr pBuffer 方法一: 直接使用Marshal.PtrToStringAnsi方法: string ss = Marshal.PtrToStringAnsi(pBuffer); 但,如果pBuffer中有\0,此方法所获取的字符串会被截断。这种情况要用方法二。 方法二: 先转为byte数组,然后再转string: byte[] cc = new byte[dwBufSize]; Marshal.Copy(pBuffer, cc, 0, (int)dwBufSi
庞小明
2018/03/09
2.4K0
long转string mybatis_Long转String总结
* 通过测试,发现如果传入null,则第一种方式报错;第二种方式打印出null字符串
全栈程序员站长
2022/08/28
3.3K0
python 数组转换为字典_char转换为string
会触发TypeError: sequence item 0: expected string, int found的错误
全栈程序员站长
2022/11/07
1.1K0
数组转String
这里对文章进行总结:以上就是今天要讲的内容,本文仅仅简单介绍了Java转的数组使用
用户10175992
2022/11/15
3K0
Array,Date,String 对象方法
方法 描述 concat() 连接两个或更多的数组,并返回结果。 copyWithin() 从数组的指定位置拷贝元素到数组的另一个指定位置中。 entries() 返回数组的可迭代对象。 every() 检测数值元素的每个元素是否都符合条件。 fill() 使用一个固定值来填充数组。 filter() 检测数值元素,并返回符合条件所有元素的数组。 find() 返回符合传入测试(函数)条件的数组元素。 findIndex() 返回符合传入测试(函数)条件的数组元素索引。 forEach() 数组每个元素都执行一次回调函数。 from() 通过给定的对象中创建一个数组。 includes() 判断一个数组是否包含一个指定的值。 indexOf() 搜索数组中的元素,并返回它所在的位置。 isArray() 判断对象是否为数组。 join() 把数组的所有元素放入一个字符串。 keys() 返回数组的可迭代对象,包含原始数组的键(key)。 lastIndexOf() 搜索数组中的元素,并返回它最后出现的位置。 map() 通过指定函数处理数组的每个元素,并返回处理后的数组。 pop() 删除数组的最后一个元素并返回删除的元素。 push() 向数组的末尾添加一个或更多元素,并返回新的长度。 reduce() 将数组元素计算为一个值(从左到右)。 reduceRight() 将数组元素计算为一个值(从右到左)。 reverse() 反转数组的元素顺序。 shift() 删除并返回数组的第一个元素。 slice() 选取数组的的一部分,并返回一个新数组。 some() 检测数组元素中是否有元素符合指定条件。 sort() 对数组的元素进行排序。 splice() 从数组中添加或删除元素。 toString() 把数组转换为字符串,并返回结果。 unshift() 向数组的开头添加一个或更多元素,并返回新的长度。 valueOf() 返回数组对象的原始值。
江一铭
2022/07/05
1.2K0
string和array基本方法
  变异方法 :  push() pop() shift() unshift() splice() sort() reverse()  会改变被这些方法调用的原始数组。
刘嘿哈
2022/10/25
4040
alibaba String转json转map
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/145506.html原文链接:https://javaforall.cn
全栈程序员站长
2022/08/27
5K0
String转JSONArray,遍历JSONArray,Array数组转换成JSON字符串
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/151413.html原文链接:https://javaforall.cn
全栈程序员站长
2022/08/31
1.2K0
String转JSONArray,遍历JSONArray,Array数组转换成JSON字符串

相似问题

将Array<String>转换为String,然后返回到Array<String>

26

从Array[((String,String),Double)]转换为Array[(String,Array[((String,String),Double)]]

11

如何将Array[(String,List[String])]转换为Array[(String,String)]

43

配置单元:将array<struct<key:string、value:array<string>>>转换为map<string、array<string>>

10

将array<String^>转换为System::String^

12
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文