133 lines
2.8 KiB
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;
|
|
}
|