Files
tcfs/src/decode.c

133 lines
2.8 KiB
C

/*
Copyright (c) 2010 Matthias Blankertz <matthias@blankertz.org>
This work is licensed under the Open Software License ("OSL") v. 3.0.
*/
#include "common.h"
struct decode_ctx {
AVFormatContext *avfctx;
int stream;
AVCodec *avc;
char *bod;
int len, offs;
};
struct decode_ctx *decode_open(const char *src)
{
struct decode_ctx *fd = (struct decode_ctx*)malloc(sizeof(struct decode_ctx));
if(!fd)
return NULL;
int ret;
if((ret = av_open_input_file(&fd->avfctx, src, NULL, 0, NULL)) != 0) {
char err[512];
av_strerror(ret, err, 512);
fprintf(stderr, "ffmpeg error: %s\n", err);
free(fd);
errno = EIO;
return NULL;
}
if((ret = av_find_stream_info(fd->avfctx)) < 0) {
char err[512];
av_strerror(ret, err, 512);
fprintf(stderr, "ffmpeg error: %s\n", err);
av_close_input_file(fd->avfctx);
free(fd);
errno = EIO;
return NULL;
}
dump_format(fd->avfctx, 0, src, 0);
int i;
for(i = 0;i < fd->avfctx->nb_streams;++i) {
if(fd->avfctx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO)
break;
}
if(i == fd->avfctx->nb_streams) {
// no audio stream
av_close_input_file(fd->avfctx);
free(fd);
errno = EIO;
return NULL;
}
fd->stream = i;
fd->avc = avcodec_find_decoder(fd->avfctx->streams[fd->stream]->codec->codec_id);
if(!fd->avc) {
fprintf(stderr, "ffmpeg error: Could not find decoder.\n");
av_close_input_file(fd->avfctx);
free(fd);
errno = EIO;
return NULL;
}
if((ret = avcodec_open(fd->avfctx->streams[fd->stream]->codec, fd->avc)) < 0) {
char err[512];
av_strerror(ret, err, 512);
fprintf(stderr, "ffmpeg error: %s\n", err);
av_close_input_file(fd->avfctx);
free(fd);
errno = EIO;
return NULL;
}
fd->bod = malloc(128*1024*1024);
if(!fd->bod)
return NULL;
AVPacket pack;
int pos = 0;
int fsp = 128*1024*1024;
while(av_read_frame(fd->avfctx, &pack) == 0) {
if(pack.stream_index == fd->stream) {
if(avcodec_decode_audio3(fd->avfctx->streams[fd->stream]->codec, fd->bod+pos, &fsp, &pack) < 0) {
printf("Decode error.\n");
return NULL;
}
pos += fsp;
fsp = 128*1024*1024-pos;
}
}
fd->len = pos;
fd->offs = 0;
return fd;
}
int decode_read(char *buf, size_t size, struct decode_ctx *fd)
{
if(size < fd->len-fd->offs) {
memcpy(buf, fd->bod+fd->offs, size);
fd->offs += size;
return size;
} else {
memcpy(buf, fd->bod+fd->offs, fd->len-fd->offs);
int ret = fd->len - fd->offs;
fd->offs = fd->len;
return ret;
}
}
int decode_close(struct decode_ctx *fd)
{
if(!fd) {
errno = EINVAL;
return -1;
}
if(!fd->avfctx || !fd->avc) {
free(fd);
return 0;
}
free(fd->bod);
avcodec_close(fd->avfctx->streams[fd->stream]->codec);
av_close_input_file(fd->avfctx);
free(fd);
return 0;
}