- Added LAME mp3 encode module
- Redesigned encode/decode API - misc. changes and debugging
This commit is contained in:
21
Makefile.am
21
Makefile.am
@@ -1,7 +1,18 @@
|
||||
bin_PROGRAMS=tcfs test_encode
|
||||
tcfs_SOURCES=src/tcfs.c src/transcode.c src/decode.c src/encode.c src/util.c src/tcfs_buf.c src/decode-ffmpeg.c src/encode-ffmpeg.c
|
||||
bin_PROGRAMS=tcfs
|
||||
|
||||
tcfs_SOURCES = src/tcfs.c src/transcode.c src/decode.c src/encode.c src/util.c src/tcfs_buf.c src/decode-ffmpeg.c src/encode-ffmpeg.c
|
||||
if MP3LAME
|
||||
tcfs_SOURCES += src/encode-mp3lame.c
|
||||
endif
|
||||
tcfs_LDADD = $(LIBOBJS) $(FUSE_LIBS) $(libavcore_LIBS) $(libavutil_LIBS) $(libavformat_LIBS) $(libavcodec_LIBS)
|
||||
if MP3LAME
|
||||
tcfs_LDADD += -lmp3lame
|
||||
endif
|
||||
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 src/decode-ffmpeg.c src/encode-ffmpeg.c
|
||||
test_encode_LDADD = $(LIBOBJS) $(libavcore_LIBS) $(libavutil_LIBS) $(libavformat_LIBS) $(libavcodec_LIBS)
|
||||
test_encode_CFLAGS = $(libavcore_CFLAGS) $(libavutil_CFLAGS) $(libavformat_CFLAGS) $(libavcodec_CFLAGS)
|
||||
if MP3LAME
|
||||
tcfs_CFLAGS += -I/usr/include/lame -DHAVE_LIBMP3LAME
|
||||
endif
|
||||
|
||||
#test_encode_SOURCES = src/decode.c src/encode.c src/tcfs_buf.c src/util.c src/test_encode.c src/decode-ffmpeg.c src/encode-ffmpeg.c
|
||||
#test_encode_LDADD = $(LIBOBJS) $(libavcore_LIBS) $(libavutil_LIBS) $(libavformat_LIBS) $(libavcodec_LIBS)
|
||||
#test_encode_CFLAGS = $(libavcore_CFLAGS) $(libavutil_CFLAGS) $(libavformat_CFLAGS) $(libavcodec_CFLAGS)
|
||||
13
configure.ac
13
configure.ac
@@ -16,9 +16,11 @@ PKG_CHECK_MODULES([libavcodec], [libavcodec >= 52.94])
|
||||
PKG_CHECK_MODULES([libavformat], [libavformat >= 52.84])
|
||||
PKG_CHECK_MODULES([libavcore], [libavcore >= 0.12])
|
||||
PKG_CHECK_MODULES([libavutil], [libavutil >= 50.32])
|
||||
PKG_CHECK_MODULES([taglib_c], [taglib_c >= 1.7])
|
||||
|
||||
|
||||
# Checks for header files.
|
||||
AC_CHECK_HEADERS([fcntl.h stddef.h stdlib.h string.h errno.h dirent.h])
|
||||
AC_CHECK_HEADERS([fcntl.h stddef.h stdlib.h string.h errno.h dirent.h assert.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_PROG_CC_C99
|
||||
@@ -29,5 +31,14 @@ AX_TLS
|
||||
AC_CHECK_FUNCS([memset strerror])
|
||||
AC_CHECK_FUNCS([asprintf], [], [AC_MSG_ERROR([asprintf emulation for non-GNU systems NYI])])
|
||||
|
||||
# Check for optional encoders
|
||||
# libmp3lame
|
||||
AC_ARG_ENABLE(mp3lame, [ --enable-mp3lame Enable support for MP3 encoding with libmp3lame],
|
||||
[AC_CHECK_LIB(mp3lame, get_lame_version, [mp3lame=true], [AC_MSG_WARN([libmp3lame not found]);mp3lame=false])]
|
||||
[]
|
||||
)
|
||||
AM_CONDITIONAL([MP3LAME], [test x$mp3lame = xtrue])
|
||||
|
||||
# finish
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -58,6 +58,10 @@
|
||||
# include <dirent.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ASSERT_H
|
||||
# include <assert.h>
|
||||
#endif
|
||||
|
||||
#include <libavcore/avcore.h>
|
||||
#include <libavutil/avutil.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
|
||||
@@ -14,12 +14,12 @@ struct decode_ffmpeg_ctx
|
||||
AVFormatContext *avfctx;
|
||||
int stream;
|
||||
AVCodec *avc;
|
||||
char *bod;
|
||||
int16_t *bod;
|
||||
int len, offs;
|
||||
void *metadata;
|
||||
};
|
||||
|
||||
struct decode_ctx *decode_ffmpeg_open(const char *src);
|
||||
struct decode_ctx *decode_ffmpeg_open(const char *src, struct source_info *src_info);
|
||||
int decode_ffmpeg_read(void *buf, size_t size, struct decode_ctx *fd);
|
||||
int decode_ffmpeg_close(struct decode_ctx *fd);
|
||||
|
||||
@@ -29,7 +29,7 @@ struct decode_ops decode_ffmpeg_ops = {
|
||||
decode_ffmpeg_close
|
||||
};
|
||||
|
||||
struct decode_ctx *decode_ffmpeg_open(const char *src)
|
||||
struct decode_ctx *decode_ffmpeg_open(const char *src, struct source_info *src_info)
|
||||
{
|
||||
struct decode_ctx *fd = (struct decode_ctx*)malloc(sizeof(struct decode_ctx)+sizeof(struct decode_ffmpeg_ctx));
|
||||
if(!fd)
|
||||
@@ -105,24 +105,28 @@ struct decode_ctx *decode_ffmpeg_open(const char *src)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->bod = malloc(128*1024*1024);
|
||||
ctx->bod = (int16_t*)malloc(128*1024*1024);
|
||||
if(!ctx->bod) {
|
||||
tcfs_errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
src_info->sample_rate = ctx->avfctx->streams[ctx->stream]->codec->sample_rate;
|
||||
src_info->channels = ctx->avfctx->streams[ctx->stream]->codec->channels;
|
||||
src_info->depth = 16;
|
||||
|
||||
AVPacket pack;
|
||||
int pos = 0;
|
||||
int fsp = 128*1024*1024;
|
||||
while(av_read_frame(ctx->avfctx, &pack) == 0) {
|
||||
if(pack.stream_index == ctx->stream) {
|
||||
if(avcodec_decode_audio3(ctx->avfctx->streams[ctx->stream]->codec,
|
||||
(int16_t*)(ctx->bod+pos), &fsp, &pack) < 0) {
|
||||
ctx->bod+pos, &fsp, &pack) < 0) {
|
||||
printf("Decode error.\n");
|
||||
return NULL;
|
||||
}
|
||||
pos += fsp;
|
||||
fsp = 128*1024*1024-pos;
|
||||
pos += fsp/sizeof(int16_t);
|
||||
fsp = 128*1024*1024-pos*sizeof(int16_t);
|
||||
}
|
||||
}
|
||||
ctx->len = pos;
|
||||
@@ -140,12 +144,14 @@ int decode_ffmpeg_read(void *buf, size_t size, struct decode_ctx *fd)
|
||||
|
||||
struct decode_ffmpeg_ctx *ctx = (struct decode_ffmpeg_ctx*)(fd+1);
|
||||
|
||||
if(size < ctx->len-ctx->offs) {
|
||||
memcpy(buf, ctx->bod+ctx->offs, size);
|
||||
if(ctx->offs == ctx->len) { // EOF
|
||||
return 0;
|
||||
} else if(size < ctx->len-ctx->offs) {
|
||||
memcpy(buf, ctx->bod+ctx->offs, size*sizeof(int16_t));
|
||||
ctx->offs += size;
|
||||
return size;
|
||||
} else {
|
||||
memcpy(buf, ctx->bod+ctx->offs, ctx->len-ctx->offs);
|
||||
memcpy(buf, ctx->bod+ctx->offs, (ctx->len-ctx->offs)*sizeof(int16_t));
|
||||
int ret = ctx->len - ctx->offs;
|
||||
ctx->offs = ctx->len;
|
||||
return ret;
|
||||
|
||||
@@ -9,17 +9,18 @@
|
||||
#include "decode.h"
|
||||
#include "decode-ffmpeg.h"
|
||||
|
||||
struct decoders_entry decoders[] = {
|
||||
const struct decoders_entry decoders[] = {
|
||||
{&decode_ffmpeg_ops, "ffmpeg"},
|
||||
{NULL, ""}
|
||||
};
|
||||
|
||||
struct decode_ctx *decode_open(const char *src)
|
||||
struct decode_ctx *decode_open(const char *src, struct source_info *src_info)
|
||||
{
|
||||
struct decode_ctx *ctx;
|
||||
int i = 0;
|
||||
while(decoders[i].ops) {
|
||||
ctx = decoders[i++].ops->open(src);
|
||||
assert(decoders[i].ops->open != NULL);
|
||||
ctx = decoders[i++].ops->open(src, src_info);
|
||||
if(!ctx) { // open failed
|
||||
if(tcfs_errno == ECODEC) // the codec doesn't support this file, try the next one
|
||||
continue;
|
||||
@@ -33,7 +34,7 @@ struct decode_ctx *decode_open(const char *src)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int decode_read(char *buf, size_t size, struct decode_ctx *fd)
|
||||
int decode_read(void *buf, size_t size, struct decode_ctx *fd)
|
||||
{
|
||||
if(!fd) {
|
||||
tcfs_errno = EINVAL;
|
||||
|
||||
12
src/decode.h
12
src/decode.h
@@ -7,25 +7,27 @@
|
||||
#ifndef TCFS_DECODE_H
|
||||
#define TCFS_DECODE_H 1
|
||||
|
||||
#include "util.h"
|
||||
|
||||
struct decode_ctx {
|
||||
struct decode_ops *ops;
|
||||
};
|
||||
|
||||
struct decode_ops {
|
||||
struct decode_ctx *(*open)(const char *src);
|
||||
struct decode_ctx *(*open)(const char *src, struct source_info *src_info);
|
||||
int (*read)(void *buf, size_t size, struct decode_ctx *fd);
|
||||
int (*close)(struct decode_ctx *fd);
|
||||
};
|
||||
|
||||
struct decoders_entry {
|
||||
struct decode_ops *ops;
|
||||
char name[];
|
||||
char name[TCFS_MAX_NAME_LENGTH];
|
||||
};
|
||||
|
||||
extern struct decoders_entry decoders[];
|
||||
extern const struct decoders_entry decoders[];
|
||||
|
||||
struct decode_ctx *decode_open(const char *src);
|
||||
int decode_read(char *buf, size_t size, struct decode_ctx *fd);
|
||||
struct decode_ctx *decode_open(const char *src, struct source_info *src_info);
|
||||
int decode_read(void *buf, size_t size, struct decode_ctx *fd);
|
||||
int decode_close(struct decode_ctx *fd);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,33 +9,136 @@
|
||||
#include "encode.h"
|
||||
#include "encode-ffmpeg.h"
|
||||
|
||||
struct encode_ffmpeg_ctx
|
||||
{
|
||||
|
||||
struct ffmpeg_formats {
|
||||
char name[32];
|
||||
char codec[32];
|
||||
char format[32];
|
||||
int raw;
|
||||
};
|
||||
|
||||
struct encode_ctx *encode_ffmpeg_open(const char *tfmt);
|
||||
int encode_ffmpeg_encode(void *dst, size_t dst_size, const void *src, size_t src_size, struct encode_ctx *ctx);
|
||||
int encode_ffmpeg_close(struct encode_ctx *ctx);
|
||||
struct encode_ffmpeg_ctx
|
||||
{
|
||||
struct ffmpeg_formats format;
|
||||
AVCodecContext *codecctx;
|
||||
AVCodec *codec;
|
||||
AVFormatContext *formatctx;
|
||||
};
|
||||
|
||||
struct encode_ctx *encode_ffmpeg_init(struct decode_ctx *src, const char *tfmt, const struct source_info *src_info);
|
||||
int encode_ffmpeg_encode(void **dst, size_t *dst_size, struct encode_ctx *fd);
|
||||
int encode_ffmpeg_close(struct encode_ctx *fd);
|
||||
|
||||
struct encode_ops encode_ffmpeg_ops = {
|
||||
encode_ffmpeg_open,
|
||||
encode_ffmpeg_init,
|
||||
encode_ffmpeg_encode,
|
||||
encode_ffmpeg_close
|
||||
};
|
||||
|
||||
struct encode_ctx *encode_ffmpeg_open(const char *tfmt)
|
||||
// special handling instructions for certain encoders
|
||||
static struct ffmpeg_formats ffmpeg_formats[] = {
|
||||
{"mp3", "libmp3lame", "", 1},
|
||||
{"ogg", "libvorbis", "ogg", 0},
|
||||
{"flac", "flac", "ogg", 0},
|
||||
{"", "", 0} // END
|
||||
};
|
||||
|
||||
struct encode_ctx *encode_ffmpeg_init(struct decode_ctx *src, const char *tfmt, const struct source_info *src_info)
|
||||
{
|
||||
tcfs_errno = ENOSYS;
|
||||
struct encode_ctx *fd = (struct encode_ctx*)malloc(sizeof(struct encode_ctx)+sizeof(struct encode_ffmpeg_ctx));
|
||||
if(!fd) {
|
||||
tcfs_errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct encode_ffmpeg_ctx *ctx = (struct encode_ffmpeg_ctx*)(fd+1);
|
||||
|
||||
fd->src = src;
|
||||
fd->ops = &encode_ffmpeg_ops;
|
||||
|
||||
int i = 0, found = 0;
|
||||
while(ffmpeg_formats[i].name[0]) {
|
||||
if(strcmp(tfmt, ffmpeg_formats[i].name) == 0) {
|
||||
memcpy(&ctx->format, ffmpeg_formats+i, sizeof(struct ffmpeg_formats));
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// try default settings
|
||||
if(!found) {
|
||||
strncpy(ctx->format.name, tfmt, 32);
|
||||
strncpy(ctx->format.codec, tfmt, 32);
|
||||
strncpy(ctx->format.format, tfmt, 32);
|
||||
ctx->format.raw = 0;
|
||||
}
|
||||
|
||||
if(ctx->format.raw) {
|
||||
ctx->formatctx = NULL;
|
||||
ctx->codec = avcodec_find_encoder_by_name(ctx->format.codec);
|
||||
if(!ctx->codec) {
|
||||
tcfs_errno = ECODEC;
|
||||
free(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->codecctx = (AVCodecContext*)malloc(sizeof(AVCodecContext));
|
||||
if(!ctx->codecctx) {
|
||||
free(fd);
|
||||
tcfs_errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
avcodec_get_context_defaults3(ctx->codecctx, ctx->codec);
|
||||
|
||||
//avcodec_thread_init(st->codec, 1);
|
||||
|
||||
ctx->codecctx->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
ctx->codecctx->channels = 2;
|
||||
ctx->codecctx->sample_fmt = AV_SAMPLE_FMT_S16;
|
||||
ctx->codecctx->sample_rate = 44100;
|
||||
ctx->codecctx->channel_layout = 0;
|
||||
// ctx->codecctx->flags |= CODEC_FLAG_QSCALE;
|
||||
// ctx->codecctx->global_quality = 5;
|
||||
ctx->codecctx->bit_rate = 160000;
|
||||
ctx->codecctx->time_base = (AVRational){1, 44100};
|
||||
ctx->codecctx->compression_level = FF_COMPRESSION_DEFAULT;
|
||||
|
||||
if(avcodec_open(ctx->codecctx, ctx->codec) < 0) {
|
||||
free(fd);
|
||||
tcfs_errno = ECODEC;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
tcfs_errno = ENOSYS;
|
||||
free(fd);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int encode_ffmpeg_encode(void *dst, size_t dst_size, const void *src, size_t src_size, struct encode_ctx *ctx)
|
||||
int encode_ffmpeg_encode(void **dst, size_t *dst_size, struct encode_ctx *fd)
|
||||
{
|
||||
if(!fd || (fd->ops != &encode_ffmpeg_ops)) {
|
||||
tcfs_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct encode_ffmpeg_ctx *ctx = (struct encode_ffmpeg_ctx*)(fd+1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int encode_ffmpeg_close(struct encode_ctx *ctx)
|
||||
int encode_ffmpeg_close(struct encode_ctx *fd)
|
||||
{
|
||||
if(!fd || (fd->ops != &encode_ffmpeg_ops)) {
|
||||
tcfs_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct encode_ffmpeg_ctx *ctx = (struct encode_ffmpeg_ctx*)(fd+1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
127
src/encode-mp3lame.c
Normal file
127
src/encode-mp3lame.c
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
Copyright (c) 2010-2011 Matthias Blankertz <matthias@blankertz.org>
|
||||
|
||||
This work is licensed under the Open Software License ("OSL") v. 3.0.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include <lame.h>
|
||||
#include "util.h"
|
||||
#include "encode.h"
|
||||
#include "encode-mp3lame.h"
|
||||
|
||||
struct encode_ctx *encode_mp3lame_init(struct decode_ctx *src, const char *tfmt, const struct source_info *src_info);
|
||||
int encode_mp3lame_encode(void **dst, size_t *dst_size, struct encode_ctx *fd);
|
||||
int encode_mp3lame_close(struct encode_ctx *fd);
|
||||
|
||||
struct encode_ops encode_mp3lame_ops = {
|
||||
encode_mp3lame_init,
|
||||
encode_mp3lame_encode,
|
||||
encode_mp3lame_close
|
||||
};
|
||||
|
||||
struct encode_mp3lame_ctx
|
||||
{
|
||||
lame_global_flags *gfp;
|
||||
struct source_info src_info;
|
||||
};
|
||||
|
||||
struct encode_ctx *encode_mp3lame_init(struct decode_ctx *src, const char *tfmt, const struct source_info* src_info)
|
||||
{
|
||||
assert(tfmt != NULL);
|
||||
assert(src_info != NULL);
|
||||
|
||||
if(strcmp(tfmt, "mp3") != 0) {
|
||||
tcfs_errno = ECODEC;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct encode_ctx *fd = (struct encode_ctx*)malloc(sizeof(struct encode_ctx)+sizeof(struct encode_mp3lame_ctx));
|
||||
if(!fd) {
|
||||
tcfs_errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct encode_mp3lame_ctx *ctx = (struct encode_mp3lame_ctx*)(fd+1);
|
||||
|
||||
fd->src = src;
|
||||
fd->ops = &encode_mp3lame_ops;
|
||||
ctx->src_info = *src_info;
|
||||
|
||||
ctx->gfp = lame_init();
|
||||
if(!ctx->gfp) {
|
||||
free(fd);
|
||||
tcfs_errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(src_info->samples != 0)
|
||||
lame_set_num_samples(ctx->gfp, src_info->samples);
|
||||
if(src_info->sample_rate != 0)
|
||||
lame_set_in_samplerate(ctx->gfp, src_info->sample_rate);
|
||||
|
||||
lame_set_quality(ctx->gfp, 2);
|
||||
lame_set_VBR(ctx->gfp, vbr_mtrh);
|
||||
lame_set_VBR_q(ctx->gfp, 3);
|
||||
lame_set_strict_ISO(ctx->gfp, 1);
|
||||
|
||||
if(lame_init_params(ctx->gfp) < 0) {
|
||||
tcfs_errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int encode_mp3lame_encode(void **dst, size_t *dst_size, struct encode_ctx *fd)
|
||||
{
|
||||
if(!fd || (fd->ops != &encode_mp3lame_ops)) {
|
||||
tcfs_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct encode_mp3lame_ctx *ctx = (struct encode_mp3lame_ctx*)(fd+1);
|
||||
|
||||
int dst_bufsize = 1.25*ctx->src_info.samples+7200;
|
||||
int dst_pos = 0;
|
||||
char *dst_buffer = (char*)malloc(dst_bufsize);
|
||||
if(!dst_buffer) {
|
||||
tcfs_errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int16_t *src_buffer = (int16_t*)malloc(1024*ctx->src_info.channels*sizeof(int16_t));
|
||||
|
||||
int dec_ret;
|
||||
while((dec_ret = decode_read((void*)src_buffer, 1024*ctx->src_info.channels, fd->src)) > 0) {
|
||||
int enc_ret = lame_encode_buffer_interleaved(ctx->gfp, src_buffer, dec_ret/ctx->src_info.channels, dst_buffer+dst_pos, dst_bufsize-dst_pos);
|
||||
if(enc_ret < 0) {
|
||||
tcfs_errno = ECODEC;
|
||||
return -1;
|
||||
}
|
||||
dst_pos += enc_ret;
|
||||
}
|
||||
|
||||
int enc_ret = lame_encode_flush(ctx->gfp, dst_buffer+dst_pos, dst_bufsize-dst_pos);
|
||||
|
||||
dst_pos += enc_ret;
|
||||
|
||||
dst_buffer = (char*)realloc((void*)dst_buffer, dst_pos);
|
||||
|
||||
*dst = dst_buffer;
|
||||
*dst_size = dst_pos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int encode_mp3lame_close(struct encode_ctx *fd)
|
||||
{
|
||||
if(!fd || (fd->ops != &encode_mp3lame_ops)) {
|
||||
tcfs_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct encode_mp3lame_ctx *ctx = (struct encode_mp3lame_ctx*)(fd+1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
14
src/encode-mp3lame.h
Normal file
14
src/encode-mp3lame.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_MP3LAME_H
|
||||
#define TCFS_ENCODE_MP3LAME_H 1
|
||||
|
||||
#include "encode.h"
|
||||
|
||||
extern struct encode_ops encode_mp3lame_ops;
|
||||
|
||||
#endif
|
||||
22
src/encode.c
22
src/encode.c
@@ -8,18 +8,22 @@
|
||||
#include "util.h"
|
||||
#include "encode.h"
|
||||
#include "encode-ffmpeg.h"
|
||||
#include "encode-mp3lame.h"
|
||||
|
||||
struct encoders_entry encoders[] = {
|
||||
{&encode_ffmpeg_ops, "ffmpeg"},
|
||||
#ifdef HAVE_LIBMP3LAME
|
||||
{&encode_mp3lame_ops, "mp3lame", 0},
|
||||
#endif
|
||||
{&encode_ffmpeg_ops, "ffmpeg", 1},
|
||||
{NULL, ""}
|
||||
};
|
||||
|
||||
struct encode_ctx *encode_open(const char *tfmt)
|
||||
struct encode_ctx *encode_init(struct decode_ctx *src, const char *tfmt, const struct source_info *src_info)
|
||||
{
|
||||
struct encode_ctx *ctx;
|
||||
int i = 0;
|
||||
while(encoders[i].ops) {
|
||||
ctx = encoders[i++].ops->open(tfmt);
|
||||
ctx = encoders[i++].ops->init(src, tfmt, src_info);
|
||||
if(!ctx) { // open failed
|
||||
if(tcfs_errno == ECODEC) // the codec doesn't support this format, try the next one
|
||||
continue;
|
||||
@@ -33,12 +37,18 @@ struct encode_ctx *encode_open(const char *tfmt)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int encode_encode(void *dst, size_t dst_size, const void *src, size_t src_size, struct encode_ctx *ctx)
|
||||
int encode_encode(void **dst, size_t *dst_size, struct encode_ctx *ctx)
|
||||
{
|
||||
return 0;
|
||||
assert(ctx);
|
||||
assert(ctx->ops);
|
||||
assert(ctx->ops->encode);
|
||||
return ctx->ops->encode(dst, dst_size, ctx);
|
||||
}
|
||||
|
||||
int encode_close(struct encode_ctx *ctx)
|
||||
{
|
||||
return 0;
|
||||
assert(ctx);
|
||||
assert(ctx->ops);
|
||||
assert(ctx->ops->close);
|
||||
return ctx->ops->close(ctx);
|
||||
}
|
||||
|
||||
15
src/encode.h
15
src/encode.h
@@ -7,25 +7,30 @@
|
||||
#ifndef TCFS_ENCODE_H
|
||||
#define TCFS_ENCODE_H 1
|
||||
|
||||
#include "util.h"
|
||||
#include "decode.h"
|
||||
|
||||
struct encode_ctx {
|
||||
struct encode_ops *ops;
|
||||
struct decode_ctx *src;
|
||||
};
|
||||
|
||||
struct encode_ops {
|
||||
struct encode_ctx *(*open)(const char *);
|
||||
int (*encode)(void *, size_t, const void *, size_t, struct encode_ctx *);
|
||||
struct encode_ctx *(*init)(struct decode_ctx *, const char *, const struct source_info *);
|
||||
int (*encode)(void **, size_t *, struct encode_ctx *);
|
||||
int (*close)(struct encode_ctx *);
|
||||
};
|
||||
|
||||
struct encoders_entry {
|
||||
struct encode_ops *ops;
|
||||
char name[];
|
||||
char name[TCFS_MAX_NAME_LENGTH];
|
||||
unsigned stream:1;
|
||||
};
|
||||
|
||||
extern struct encoders_entry encoders[];
|
||||
|
||||
struct encode_ctx *encode_open(const char *tfmt);
|
||||
int encode_encode(void *dst, size_t dst_size, const void *src, size_t src_size, struct encode_ctx *ctx);
|
||||
struct encode_ctx *encode_init(struct decode_ctx *src, const char *tfmt, const struct source_info *src_info);
|
||||
int encode_encode(void **dst, size_t *dst_size, struct encode_ctx *ctx);
|
||||
int encode_close(struct encode_ctx *ctx);
|
||||
|
||||
#endif
|
||||
|
||||
30
src/tcfs.c
30
src/tcfs.c
@@ -27,6 +27,7 @@ int tcfs_getattr(const char *path, struct stat *stbuf)
|
||||
if(tc_src) {
|
||||
ret = stat(tc_src, stbuf);
|
||||
stbuf->st_size = 0;
|
||||
free(tc_src);
|
||||
if(ret == -1) {
|
||||
free(base_path);
|
||||
return -errno;
|
||||
@@ -117,10 +118,11 @@ int tcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
||||
}
|
||||
}
|
||||
filler(buf, file_new_ext, NULL, 0);
|
||||
free(file_new_ext);
|
||||
}
|
||||
}
|
||||
|
||||
free(base_path);
|
||||
free(base_path);
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
@@ -131,6 +133,7 @@ struct tcfs_file_info {
|
||||
TRANSCODE
|
||||
} type;
|
||||
FILE *fd;
|
||||
struct TC_FILE *tc_fd;
|
||||
};
|
||||
|
||||
int tcfs_open(const char *path, struct fuse_file_info *fi)
|
||||
@@ -150,15 +153,19 @@ int tcfs_open(const char *path, struct fuse_file_info *fi)
|
||||
if(!tcfs_fi->fd) {
|
||||
char *src_name = get_tc_source_name(base_path);
|
||||
if(src_name) {
|
||||
tcfs_fi->fd = fopen(src_name, "r");
|
||||
if(!tcfs_fi->fd) {
|
||||
tcfs_fi->tc_fd = tc_open(src_name, base_path, options.tfmt);
|
||||
free(src_name);
|
||||
if(!tcfs_fi->tc_fd) {
|
||||
return -errno;
|
||||
}
|
||||
tcfs_fi->type = TRANSCODE;
|
||||
} else {
|
||||
return -errno;
|
||||
}
|
||||
} else {
|
||||
tcfs_fi->type = DIRECT;
|
||||
}
|
||||
|
||||
|
||||
fi->fh = (uint64_t)tcfs_fi;
|
||||
fi->direct_io = 1;
|
||||
return 0;
|
||||
@@ -170,12 +177,15 @@ int tcfs_read(const char *path, char *buf, size_t size, off_t offset, struct fus
|
||||
if(!tcfs_fi)
|
||||
return -EINVAL;
|
||||
|
||||
errno = 0;
|
||||
int ret = fread(buf, 1, size, tcfs_fi->fd);
|
||||
if((ret == 0) && (errno != 0))
|
||||
return -errno;
|
||||
|
||||
return ret;
|
||||
if(tcfs_fi->type == DIRECT) {
|
||||
errno = 0;
|
||||
int ret = fread(buf, 1, size, tcfs_fi->fd);
|
||||
if((ret == 0) && (errno != 0))
|
||||
return -errno;
|
||||
return ret;
|
||||
} else {
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
void *tcfs_init(struct fuse_conn_info *conn)
|
||||
|
||||
@@ -10,9 +10,13 @@
|
||||
|
||||
struct TC_FILE {
|
||||
struct decode_ctx *decode;
|
||||
struct encode_ctx *encode;
|
||||
char *encoded_data;
|
||||
size_t encoded_size;
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
struct TC_FILE *tc_open(const char *src, const char *tfmt)
|
||||
struct TC_FILE *tc_open(const char *src, const char *dst, const char *tfmt)
|
||||
{
|
||||
struct TC_FILE *fd = (struct TC_FILE*)malloc(sizeof(struct TC_FILE));
|
||||
if(!fd) {
|
||||
@@ -20,11 +24,59 @@ struct TC_FILE *tc_open(const char *src, const char *tfmt)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fd->decode = decode_open(src);
|
||||
struct source_info src_info;
|
||||
|
||||
fd->decode = decode_open(src, &src_info);
|
||||
if(!fd->decode) {
|
||||
free(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fd->encode = encode_init(fd->decode, tfmt, &src_info);
|
||||
if(!fd->encode) {
|
||||
decode_close(fd->decode);
|
||||
free(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(encode_encode(&fd->encoded_data, &fd->encoded_size, fd->encode) < 0) {
|
||||
encode_close(fd->encode);
|
||||
decode_close(fd->decode);
|
||||
free(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// debug dump
|
||||
char name[11+strlen(tfmt)];
|
||||
strcpy(name,"debugdump.");
|
||||
strcpy(name+10, tfmt);
|
||||
FILE *debugdump = fopen(name, "w");
|
||||
fwrite(fd->encoded_data, fd->encoded_size, 1, debugdump);
|
||||
fclose(debugdump);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int tc_read(char *buf, size_t size, struct TC_FILE *fd)
|
||||
{
|
||||
assert(fd);
|
||||
|
||||
size_t readsize = (size+fd->pos<fd->encoded_size)?size:(fd->encoded_size-fd->pos);
|
||||
if(!readsize)
|
||||
return 0;
|
||||
|
||||
memcpy(buf, fd->encoded_data, readsize);
|
||||
|
||||
fd->pos += readsize;
|
||||
|
||||
return readsize;
|
||||
}
|
||||
|
||||
int tc_close(struct TC_FILE *fd)
|
||||
{
|
||||
assert(fd);
|
||||
encode_close(fd->encode);
|
||||
decode_close(fd->decode);
|
||||
free(fd->encoded_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
struct TC_FILE;
|
||||
|
||||
struct TC_FILE *tc_open(const char *src, const char *tfmt);
|
||||
struct TC_FILE *tc_open(const char *src, const char *dst, const char *tfmt);
|
||||
int tc_read(char *buf, size_t size, struct TC_FILE *fd);
|
||||
int tc_close(struct TC_FILE *fd);
|
||||
|
||||
|
||||
@@ -97,8 +97,9 @@ int is_tc_audio_file(const char *path)
|
||||
if(strcmp(ext,options.tfmt) == 0)
|
||||
return 0; // file already has right format
|
||||
|
||||
struct source_info src_info;
|
||||
// try to open file as transcode source
|
||||
struct decode_ctx *tcfd = decode_open(path);
|
||||
struct decode_ctx *tcfd = decode_open(path, &src_info);
|
||||
if(tcfd) {
|
||||
decode_close(tcfd);
|
||||
return 1;
|
||||
|
||||
@@ -17,7 +17,15 @@ struct options {
|
||||
extern struct options options;
|
||||
extern TLS int tcfs_errno;
|
||||
|
||||
struct source_info {
|
||||
unsigned long samples;
|
||||
int sample_rate;
|
||||
int depth;
|
||||
int channels;
|
||||
};
|
||||
|
||||
#define ECODEC 1001
|
||||
#define TCFS_MAX_NAME_LENGTH 64
|
||||
|
||||
const char *get_file_from_path(const char *path);
|
||||
const char *get_ext_from_file(const char *file);
|
||||
|
||||
Reference in New Issue
Block a user