免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2260 | 回复: 1
打印 上一主题 下一主题

[C] 求教,ffmpeg怎么自定义输出流 [复制链接]

论坛徽章:
2
15-16赛季CBA联赛之天津
日期:2016-12-20 17:56:18CU十四周年纪念徽章
日期:2017-04-20 16:30:16
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2016-12-20 11:41 |只看该作者 |倒序浏览
本帖最后由 lhd666 于 2017-02-16 10:04 编辑

以前没搞过视频相关的东西,现在需要使用ffmpeg在ceph对象存储上进行转码。ffmpeg自带示例avio_reading.c演示了怎么自定义输入流,我参照它成功从ceph对象存储中读取到数据并解码,但是又该怎么自定义输出流呢?
ffmpeg示例中,也有不使用AVFormatContext,用fwrite()写入AVPacket的示例,那么我只需要把fwrite()替换成rados的写入操作即可,但是不知道avformat_write_header()和av_write_trailer()这两个api写入的数据该怎么使用fwrite()写入,归根结底还是对ffmpeg不熟,网上资料又少。
下面是自定义输入流的代码:
  1. struct ceph_handler {
  2.         rados_t cluster;
  3.         rados_ioctx_t io;
  4.         uint64_t off;
  5.         char *objname;
  6. };

  7. struct ceph_handler *ceph_handler_create(const char * const clustername,
  8.                                const char * const username,
  9.                                uint64_t flags,
  10.                                const char * const conf,
  11.                                const char * const poolname,
  12.                                const char * const objname)
  13. {
  14.         struct ceph_handler *handler;
  15.         int err;

  16.         handler = malloc(sizeof(*handler));
  17.         if (!handler)
  18.                 return NULL;

  19.         err = rados_create2(&handler->cluster, clustername, username, flags);
  20.         if (err < 0) {
  21.                 free(handler);
  22.                 return NULL;
  23.         }

  24.         err = rados_conf_read_file(handler->cluster, conf);
  25.         if (err < 0) {
  26.                 rados_shutdown(handler->cluster);
  27.                 free(handler);
  28.                 return NULL;
  29.         }

  30.         err = rados_connect(handler->cluster);
  31.         if (err < 0) {
  32.                 rados_shutdown(handler->cluster);
  33.                 free(handler);
  34.                 return NULL;
  35.         }

  36.         err = rados_ioctx_create(handler->cluster, poolname, &handler->io);
  37.         if (err < 0) {
  38.                 rados_shutdown(handler->cluster);
  39.                 free(handler);
  40.                 return NULL;
  41.         }

  42.         handler->objname = strdup(objname);
  43.         if (!handler->objname) {
  44.                 rados_ioctx_destroy(handler->io);
  45.                 rados_shutdown(handler->cluster);
  46.                 free(handler);
  47.                 return NULL;
  48.         }

  49.         handler->off = 0;

  50.         return handler;
  51. }

  52. void ceph_handler_destroy(struct ceph_handler *handler)
  53. {
  54.         rados_ioctx_destroy(handler->io);
  55.         rados_shutdown(handler->cluster);
  56.         free(handler->objname);
  57.         free(handler);
  58. }

  59. static int read_packet(void *opaque, uint8_t *buf, int buf_size)
  60. {
  61.         struct ceph_handler *handler = opaque;
  62.         int nr;

  63.         nr = rados_read(handler->io, handler->objname, (char *)buf, buf_size, handler->off);
  64.         if (nr < 0)
  65.                 errno = -nr;
  66.         else
  67.                 handler->off += nr;

  68.         return nr;
  69. }

  70. static int write_packet(void *opaque, uint8_t *buf, int buf_size)
  71. {
  72.         struct ceph_handler *handler = opaque;
  73.         int err;

  74.         /* 成功时返回0,而非写入字节数 */
  75.         err = rados_write(handler->io, handler->objname, (char *)buf, buf_size, handler->off);
  76.         if (err)
  77.                 errno = - err;
  78.         else
  79.                 handler->off += buf_size;

  80.         return err ? err : buf_size;
  81. }

  82. static int64_t seek(void *opaque, int64_t offset, int whence)
  83. {
  84.         struct ceph_handler *handler = opaque;
  85.         uint64_t size;
  86.         time_t mtime;
  87.         int err;

  88.         switch (whence) {
  89.         case SEEK_SET:
  90.                 handler->off = offset;
  91.                 break;

  92.         case SEEK_CUR:
  93.                 handler->off += offset;
  94.                 break;

  95.         case SEEK_END:
  96.                 err = rados_stat(handler->io, handler->objname, &size, &mtime);
  97.                 if (err < 0) {
  98.                         errno = - err;
  99.                         return -1;
  100.                 }
  101.                 if (size < offset)
  102.                         handler->off = 0;
  103.                 else
  104.                         handler->off = size - offset;
  105.         }

  106.         return handler->off;
  107. }

  108. static int open_input_file(const char *filename)
  109. {
  110.         AVIOContext *avio_ctx = NULL;
  111.         uint8_t *avio_ctx_buffer = NULL;
  112.         size_t avio_ctx_buffer_size = 1 << 2;
  113.         struct ceph_handler *handler = NULL;
  114.         unsigned int i;
  115.         int ret;

  116.         ifmt_ctx = NULL;
  117.         
  118.         handler = ceph_handler_create("ceph", "client.admin", 0,
  119.                                       "ceph.conf", "mypool", filename);
  120.         if (!handler)
  121.                 return -1;

  122.         ifmt_ctx = avformat_alloc_context();
  123.         if (!ifmt_ctx)
  124.                 goto err;

  125.         avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);
  126.         if (!avio_ctx_buffer)
  127.                 goto err;

  128.         avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,
  129.                                       0, handler, read_packet, write_packet,
  130.                                       seek);
  131.         if (!avio_ctx)
  132.                 goto err;
  133.         ifmt_ctx->pb = avio_ctx;

  134.         ret = avformat_open_input(&ifmt_ctx, NULL, NULL, NULL);
  135.         if (ret < 0)
  136.                 goto err;

  137.         ret = avformat_find_stream_info(ifmt_ctx, NULL);
  138.         if (ret < 0)
  139.                 goto err;

  140.         for (i = 0; i < ifmt_ctx->nb_streams; i++) {
  141.                 AVStream *stream;
  142.                 AVCodecContext *codec_ctx;
  143.                 stream = ifmt_ctx->streams[i];
  144.                 codec_ctx = stream->codec;
  145.                 /* Reencode video & audio and remux subtitles etc. */
  146.                 if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
  147.                     codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
  148.                         /* Open decoder */
  149.                         ret = avcodec_open2(codec_ctx,
  150.                                             avcodec_find_decoder(codec_ctx->codec_id), NULL);
  151.                         if (ret < 0)
  152.                                 goto err;
  153.                 }
  154.         }

  155.         
  156.         av_dump_format(ifmt_ctx, 0, filename, 0);
  157.         return 0;

  158. err:
  159.         if (ifmt_ctx)
  160.                 avformat_close_input(&ifmt_ctx);
  161.         ifmt_ctx = NULL;
  162.         if (handler)
  163.                 ceph_handler_destroy(handler);
  164.         if (avio_ctx) {
  165.                 av_freep(&avio_ctx->buffer);
  166.                 av_freep(&avio_ctx);
  167.         }

  168.         return -1;
  169. }
复制代码


论坛徽章:
2
15-16赛季CBA联赛之天津
日期:2016-12-20 17:56:18CU十四周年纪念徽章
日期:2017-04-20 16:30:16
2 [报告]
发表于 2017-02-16 10:00 |只看该作者
找方法了,在学习雷大的教程的时候,看到了相关介绍:http://blog.csdn.net/leixiaohua1020/article/details/39759623
和读的方法很相似,但是注意必须提供seek和write,否则有的视频编码会失败。看来ffmpeg没举输出流的例子,是觉得没有必要,归根结底还是自身水平太低,需要不断学习、练习和归纳总结
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP