FFmpeg读取并定位代码中的视频

什么情况下视频会存储在代码中?

在没有文件系统时或者内存紧缺时,就需要把视频资源转成常量数组直接编译到代码中。

实现

实现方式

将常量数组分块放入内存,再从内存中读取数据。

从内存中读取数据

avformat_open_input() 之前初始化一个 AVIOContext ,而且将原本的 AVFormatContext 的指针pb( AVIOContext 类型)指向这个自行初始化 AVIOContext 。当自行指定了 AVIOContext 之后,avformat_open_input() 里面的 URL 参数就不起作用了(URL类型还是起作用的,最好填 NULL"" )。

#define ASSET_BUFFER_SIZE (32 * 1024)   /* 内存块大小 */

  AVFormatContext *ic = NULL;
  ic = avformat_alloc_context();

  ic->pb = avio_alloc_context((unsigned char*)av_malloc(ASSET_BUFFER_SIZE), ASSET_BUFFER_SIZE, 0,
                               is         /* 回调函数上下文 */,
                               read_asset /* 读取数据的回调函数指针 */,
                               NULL       /* 输出数据的回调函数指针 */,
                               seek_asset /* 定位数据的回调函数指针 */);

  avformat_open_input(&ic, ""/* URL */, NULL, NULL);
  /* 省略... */
exit:
  if (ic) avformat_close_input(&ic);

读取视频

以下是读取文件线程的代码:

#define ASSET_BUFFER_SIZE (32 * 1024)   /* 内存块大小 */

typedef struct _VideoState {
  /* 省略... */
  const asset_info_t* asset_info;       /* 单个资源的描述信息,通过该对象获取常量数组 */
  int64_t asset_offset;                 /* 记录获取数据的偏移量 */
  char asset_name[32];                  /* 资源名 */
} VideoState;

static int read_thread(void* arg) {
  VideoState* is = arg;
  int ret;
  bool_t is_fail = FALSE;
  AVFormatContext* ic = NULL;

  /* 省略... */

  ic = avformat_alloc_context();
  if (!ic) {
    av_log(NULL, AV_LOG_FATAL, "Could not allocate context.\n");
    ret = AVERROR(ENOMEM);
    goto fail;
  }
  /* 省略... */
  
  /* 通过 AWTK 中 的 assets_manager 获取常量数组 */
  is->asset_info = assets_manager_ref(assets_manager(), ASSET_TYPE_DATA, is->asset_name);
  is->asset_offset = 0;
  ic->pb = avio_alloc_context((unsigned char*)av_malloc(ASSET_BUFFER_SIZE), ASSET_BUFFER_SIZE, 0,
                              is, read_asset, NULL, seek_asset);

  avformat_open_input(&ic, "", NULL, NULL);

/* 省略... */
  goto exit;
fail:
  is_fail = TRUE;
exit:

/* 省略... */

  if (ic) avformat_close_input(&ic);
  return 0;
}

读取数据的回调函数实现:

/* 实现功能: 把buf_size字节数据送入buf,返回值为获取到的数据大小,返回0表示读取数据完成,返回-1表示出错。 */
static int read_asset(void* opaque, uint8_t* buf, int buf_size) {
  VideoState* is = (VideoState*)opaque;
  uint32_t ret_size = 0;
  return_value_if_fail(is != NULL && is->asset_info != NULL, 0);

  if (is->asset_offset < is->asset_info->size) {
    uint32_t size = is->asset_info->size - is->asset_offset;
    ret_size = tk_min(buf_size, size);
    memcpy(buf, is->asset_info->data + is->asset_offset, ret_size);
    is->asset_offset += ret_size; /* 记录数据的偏移量 */
  }
  return ret_size;
}

定位视频

static int64_t seek_asset(void* opaque, int64_t offset, int whence) {
  VideoState* is = (VideoState*)opaque;
  return_value_if_fail(is != NULL && is->asset_info != NULL, -1);

  switch (whence) {
    case AVSEEK_SIZE: { /* 不进行 seek 操作,而是要求返回 视频 大小 */
      return (int64_t)is->asset_info->size;
    } break;
    case SEEK_SET: { /* 表示 offset 是相对 视频开头的位置 */
      is->asset_offset = offset;
    } break;
    case SEEK_END: { /* 表示 offset 是相对 视频结尾的位置, offset通常小于0 */
      is->asset_offset = is->asset_info->size + offset;
    } break;
    default: {
      av_log(NULL, AV_LOG_FATAL, "seek_asset(): Do not implement \"whence\" = %d\n", whence);
      return -1;
    } break;
  }
  return (int64_t)(is->asset_info->data + offset); /* 返回数据地址 */
}

参考

AWTK:github.com/zlgopen/awtk
awtk-media-player:github.com/zlgopen/awtk-media-player
ffmpeg 从内存中读取数据(或将数据输出到内存)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,451评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,172评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,782评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,709评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,733评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,578评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,320评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,241评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,686评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,878评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,992评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,715评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,336评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,912评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,040评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,173评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,947评论 2 355

推荐阅读更多精彩内容