From c2bbe2ef69576fadda7672bc7bc7868d7e97576f Mon Sep 17 00:00:00 2001 From: Matthias Blankertz Date: Mon, 15 Nov 2010 19:54:46 +0100 Subject: [PATCH] Added infrastructure for different encode modules. Made tcfs_errno thread-local and added TLS autoconf check. --- Makefile.am | 4 +-- acinclude.m4 | 76 +++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 1 + src/decode-ffmpeg.c | 30 ++++++++++++------ src/decode.c | 25 +++++++++++++++ src/decode.h | 7 +++++ src/encode-ffmpeg.c | 41 ++++++++++++++++++++++++ src/encode-ffmpeg.h | 14 +++++++++ src/encode.c | 64 +++++++++++++++++--------------------- src/encode.h | 19 +++++++++++- src/test_encode.c | 2 +- src/transcode.c | 2 +- src/util.c | 4 +-- src/util.h | 6 +++- 14 files changed, 243 insertions(+), 52 deletions(-) create mode 100644 acinclude.m4 create mode 100644 src/encode-ffmpeg.c create mode 100644 src/encode-ffmpeg.h diff --git a/Makefile.am b/Makefile.am index 15bb9e4..df1b2ab 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ 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 +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 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 -test_encode_SOURCES=src/decode.c src/encode.c src/tcfs_buf.c src/util.c src/test_encode.c src/decode-ffmpeg.c +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) \ No newline at end of file diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000..033e3b1 --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,76 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_tls.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_TLS([action-if-found], [action-if-not-found]) +# +# DESCRIPTION +# +# Provides a test for the compiler support of thread local storage (TLS) +# extensions. Defines TLS if it is found. Currently knows about GCC/ICC +# and MSVC. I think SunPro uses the same as GCC, and Borland apparently +# supports either. +# +# LICENSE +# +# Copyright (c) 2008 Alan Woodland +# Copyright (c) 2010 Diego Elio Petteno` +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 10 + +AC_DEFUN([AX_TLS], [ + AC_MSG_CHECKING(for thread local storage (TLS) class) + AC_CACHE_VAL(ac_cv_tls, [ + ax_tls_keywords="__thread __declspec(thread) none" + for ax_tls_keyword in $ax_tls_keywords; do + AS_CASE([$ax_tls_keyword], + [none], [ac_cv_tls=none ; break], + [AC_TRY_COMPILE( + [#include + static void + foo(void) { + static ] $ax_tls_keyword [ int bar; + exit(1); + }], + [], + [ac_cv_tls=$ax_tls_keyword ; break], + ac_cv_tls=none + )]) + done + ]) + AC_MSG_RESULT($ac_cv_tls) + + AS_IF([test "$ac_cv_tls" != "none"], + AC_DEFINE_UNQUOTED([TLS], $ac_cv_tls, [If the compiler supports a TLS storage class define it to that here]) + m4_ifnblank([$1], [$1]), + m4_ifnblank([$2], [$2]) + ) +]) diff --git a/configure.ac b/configure.ac index 12a1164..16d44d2 100644 --- a/configure.ac +++ b/configure.ac @@ -23,6 +23,7 @@ AC_CHECK_HEADERS([fcntl.h stddef.h stdlib.h string.h errno.h dirent.h]) # Checks for typedefs, structures, and compiler characteristics. AC_PROG_CC_C99 AM_PROG_CC_C_O +AX_TLS # Checks for library functions. AC_CHECK_FUNCS([memset strerror]) diff --git a/src/decode-ffmpeg.c b/src/decode-ffmpeg.c index 3e57f82..0fbe02a 100644 --- a/src/decode-ffmpeg.c +++ b/src/decode-ffmpeg.c @@ -20,7 +20,7 @@ struct decode_ffmpeg_ctx }; struct decode_ctx *decode_ffmpeg_open(const char *src); -int decode_ffmpeg_read(char *buf, size_t size, struct decode_ctx *fd); +int decode_ffmpeg_read(void *buf, size_t size, struct decode_ctx *fd); int decode_ffmpeg_close(struct decode_ctx *fd); struct decode_ops decode_ffmpeg_ops = { @@ -44,7 +44,10 @@ struct decode_ctx *decode_ffmpeg_open(const char *src) av_strerror(ret, err, 512); fprintf(stderr, "ffmpeg error: %s\n", err); free(fd); - errno = EIO; + if((ret == AVERROR_NOFMT) || (ret == AVERROR_INVALIDDATA) || (ret == AVERROR_PATCHWELCOME)) + tcfs_errno = ECODEC; + else + tcfs_errno = AVUNERROR(ret); return NULL; } @@ -54,7 +57,10 @@ struct decode_ctx *decode_ffmpeg_open(const char *src) fprintf(stderr, "ffmpeg error: %s\n", err); av_close_input_file(ctx->avfctx); free(fd); - errno = EIO; + if((ret == AVERROR_NOFMT) || (ret == AVERROR_INVALIDDATA) || (ret == AVERROR_PATCHWELCOME)) + tcfs_errno = ECODEC; + else + tcfs_errno = AVUNERROR(ret); return NULL; } @@ -70,7 +76,7 @@ struct decode_ctx *decode_ffmpeg_open(const char *src) // no audio stream av_close_input_file(ctx->avfctx); free(fd); - errno = EIO; + tcfs_errno = ECODEC; return NULL; } @@ -82,7 +88,7 @@ struct decode_ctx *decode_ffmpeg_open(const char *src) fprintf(stderr, "ffmpeg error: Could not find decoder.\n"); av_close_input_file(ctx->avfctx); free(fd); - errno = EIO; + tcfs_errno = ECODEC; return NULL; } @@ -92,20 +98,26 @@ struct decode_ctx *decode_ffmpeg_open(const char *src) fprintf(stderr, "ffmpeg error: %s\n", err); av_close_input_file(ctx->avfctx); free(fd); - errno = EIO; + if((ret == AVERROR_NOFMT) || (ret == AVERROR_INVALIDDATA) || (ret == AVERROR_PATCHWELCOME)) + tcfs_errno = ECODEC; + else + tcfs_errno = AVUNERROR(ret); return NULL; } ctx->bod = malloc(128*1024*1024); - if(!ctx->bod) + if(!ctx->bod) { + tcfs_errno = ENOMEM; return NULL; + } 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, ctx->bod+pos, &fsp, &pack) < 0) { + if(avcodec_decode_audio3(ctx->avfctx->streams[ctx->stream]->codec, + (int16_t*)(ctx->bod+pos), &fsp, &pack) < 0) { printf("Decode error.\n"); return NULL; } @@ -119,7 +131,7 @@ struct decode_ctx *decode_ffmpeg_open(const char *src) return fd; } -int decode_ffmpeg_read(char *buf, size_t size, struct decode_ctx *fd) +int decode_ffmpeg_read(void *buf, size_t size, struct decode_ctx *fd) { if(!fd || (fd->ops != &decode_ffmpeg_ops)) { tcfs_errno = EINVAL; diff --git a/src/decode.c b/src/decode.c index 48d736d..0bb2ca0 100644 --- a/src/decode.c +++ b/src/decode.c @@ -7,6 +7,31 @@ #include "common.h" #include "util.h" #include "decode.h" +#include "decode-ffmpeg.h" + +struct decoders_entry decoders[] = { + {&decode_ffmpeg_ops, "ffmpeg"}, + {NULL, ""} +}; + +struct decode_ctx *decode_open(const char *src) +{ + struct decode_ctx *ctx; + int i = 0; + while(decoders[i].ops) { + ctx = decoders[i++].ops->open(src); + if(!ctx) { // open failed + if(tcfs_errno == ECODEC) // the codec doesn't support this file, try the next one + continue; + // something else went wrong, give up + return NULL; + } + return ctx; + } + + // no codec found + return NULL; +} int decode_read(char *buf, size_t size, struct decode_ctx *fd) { diff --git a/src/decode.h b/src/decode.h index b9d3f31..074f0ef 100644 --- a/src/decode.h +++ b/src/decode.h @@ -17,6 +17,13 @@ struct decode_ops { int (*close)(struct decode_ctx *fd); }; +struct decoders_entry { + struct decode_ops *ops; + char name[]; +}; + +extern struct decoders_entry decoders[]; + 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); diff --git a/src/encode-ffmpeg.c b/src/encode-ffmpeg.c new file mode 100644 index 0000000..795915b --- /dev/null +++ b/src/encode-ffmpeg.c @@ -0,0 +1,41 @@ +/* + Copyright (c) 2010 Matthias Blankertz + + This work is licensed under the Open Software License ("OSL") v. 3.0. + */ + +#include "common.h" +#include "util.h" +#include "encode.h" +#include "encode-ffmpeg.h" + +struct encode_ffmpeg_ctx +{ + +}; + +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_ops encode_ffmpeg_ops = { + encode_ffmpeg_open, + encode_ffmpeg_encode, + encode_ffmpeg_close +}; + +struct encode_ctx *encode_ffmpeg_open(const char *tfmt) +{ + tcfs_errno = ENOSYS; +} + +int encode_ffmpeg_encode(void *dst, size_t dst_size, const void *src, size_t src_size, struct encode_ctx *ctx) +{ + return 0; +} + +int encode_ffmpeg_close(struct encode_ctx *ctx) +{ + return 0; +} + diff --git a/src/encode-ffmpeg.h b/src/encode-ffmpeg.h new file mode 100644 index 0000000..097c1da --- /dev/null +++ b/src/encode-ffmpeg.h @@ -0,0 +1,14 @@ +/* + Copyright (c) 2010 Matthias Blankertz + + This work is licensed under the Open Software License ("OSL") v. 3.0. + */ + +#ifndef TCFS_ENCODE_FFMPEG_H +#define TCFS_ENCODE_FFMPEG_H 1 + +#include "encode.h" + +extern struct encode_ops encode_ffmpeg_ops; + +#endif diff --git a/src/encode.c b/src/encode.c index f392cb1..a2b6912 100644 --- a/src/encode.c +++ b/src/encode.c @@ -5,46 +5,40 @@ */ #include "common.h" +#include "util.h" +#include "encode.h" +#include "encode-ffmpeg.h" -struct encode_ctx { - AVFormatContext *avfctx; +struct encoders_entry encoders[] = { + {&encode_ffmpeg_ops, "ffmpeg"}, + {NULL, ""} }; 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; + struct encode_ctx *ctx; + int i = 0; + while(encoders[i].ops) { + ctx = encoders[i++].ops->open(tfmt); + if(!ctx) { // open failed + if(tcfs_errno == ECODEC) // the codec doesn't support this format, try the next one + continue; + // something else went wrong, give up + return NULL; + } + return ctx; } - 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; + // no codec found + return NULL; +} + +int encode_encode(void *dst, size_t dst_size, const void *src, size_t src_size, struct encode_ctx *ctx) +{ + return 0; +} + +int encode_close(struct encode_ctx *ctx) +{ + return 0; } diff --git a/src/encode.h b/src/encode.h index 7d3b763..520b4ed 100644 --- a/src/encode.h +++ b/src/encode.h @@ -7,8 +7,25 @@ #ifndef TCFS_ENCODE_H #define TCFS_ENCODE_H 1 -struct encode_ctx; +struct encode_ctx { + struct encode_ops *ops; +}; + +struct encode_ops { + struct encode_ctx *(*open)(const char *); + int (*encode)(void *, size_t, const void *, size_t, struct encode_ctx *); + int (*close)(struct encode_ctx *); +}; + +struct encoders_entry { + struct encode_ops *ops; + char name[]; +}; + +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); +int encode_close(struct encode_ctx *ctx); #endif diff --git a/src/test_encode.c b/src/test_encode.c index 4655dfa..5f1eefd 100644 --- a/src/test_encode.c +++ b/src/test_encode.c @@ -53,7 +53,7 @@ int main(int argc, char *argv[]) tcfs_buf_register(); - struct decode_ctx *decode = decode_ffmpeg_open("testbase/fmc/Sinn/01 - Das frivole Burgfräulein - Erwachsen.ogg"); + 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; diff --git a/src/transcode.c b/src/transcode.c index fa018e7..aa23914 100644 --- a/src/transcode.c +++ b/src/transcode.c @@ -20,7 +20,7 @@ struct TC_FILE *tc_open(const char *src, const char *tfmt) return NULL; } - fd->decode = decode_ffmpeg_open(src); + fd->decode = decode_open(src); if(!fd->decode) { free(fd); return NULL; diff --git a/src/util.c b/src/util.c index eec2008..8a9c11f 100644 --- a/src/util.c +++ b/src/util.c @@ -8,7 +8,7 @@ #include "util.h" #include "decode.h" -int tcfs_errno = 0; +TLS int tcfs_errno = 0; // Get the filename from a path, i.e. a pointer to the character after the last / in path. // If path contains no /, returns path. @@ -98,7 +98,7 @@ int is_tc_audio_file(const char *path) return 0; // file already has right format // try to open file as transcode source - struct decode_ctx *tcfd = decode_ffmpeg_open(path); + struct decode_ctx *tcfd = decode_open(path); if(tcfd) { decode_close(tcfd); return 1; diff --git a/src/util.h b/src/util.h index 504a7fe..8a87d02 100644 --- a/src/util.h +++ b/src/util.h @@ -7,13 +7,17 @@ #ifndef TCFS_UTIL_H #define TCFS_UTIL_H 1 +#include "common.h" + struct options { char *base; char *tfmt; }; extern struct options options; -extern int tcfs_errno; +extern TLS int tcfs_errno; + +#define ECODEC 1001 const char *get_file_from_path(const char *path); const char *get_ext_from_file(const char *file);