Successfully encoded an mp3 with test_encode.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,4 +1,6 @@
|
|||||||
tcfs
|
tcfs
|
||||||
|
test_encode
|
||||||
|
*.mp3
|
||||||
*.o
|
*.o
|
||||||
*~
|
*~
|
||||||
testmnt/
|
testmnt/
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
bin_PROGRAMS=tcfs
|
bin_PROGRAMS=tcfs test_encode
|
||||||
tcfs_SOURCES=src/tcfs.c src/transcode.c src/util.c
|
tcfs_SOURCES=src/tcfs.c src/transcode.c src/decode.c src/encode.c src/util.c src/tcfs_buf.c
|
||||||
tcfs_LDADD = $(LIBOBJS) $(FUSE_LIBS) $(libavcore_LIBS) $(libavutil_LIBS) $(libavformat_LIBS) $(libavcodec_LIBS)
|
tcfs_LDADD = $(LIBOBJS) $(FUSE_LIBS) $(libavcore_LIBS) $(libavutil_LIBS) $(libavformat_LIBS) $(libavcodec_LIBS)
|
||||||
tcfs_CFLAGS = $(FUSE_CFLAGS) $(libavcore_CFLAGS) $(libavutil_CFLAGS) $(libavformat_CFLAGS) $(libavcodec_CFLAGS) -DFUSE_USE_VERSION=28
|
tcfs_CFLAGS = $(FUSE_CFLAGS) $(libavcore_CFLAGS) $(libavutil_CFLAGS) $(libavformat_CFLAGS) $(libavcodec_CFLAGS) -DFUSE_USE_VERSION=28
|
||||||
|
test_encode_SOURCES=src/decode.c src/encode.c src/tcfs_buf.c src/util.c src/test_encode.c
|
||||||
|
test_encode_LDADD = $(LIBOBJS) $(libavcore_LIBS) $(libavutil_LIBS) $(libavformat_LIBS) $(libavcodec_LIBS)
|
||||||
|
test_encode_CFLAGS = $(libavcore_CFLAGS) $(libavutil_CFLAGS) $(libavformat_CFLAGS) $(libavcodec_CFLAGS)
|
||||||
@@ -62,5 +62,6 @@
|
|||||||
#include <libavutil/avutil.h>
|
#include <libavutil/avutil.h>
|
||||||
#include <libavcodec/avcodec.h>
|
#include <libavcodec/avcodec.h>
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavformat/avio.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
132
src/decode.c
Normal file
132
src/decode.c
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
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;
|
||||||
|
}
|
||||||
16
src/decode.h
Normal file
16
src/decode.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2010 Matthias Blankertz <matthias@blankertz.org>
|
||||||
|
|
||||||
|
This work is licensed under the Open Software License ("OSL") v. 3.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TCFS_DECODE_H
|
||||||
|
#define TCFS_DECODE_H 1
|
||||||
|
|
||||||
|
struct decode_ctx;
|
||||||
|
|
||||||
|
struct decode_ctx *decode_open(const char *src);
|
||||||
|
int decode_read(char *buf, size_t size, struct decode_ctx *fd);
|
||||||
|
int decode_close(struct decode_ctx *fd);
|
||||||
|
|
||||||
|
#endif
|
||||||
50
src/encode.c
Normal file
50
src/encode.c
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
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 encode_ctx {
|
||||||
|
AVFormatContext *avfctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct encode_ctx *encode_open(const char *tfmt)
|
||||||
|
{
|
||||||
|
struct encode_ctx *ctx = (struct encode_ctx*)malloc(sizeof(struct encode_ctx));
|
||||||
|
if(!ctx) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->avfctx = avformat_alloc_context();
|
||||||
|
if(!ctx->avfctx) {
|
||||||
|
free(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
URLContext *urlctx;
|
||||||
|
if((ret = url_open_protocol(&urlctx, tcfs_buf_get_protocol(), "", 0)) != 0) {
|
||||||
|
char err[512];
|
||||||
|
av_strerror(ret, err, 512);
|
||||||
|
fprintf(stderr, "ffmpeg error: %s\n", err);
|
||||||
|
free(ctx->avfctx);
|
||||||
|
free(ctx);
|
||||||
|
errno = EIO;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = url_fdopen(&ctx->avfctx->pb, urlctx)) != 0) {
|
||||||
|
char err[512];
|
||||||
|
av_strerror(ret, err, 512);
|
||||||
|
fprintf(stderr, "ffmpeg error: %s\n", err);
|
||||||
|
free(ctx->avfctx);
|
||||||
|
free(ctx);
|
||||||
|
errno = EIO;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
14
src/encode.h
Normal file
14
src/encode.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2010 Matthias Blankertz <matthias@blankertz.org>
|
||||||
|
|
||||||
|
This work is licensed under the Open Software License ("OSL") v. 3.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TCFS_ENCODE_H
|
||||||
|
#define TCFS_ENCODE_H 1
|
||||||
|
|
||||||
|
struct encode_ctx;
|
||||||
|
|
||||||
|
struct encode_ctx *encode_open(const char *tfmt);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "transcode.h"
|
#include "transcode.h"
|
||||||
|
#include "tcfs_buf.h"
|
||||||
|
|
||||||
#include <fuse.h>
|
#include <fuse.h>
|
||||||
#include <fuse_opt.h>
|
#include <fuse_opt.h>
|
||||||
@@ -101,7 +102,7 @@ int tcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
|||||||
if(ret == 0)
|
if(ret == 0)
|
||||||
filler(buf, dep->d_name, NULL, 0);
|
filler(buf, dep->d_name, NULL, 0);
|
||||||
else {
|
else {
|
||||||
char *ext = strchr(dep->d_name, '.');
|
char *ext = strrchr(dep->d_name, '.');
|
||||||
char *file_new_ext;
|
char *file_new_ext;
|
||||||
if(ext == NULL) {
|
if(ext == NULL) {
|
||||||
if(asprintf(&file_new_ext, "%s.%s", dep->d_name, options.tfmt) < 0) {
|
if(asprintf(&file_new_ext, "%s.%s", dep->d_name, options.tfmt) < 0) {
|
||||||
@@ -243,5 +244,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
av_register_all();
|
av_register_all();
|
||||||
|
|
||||||
|
tcfs_buf_register();
|
||||||
|
|
||||||
return fuse_main(args.argc, args.argv, &tcfs_oper, NULL);
|
return fuse_main(args.argc, args.argv, &tcfs_oper, NULL);
|
||||||
}
|
}
|
||||||
|
|||||||
46
src/tcfs_buf.c
Normal file
46
src/tcfs_buf.c
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2010 Matthias Blankertz <matthias@blankertz.org>
|
||||||
|
|
||||||
|
This work is licensed under the Open Software License ("OSL") v. 3.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
int tcfs_buf_open(URLContext *h, const char *url, int flags)
|
||||||
|
{
|
||||||
|
return AVERROR_NOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tcfs_buf_read(URLContext *h, unsigned char *buf, int size)
|
||||||
|
{
|
||||||
|
return AVERROR_NOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tcfs_buf_write(URLContext *h, const unsigned char *buf, int size)
|
||||||
|
{
|
||||||
|
return AVERROR_NOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tcfs_buf_get_handle(URLContext *h)
|
||||||
|
{
|
||||||
|
return AVERROR_NOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
URLProtocol tcfs_buf_protocol = {
|
||||||
|
"tcfs_buf",
|
||||||
|
tcfs_buf_open,
|
||||||
|
tcfs_buf_read,
|
||||||
|
tcfs_buf_write,
|
||||||
|
.url_get_file_handle = tcfs_buf_get_handle
|
||||||
|
};
|
||||||
|
|
||||||
|
void tcfs_buf_register()
|
||||||
|
{
|
||||||
|
av_register_protocol2(&tcfs_buf_protocol, sizeof(URLProtocol));
|
||||||
|
}
|
||||||
|
|
||||||
|
URLProtocol *tcfs_buf_get_protocol()
|
||||||
|
{
|
||||||
|
return &tcfs_buf_protocol;
|
||||||
|
}
|
||||||
13
src/tcfs_buf.h
Normal file
13
src/tcfs_buf.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2010 Matthias Blankertz <matthias@blankertz.org>
|
||||||
|
|
||||||
|
This work is licensed under the Open Software License ("OSL") v. 3.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TCFS_BUF_H
|
||||||
|
#define TCFS_BUF_H 1
|
||||||
|
|
||||||
|
void tcfs_buf_register();
|
||||||
|
URLProtocol *tcfs_buf_get_protocol();
|
||||||
|
|
||||||
|
#endif
|
||||||
173
src/test_encode.c
Normal file
173
src/test_encode.c
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2010 Matthias Blankertz <matthias@blankertz.org>
|
||||||
|
|
||||||
|
This work is licensed under the Open Software License ("OSL") v. 3.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "encode.h"
|
||||||
|
|
||||||
|
struct options options = {
|
||||||
|
"testbase",
|
||||||
|
"mp3"
|
||||||
|
};
|
||||||
|
static void choose_sample_fmt(AVStream *st, AVCodec *codec)
|
||||||
|
{
|
||||||
|
if(codec && codec->sample_fmts){
|
||||||
|
const enum SampleFormat *p= codec->sample_fmts;
|
||||||
|
for(; *p!=-1; p++){
|
||||||
|
if(*p == st->codec->sample_fmt)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(*p == -1)
|
||||||
|
st->codec->sample_fmt = codec->sample_fmts[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void choose_sample_rate(AVStream *st, AVCodec *codec)
|
||||||
|
{
|
||||||
|
if(codec && codec->supported_samplerates){
|
||||||
|
const int *p= codec->supported_samplerates;
|
||||||
|
int best=0;
|
||||||
|
int best_dist=INT_MAX;
|
||||||
|
for(; *p; p++){
|
||||||
|
int dist= abs(st->codec->sample_rate - *p);
|
||||||
|
if(dist < best_dist){
|
||||||
|
best_dist= dist;
|
||||||
|
best= *p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(best_dist){
|
||||||
|
av_log(st->codec, AV_LOG_WARNING, "Requested sampling rate unsupported using closest supported (%d)\n", best);
|
||||||
|
}
|
||||||
|
st->codec->sample_rate= best;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
av_register_all();
|
||||||
|
|
||||||
|
tcfs_buf_register();
|
||||||
|
|
||||||
|
struct decode_ctx *decode = decode_open("testbase/fmc/Sinn/01 - Das frivole Burgfräulein - Erwachsen.ogg");
|
||||||
|
if(!decode) {
|
||||||
|
printf("Can't decode source.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVFormatContext *avfctx = avformat_alloc_context();
|
||||||
|
if(!avfctx) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
AVOutputFormat *ofmt;
|
||||||
|
ofmt = av_guess_format(NULL, "test.mp3", NULL);
|
||||||
|
if(!ofmt) {
|
||||||
|
printf("Can't find output format.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
avfctx->oformat = ofmt;
|
||||||
|
|
||||||
|
AVStream *st = av_new_stream(avfctx, 0);
|
||||||
|
if(!st) {
|
||||||
|
printf("Can't allocate stream.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CodecID codecid = av_guess_codec(ofmt, NULL, "test.mp3", NULL, AVMEDIA_TYPE_AUDIO);
|
||||||
|
AVCodec *codec = avcodec_find_encoder(codecid);
|
||||||
|
if(!codec) {
|
||||||
|
printf("Can't get codec.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
avcodec_get_context_defaults3(st->codec, codec);
|
||||||
|
|
||||||
|
//avcodec_thread_init(st->codec, 1);
|
||||||
|
|
||||||
|
// st->codec->codec = codec;
|
||||||
|
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||||
|
st->codec->codec_id = codecid;
|
||||||
|
st->codec->channels = 2;
|
||||||
|
st->codec->sample_fmt = AV_SAMPLE_FMT_S16;
|
||||||
|
st->codec->sample_rate = 44100;
|
||||||
|
st->codec->channel_layout = 0;
|
||||||
|
st->codec->flags |= CODEC_FLAG_QSCALE;
|
||||||
|
st->codec->global_quality = st->quality = 5;
|
||||||
|
st->codec->time_base = (AVRational){1, 44100};
|
||||||
|
choose_sample_fmt(st, codec);
|
||||||
|
choose_sample_rate(st, codec);
|
||||||
|
|
||||||
|
if((ret=avcodec_open(st->codec, codec)) < 0) {
|
||||||
|
char err[512];
|
||||||
|
av_strerror(ret, err, 512);
|
||||||
|
fprintf(stderr, "ffmpeg error: %s\n", err);
|
||||||
|
free(avfctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = url_fopen(&avfctx->pb, "file:///home/matthias/devel/tcfs/test.mp3", URL_WRONLY)) != 0) {
|
||||||
|
char err[512];
|
||||||
|
av_strerror(ret, err, 512);
|
||||||
|
fprintf(stderr, "ffmpeg error: %s\n", err);
|
||||||
|
free(avfctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = av_write_header(avfctx)) != 0) {
|
||||||
|
char err[512];
|
||||||
|
av_strerror(ret, err, 512);
|
||||||
|
fprintf(stderr, "ffmpeg error: %s\n", err);
|
||||||
|
free(avfctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
short *ibuf = (short*)malloc(sizeof(short)*st->codec->frame_size*st->codec->channels);
|
||||||
|
if(!ibuf) {
|
||||||
|
printf("No memory.\n");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
memset(ibuf, 0, sizeof(short)*st->codec->frame_size*st->codec->channels);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t obuf[4096];
|
||||||
|
int done = 0;
|
||||||
|
while(!done) {
|
||||||
|
memset(ibuf, 0, sizeof(short)*st->codec->frame_size*st->codec->channels);
|
||||||
|
ret = decode_read(ibuf, sizeof(short)*st->codec->frame_size*st->codec->channels, decode);
|
||||||
|
if(ret != sizeof(short)*st->codec->frame_size*st->codec->channels)
|
||||||
|
done = 1;
|
||||||
|
if((ret = avcodec_encode_audio(st->codec, obuf, 4096, ibuf)) < 0) {
|
||||||
|
char err[512];
|
||||||
|
av_strerror(ret, err, 512);
|
||||||
|
fprintf(stderr, "ffmpeg error: %s\n", err);
|
||||||
|
free(avfctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(ret != 0) {
|
||||||
|
AVPacket pack;
|
||||||
|
av_new_packet(&pack, ret);
|
||||||
|
memcpy(pack.data, obuf, ret);
|
||||||
|
|
||||||
|
av_write_frame(avfctx, &pack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = av_write_trailer(avfctx)) != 0) {
|
||||||
|
char err[512];
|
||||||
|
av_strerror(ret, err, 512);
|
||||||
|
fprintf(stderr, "ffmpeg error: %s\n", err);
|
||||||
|
free(avfctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// url_fclose(&avfctx->pb);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -5,17 +5,26 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "decode.h"
|
||||||
|
#include "encode.h"
|
||||||
|
|
||||||
struct TC_FILE {
|
struct TC_FILE {
|
||||||
|
struct decode_ctx *decode;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TC_FILE *tc_open(const char *src, const char *tfmt)
|
struct TC_FILE *tc_open(const char *src, const char *tfmt)
|
||||||
{
|
{
|
||||||
|
struct TC_FILE *fd = (struct TC_FILE*)malloc(sizeof(struct TC_FILE));
|
||||||
|
if(!fd) {
|
||||||
|
errno = ENOMEM;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tc_read(char *buf, size_t size, struct TC_FILE *fd)
|
fd->decode = decode_open(src);
|
||||||
{
|
if(!fd->decode) {
|
||||||
errno = ENOSYS;
|
free(fd);
|
||||||
return 0;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,5 +11,6 @@ struct TC_FILE;
|
|||||||
|
|
||||||
struct TC_FILE *tc_open(const char *src, const char *tfmt);
|
struct TC_FILE *tc_open(const char *src, const char *tfmt);
|
||||||
int tc_read(char *buf, size_t size, struct TC_FILE *fd);
|
int tc_read(char *buf, size_t size, struct TC_FILE *fd);
|
||||||
|
int tc_close(struct TC_FILE *fd);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
92
src/util.c
92
src/util.c
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "decode.h"
|
||||||
|
|
||||||
// Get the filename from a path, i.e. a pointer to the character after the last / in path.
|
// Get the filename from a path, i.e. a pointer to the character after the last / in path.
|
||||||
// If path contains no /, returns path.
|
// If path contains no /, returns path.
|
||||||
@@ -14,7 +15,7 @@ const char *get_file_from_path(const char *path)
|
|||||||
if(!path)
|
if(!path)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
char *ret = strchr(path, '/');
|
char *ret = strrchr(path, '/');
|
||||||
if(ret == NULL)
|
if(ret == NULL)
|
||||||
return path;
|
return path;
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ const char *get_ext_from_file(const char *file)
|
|||||||
if(!file)
|
if(!file)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
char *ret = strchr(file, '.');
|
char *ret = strrchr(file, '.');
|
||||||
if(!ret)
|
if(!ret)
|
||||||
return file+strlen(file);
|
return file+strlen(file);
|
||||||
if(ret == file)
|
if(ret == file)
|
||||||
@@ -43,8 +44,8 @@ char *strip_ext_from_path(const char *path)
|
|||||||
|
|
||||||
char *ret = strdup(path);
|
char *ret = strdup(path);
|
||||||
|
|
||||||
char *ext = strchr(ret, '.');
|
char *ext = strrchr(ret, '.');
|
||||||
char *file = strchr(ret, '/');
|
char *file = strrchr(ret, '/');
|
||||||
if(!ext || (ext<file)) // no . or . not in last component
|
if(!ext || (ext<file)) // no . or . not in last component
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -52,6 +53,23 @@ char *strip_ext_from_path(const char *path)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *strip_file_from_path(const char *path)
|
||||||
|
{
|
||||||
|
if(!path)
|
||||||
|
return NULL;
|
||||||
|
char *ret = strdup(path);
|
||||||
|
|
||||||
|
char *file = strrchr(ret, '/');
|
||||||
|
if(!file) {
|
||||||
|
ret[0] = '/';
|
||||||
|
ret[1] = '\0';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
*(file+1) = '\0';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// returns 1 if the file is a transcodeable audio file, 0 if it is not and a negative value if an error occured
|
// returns 1 if the file is a transcodeable audio file, 0 if it is not and a negative value if an error occured
|
||||||
int is_tc_audio_file(const char *path)
|
int is_tc_audio_file(const char *path)
|
||||||
{
|
{
|
||||||
@@ -77,11 +95,12 @@ int is_tc_audio_file(const char *path)
|
|||||||
if(strcmp(ext,options.tfmt) == 0)
|
if(strcmp(ext,options.tfmt) == 0)
|
||||||
return 0; // file already has right format
|
return 0; // file already has right format
|
||||||
|
|
||||||
// TODO: proper detection code here
|
// try to open file as transcode source
|
||||||
|
struct decode_ctx *tcfd = decode_open(path);
|
||||||
// for testing
|
if(tcfd) {
|
||||||
if(strcmp(ext,"ogg") == 0)
|
decode_close(tcfd);
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -98,18 +117,59 @@ char *get_tc_source_name(const char *path)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *path_no_ext = strip_ext_from_path(path);
|
char *file_no_ext = strip_ext_from_path(get_file_from_path(path));
|
||||||
if(!path_no_ext)
|
if(!file_no_ext)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// TODO : search for transcodable files in path_no_ext.*
|
char *dir_name = strip_file_from_path(path);
|
||||||
|
if(!dir_name) {
|
||||||
// for testing
|
free(file_no_ext);
|
||||||
char *ret;
|
|
||||||
if(asprintf(&ret, "%s.ogg", path_no_ext) < 0)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
DIR *dir = opendir(dir_name);
|
||||||
|
if(!dir) {
|
||||||
|
free(file_no_ext);
|
||||||
|
free(dir_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct dirent de;
|
||||||
|
char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
|
||||||
|
} u;
|
||||||
|
struct dirent *dep;
|
||||||
|
while(readdir_r(dir, &u.de, &dep) == 0) {
|
||||||
|
if(!dep) {
|
||||||
|
free(file_no_ext);
|
||||||
|
free(dir_name);
|
||||||
|
closedir(dir);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
char *de_no_ext = strip_ext_from_path(dep->d_name);
|
||||||
|
if(strcmp(de_no_ext, file_no_ext) == 0) {
|
||||||
|
char *de_with_path;
|
||||||
|
if(asprintf(&de_with_path, "%s%s", dir_name, dep->d_name) < 0) {
|
||||||
|
free(file_no_ext);
|
||||||
|
free(dir_name);
|
||||||
|
free(de_no_ext);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(is_tc_audio_file(de_with_path) > 0) {
|
||||||
|
free(file_no_ext);
|
||||||
|
free(dir_name);
|
||||||
|
free(de_no_ext);
|
||||||
|
return de_with_path;
|
||||||
|
}
|
||||||
|
free(de_with_path);
|
||||||
|
}
|
||||||
|
free(de_no_ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(file_no_ext);
|
||||||
|
free(dir_name);
|
||||||
|
closedir(dir);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// safely concatenate options.base and path
|
// safely concatenate options.base and path
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ extern struct options options;
|
|||||||
const char *get_file_from_path(const char *path);
|
const char *get_file_from_path(const char *path);
|
||||||
const char *get_ext_from_file(const char *file);
|
const char *get_ext_from_file(const char *file);
|
||||||
char *strip_ext_from_path(const char *path);
|
char *strip_ext_from_path(const char *path);
|
||||||
|
char *strip_file_from_path(const char *path);
|
||||||
int is_tc_audio_file(const char *path);
|
int is_tc_audio_file(const char *path);
|
||||||
char *get_tc_source_name(const char *path);
|
char *get_tc_source_name(const char *path);
|
||||||
char *path_cat(const char *path);
|
char *path_cat(const char *path);
|
||||||
|
|||||||
Reference in New Issue
Block a user