Added infrastructure for different encode modules.

Made tcfs_errno thread-local and added TLS autoconf check.
This commit is contained in:
2010-11-15 19:54:46 +01:00
parent 794a7795d7
commit c2bbe2ef69
14 changed files with 243 additions and 52 deletions

View File

@@ -1,7 +1,7 @@
bin_PROGRAMS=tcfs test_encode 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_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 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_LDADD = $(LIBOBJS) $(libavcore_LIBS) $(libavutil_LIBS) $(libavformat_LIBS) $(libavcodec_LIBS)
test_encode_CFLAGS = $(libavcore_CFLAGS) $(libavutil_CFLAGS) $(libavformat_CFLAGS) $(libavcodec_CFLAGS) test_encode_CFLAGS = $(libavcore_CFLAGS) $(libavutil_CFLAGS) $(libavformat_CFLAGS) $(libavcodec_CFLAGS)

76
acinclude.m4 Normal file
View File

@@ -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 <ajw05@aber.ac.uk>
# Copyright (c) 2010 Diego Elio Petteno` <flameeyes@gmail.com>
#
# 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 <http://www.gnu.org/licenses/>.
#
# 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 <stdlib.h>
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])
)
])

View File

@@ -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. # Checks for typedefs, structures, and compiler characteristics.
AC_PROG_CC_C99 AC_PROG_CC_C99
AM_PROG_CC_C_O AM_PROG_CC_C_O
AX_TLS
# Checks for library functions. # Checks for library functions.
AC_CHECK_FUNCS([memset strerror]) AC_CHECK_FUNCS([memset strerror])

View File

@@ -20,7 +20,7 @@ struct decode_ffmpeg_ctx
}; };
struct decode_ctx *decode_ffmpeg_open(const char *src); 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); int decode_ffmpeg_close(struct decode_ctx *fd);
struct decode_ops decode_ffmpeg_ops = { struct decode_ops decode_ffmpeg_ops = {
@@ -44,7 +44,10 @@ struct decode_ctx *decode_ffmpeg_open(const char *src)
av_strerror(ret, err, 512); av_strerror(ret, err, 512);
fprintf(stderr, "ffmpeg error: %s\n", err); fprintf(stderr, "ffmpeg error: %s\n", err);
free(fd); free(fd);
errno = EIO; if((ret == AVERROR_NOFMT) || (ret == AVERROR_INVALIDDATA) || (ret == AVERROR_PATCHWELCOME))
tcfs_errno = ECODEC;
else
tcfs_errno = AVUNERROR(ret);
return NULL; return NULL;
} }
@@ -54,7 +57,10 @@ struct decode_ctx *decode_ffmpeg_open(const char *src)
fprintf(stderr, "ffmpeg error: %s\n", err); fprintf(stderr, "ffmpeg error: %s\n", err);
av_close_input_file(ctx->avfctx); av_close_input_file(ctx->avfctx);
free(fd); free(fd);
errno = EIO; if((ret == AVERROR_NOFMT) || (ret == AVERROR_INVALIDDATA) || (ret == AVERROR_PATCHWELCOME))
tcfs_errno = ECODEC;
else
tcfs_errno = AVUNERROR(ret);
return NULL; return NULL;
} }
@@ -70,7 +76,7 @@ struct decode_ctx *decode_ffmpeg_open(const char *src)
// no audio stream // no audio stream
av_close_input_file(ctx->avfctx); av_close_input_file(ctx->avfctx);
free(fd); free(fd);
errno = EIO; tcfs_errno = ECODEC;
return NULL; return NULL;
} }
@@ -82,7 +88,7 @@ struct decode_ctx *decode_ffmpeg_open(const char *src)
fprintf(stderr, "ffmpeg error: Could not find decoder.\n"); fprintf(stderr, "ffmpeg error: Could not find decoder.\n");
av_close_input_file(ctx->avfctx); av_close_input_file(ctx->avfctx);
free(fd); free(fd);
errno = EIO; tcfs_errno = ECODEC;
return NULL; return NULL;
} }
@@ -92,20 +98,26 @@ struct decode_ctx *decode_ffmpeg_open(const char *src)
fprintf(stderr, "ffmpeg error: %s\n", err); fprintf(stderr, "ffmpeg error: %s\n", err);
av_close_input_file(ctx->avfctx); av_close_input_file(ctx->avfctx);
free(fd); free(fd);
errno = EIO; if((ret == AVERROR_NOFMT) || (ret == AVERROR_INVALIDDATA) || (ret == AVERROR_PATCHWELCOME))
tcfs_errno = ECODEC;
else
tcfs_errno = AVUNERROR(ret);
return NULL; return NULL;
} }
ctx->bod = malloc(128*1024*1024); ctx->bod = malloc(128*1024*1024);
if(!ctx->bod) if(!ctx->bod) {
tcfs_errno = ENOMEM;
return NULL; return NULL;
}
AVPacket pack; AVPacket pack;
int pos = 0; int pos = 0;
int fsp = 128*1024*1024; int fsp = 128*1024*1024;
while(av_read_frame(ctx->avfctx, &pack) == 0) { while(av_read_frame(ctx->avfctx, &pack) == 0) {
if(pack.stream_index == ctx->stream) { 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"); printf("Decode error.\n");
return NULL; return NULL;
} }
@@ -119,7 +131,7 @@ struct decode_ctx *decode_ffmpeg_open(const char *src)
return fd; 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)) { if(!fd || (fd->ops != &decode_ffmpeg_ops)) {
tcfs_errno = EINVAL; tcfs_errno = EINVAL;

View File

@@ -7,6 +7,31 @@
#include "common.h" #include "common.h"
#include "util.h" #include "util.h"
#include "decode.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) int decode_read(char *buf, size_t size, struct decode_ctx *fd)
{ {

View File

@@ -17,6 +17,13 @@ struct decode_ops {
int (*close)(struct decode_ctx *fd); 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); struct decode_ctx *decode_open(const char *src);
int decode_read(char *buf, size_t size, struct decode_ctx *fd); int decode_read(char *buf, size_t size, struct decode_ctx *fd);
int decode_close(struct decode_ctx *fd); int decode_close(struct decode_ctx *fd);

41
src/encode-ffmpeg.c Normal file
View File

@@ -0,0 +1,41 @@
/*
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"
#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;
}

14
src/encode-ffmpeg.h Normal file
View 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_FFMPEG_H
#define TCFS_ENCODE_FFMPEG_H 1
#include "encode.h"
extern struct encode_ops encode_ffmpeg_ops;
#endif

View File

@@ -5,46 +5,40 @@
*/ */
#include "common.h" #include "common.h"
#include "util.h"
#include "encode.h"
#include "encode-ffmpeg.h"
struct encode_ctx { struct encoders_entry encoders[] = {
AVFormatContext *avfctx; {&encode_ffmpeg_ops, "ffmpeg"},
{NULL, ""}
}; };
struct encode_ctx *encode_open(const char *tfmt) struct encode_ctx *encode_open(const char *tfmt)
{ {
struct encode_ctx *ctx = (struct encode_ctx*)malloc(sizeof(struct encode_ctx)); struct encode_ctx *ctx;
if(!ctx) { int i = 0;
errno = ENOMEM; while(encoders[i].ops) {
return NULL; 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(); // no codec found
if(!ctx->avfctx) { return NULL;
free(ctx); }
return NULL;
} int encode_encode(void *dst, size_t dst_size, const void *src, size_t src_size, struct encode_ctx *ctx)
{
int ret; return 0;
URLContext *urlctx; }
if((ret = url_open_protocol(&urlctx, tcfs_buf_get_protocol(), "", 0)) != 0) {
char err[512]; int encode_close(struct encode_ctx *ctx)
av_strerror(ret, err, 512); {
fprintf(stderr, "ffmpeg error: %s\n", err); return 0;
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;
} }

View File

@@ -7,8 +7,25 @@
#ifndef TCFS_ENCODE_H #ifndef TCFS_ENCODE_H
#define TCFS_ENCODE_H 1 #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); 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 #endif

View File

@@ -53,7 +53,7 @@ int main(int argc, char *argv[])
tcfs_buf_register(); 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) { if(!decode) {
printf("Can't decode source.\n"); printf("Can't decode source.\n");
return -1; return -1;

View File

@@ -20,7 +20,7 @@ struct TC_FILE *tc_open(const char *src, const char *tfmt)
return NULL; return NULL;
} }
fd->decode = decode_ffmpeg_open(src); fd->decode = decode_open(src);
if(!fd->decode) { if(!fd->decode) {
free(fd); free(fd);
return NULL; return NULL;

View File

@@ -8,7 +8,7 @@
#include "util.h" #include "util.h"
#include "decode.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. // 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.
@@ -98,7 +98,7 @@ int is_tc_audio_file(const char *path)
return 0; // file already has right format return 0; // file already has right format
// try to open file as transcode source // try to open file as transcode source
struct decode_ctx *tcfd = decode_ffmpeg_open(path); struct decode_ctx *tcfd = decode_open(path);
if(tcfd) { if(tcfd) {
decode_close(tcfd); decode_close(tcfd);
return 1; return 1;

View File

@@ -7,13 +7,17 @@
#ifndef TCFS_UTIL_H #ifndef TCFS_UTIL_H
#define TCFS_UTIL_H 1 #define TCFS_UTIL_H 1
#include "common.h"
struct options { struct options {
char *base; char *base;
char *tfmt; char *tfmt;
}; };
extern struct options options; 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_file_from_path(const char *path);
const char *get_ext_from_file(const char *file); const char *get_ext_from_file(const char *file);