求教,ffmpeg怎么自定义输出流
本帖最后由 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不熟,网上资料又少。
下面是自定义输入流的代码:
struct ceph_handler {
rados_t cluster;
rados_ioctx_t io;
uint64_t off;
char *objname;
};
struct ceph_handler *ceph_handler_create(const char * const clustername,
const char * const username,
uint64_t flags,
const char * const conf,
const char * const poolname,
const char * const objname)
{
struct ceph_handler *handler;
int err;
handler = malloc(sizeof(*handler));
if (!handler)
return NULL;
err = rados_create2(&handler->cluster, clustername, username, flags);
if (err < 0) {
free(handler);
return NULL;
}
err = rados_conf_read_file(handler->cluster, conf);
if (err < 0) {
rados_shutdown(handler->cluster);
free(handler);
return NULL;
}
err = rados_connect(handler->cluster);
if (err < 0) {
rados_shutdown(handler->cluster);
free(handler);
return NULL;
}
err = rados_ioctx_create(handler->cluster, poolname, &handler->io);
if (err < 0) {
rados_shutdown(handler->cluster);
free(handler);
return NULL;
}
handler->objname = strdup(objname);
if (!handler->objname) {
rados_ioctx_destroy(handler->io);
rados_shutdown(handler->cluster);
free(handler);
return NULL;
}
handler->off = 0;
return handler;
}
void ceph_handler_destroy(struct ceph_handler *handler)
{
rados_ioctx_destroy(handler->io);
rados_shutdown(handler->cluster);
free(handler->objname);
free(handler);
}
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
{
struct ceph_handler *handler = opaque;
int nr;
nr = rados_read(handler->io, handler->objname, (char *)buf, buf_size, handler->off);
if (nr < 0)
errno = -nr;
else
handler->off += nr;
return nr;
}
static int write_packet(void *opaque, uint8_t *buf, int buf_size)
{
struct ceph_handler *handler = opaque;
int err;
/* 成功时返回0,而非写入字节数 */
err = rados_write(handler->io, handler->objname, (char *)buf, buf_size, handler->off);
if (err)
errno = - err;
else
handler->off += buf_size;
return err ? err : buf_size;
}
static int64_t seek(void *opaque, int64_t offset, int whence)
{
struct ceph_handler *handler = opaque;
uint64_t size;
time_t mtime;
int err;
switch (whence) {
case SEEK_SET:
handler->off = offset;
break;
case SEEK_CUR:
handler->off += offset;
break;
case SEEK_END:
err = rados_stat(handler->io, handler->objname, &size, &mtime);
if (err < 0) {
errno = - err;
return -1;
}
if (size < offset)
handler->off = 0;
else
handler->off = size - offset;
}
return handler->off;
}
static int open_input_file(const char *filename)
{
AVIOContext *avio_ctx = NULL;
uint8_t *avio_ctx_buffer = NULL;
size_t avio_ctx_buffer_size = 1 << 2;
struct ceph_handler *handler = NULL;
unsigned int i;
int ret;
ifmt_ctx = NULL;
handler = ceph_handler_create("ceph", "client.admin", 0,
"ceph.conf", "mypool", filename);
if (!handler)
return -1;
ifmt_ctx = avformat_alloc_context();
if (!ifmt_ctx)
goto err;
avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);
if (!avio_ctx_buffer)
goto err;
avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,
0, handler, read_packet, write_packet,
seek);
if (!avio_ctx)
goto err;
ifmt_ctx->pb = avio_ctx;
ret = avformat_open_input(&ifmt_ctx, NULL, NULL, NULL);
if (ret < 0)
goto err;
ret = avformat_find_stream_info(ifmt_ctx, NULL);
if (ret < 0)
goto err;
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
AVStream *stream;
AVCodecContext *codec_ctx;
stream = ifmt_ctx->streams;
codec_ctx = stream->codec;
/* Reencode video & audio and remux subtitles etc. */
if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
/* Open decoder */
ret = avcodec_open2(codec_ctx,
avcodec_find_decoder(codec_ctx->codec_id), NULL);
if (ret < 0)
goto err;
}
}
av_dump_format(ifmt_ctx, 0, filename, 0);
return 0;
err:
if (ifmt_ctx)
avformat_close_input(&ifmt_ctx);
ifmt_ctx = NULL;
if (handler)
ceph_handler_destroy(handler);
if (avio_ctx) {
av_freep(&avio_ctx->buffer);
av_freep(&avio_ctx);
}
return -1;
}
找方法了,在学习雷大的教程的时候,看到了相关介绍:http://blog.csdn.net/leixiaohua1020/article/details/39759623
和读的方法很相似,但是注意必须提供seek和write,否则有的视频编码会失败。看来ffmpeg没举输出流的例子,是觉得没有必要,归根结底还是自身水平太低,需要不断学习、练习和归纳总结{:qq9:}
页:
[1]