diff --git a/acinclude.m4 b/acinclude.m4 index b64b2a7..5662e5a 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -2,7 +2,6 @@ AC_DEFUN([TUXBOX_APPS],[ AM_CONFIG_HEADER(config.h) AM_MAINTAINER_MODE -AC_GNU_SOURCE AC_SYS_LARGEFILE AC_ARG_WITH(target, @@ -58,21 +57,33 @@ check_path () { ]) +dnl expand nested ${foo}/bar +AC_DEFUN([TUXBOX_EXPAND_VARIABLE],[__$1="$2" + for __CNT in false false false false true; do dnl max 5 levels of indirection + + $1=`eval echo "$__$1"` + echo ${$1} | grep -q '\$' || break # 'grep -q' is POSIX, exit if no $ in variable + __$1="${$1}" + done + $__CNT && AC_MSG_ERROR([can't expand variable $1=$2]) dnl bail out if we did not expand +]) + AC_DEFUN([TUXBOX_APPS_DIRECTORY_ONE],[ AC_ARG_WITH($1,[ $6$7 [[PREFIX$4$5]]],[ _$2=$withval if test "$TARGET" = "cdk"; then - $2=`eval echo "${targetprefix}$withval"` + $2=`eval echo "${targetprefix}$withval"` # no indirection possible IMNSHO else $2=$withval fi TARGET_$2=${$2} ],[ - $2="\${$3}$5" + # RFC 1925: "you can always add another level of indirection..." + TUXBOX_EXPAND_VARIABLE($2,"${$3}$5") if test "$TARGET" = "cdk"; then - _$2=`eval echo "${target$3}$5"` + TUXBOX_EXPAND_VARIABLE(_$2,"${target$3}$5") else - _$2=`eval echo "${$3}$5"` + _$2=${$2} fi TARGET_$2=$_$2 ]) diff --git a/azbox/dmx_lib.h b/azbox/dmx_lib.h index ed38048..754511e 100644 --- a/azbox/dmx_lib.h +++ b/azbox/dmx_lib.h @@ -8,6 +8,8 @@ #include #include "../common/cs_types.h" +#define MAX_DMX_UNITS 4 + typedef enum { DMX_INVALID = 0, diff --git a/configure.ac b/configure.ac index db9cf86..b8a2911 100644 --- a/configure.ac +++ b/configure.ac @@ -2,6 +2,7 @@ AC_INIT(libstb-hal,0.1.1) AM_INIT_AUTOMAKE(libstb-hal,0.1.1) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES]) AC_CONFIG_MACRO_DIR([m4]) +AC_GNU_SOURCE LT_INIT ## ugly, disables shared library build (not wanted yet) diff --git a/generic-pc/audio.cpp b/generic-pc/audio.cpp index bb814e7..99effcd 100644 --- a/generic-pc/audio.cpp +++ b/generic-pc/audio.cpp @@ -45,12 +45,18 @@ extern cDemux *audioDemux; static uint8_t *dmxbuf = NULL; static int bufpos; +extern bool HAL_nodec; + static cAudio *gThiz = NULL; +static ao_device *adevice = NULL; +static ao_sample_format sformat; + cAudio::cAudio(void *, void *, void *) { thread_started = false; - dmxbuf = (uint8_t *)malloc(DMX_BUF_SZ); + if (!HAL_nodec) + dmxbuf = (uint8_t *)malloc(DMX_BUF_SZ); bufpos = 0; curr_pts = 0; gThiz = this; @@ -61,6 +67,9 @@ cAudio::~cAudio(void) { closeDevice(); free(dmxbuf); + if (adevice) + ao_close(adevice); + adevice = NULL; ao_shutdown(); } @@ -89,7 +98,8 @@ int cAudio::setVolume(unsigned int left, unsigned int right) int cAudio::Start(void) { lt_info("%s >\n", __func__); - OpenThreads::Thread::start(); + if (! HAL_nodec) + OpenThreads::Thread::start(); lt_info("%s <\n", __func__); return 0; } @@ -126,21 +136,56 @@ int cAudio::setChannel(int /*channel*/) return 0; }; -int cAudio::PrepareClipPlay(int ch, int srate, int bits, int little_endian) +int cAudio::PrepareClipPlay(int ch, int srate, int bits, int le) { - lt_debug("%s ch %d srate %d bits %d le %d\n", __func__, ch, srate, bits, little_endian); + lt_debug("%s ch %d srate %d bits %d le %d adevice %p\n", __func__, ch, srate, bits, le, adevice);; + int driver; + int byte_format = le ? AO_FMT_LITTLE : AO_FMT_BIG; + if (sformat.bits != bits || sformat.channels != ch || sformat.rate != srate || + sformat.byte_format != byte_format || adevice == NULL) + { + driver = ao_default_driver_id(); + sformat.bits = bits; + sformat.channels = ch; + sformat.rate = srate; + sformat.byte_format = byte_format; + sformat.matrix = 0; + if (adevice) + ao_close(adevice); + adevice = ao_open_live(driver, &sformat, NULL); + ao_info *ai = ao_driver_info(driver); + lt_info("%s: changed params ch %d srate %d bits %d le %d adevice %p\n", + __func__, ch, srate, bits, le, adevice);; + lt_info("libao driver: %d name '%s' short '%s' author '%s'\n", + driver, ai->name, ai->short_name, ai->author); + } return 0; }; -int cAudio::WriteClip(unsigned char * /*buffer*/, int /*size*/) +int cAudio::WriteClip(unsigned char *buffer, int size) { - lt_debug("cAudio::%s\n", __func__); - return 0; + lt_debug("cAudio::%s buf 0x%p size %d\n", __func__, buffer, size); + if (!adevice) { + lt_info("%s: adevice not opened?\n", __func__); + return 0; + } + ao_play(adevice, (char *)buffer, size); + return size; }; int cAudio::StopClip() { lt_debug("%s\n", __func__); +#if 0 + /* don't do anything - closing / reopening ao all the time makes for long delays + * reinit on-demand (e.g. for changed parameters) instead */ + if (!adevice) { + lt_info("%s: adevice not opened?\n", __func__); + return 0; + } + ao_close(adevice); + adevice = NULL; +#endif return 0; }; @@ -232,8 +277,8 @@ void cAudio::run() int ret, driver; /* libao */ ao_info *ai; - ao_device *adevice; - ao_sample_format sformat; + // ao_device *adevice; + // ao_sample_format sformat; curr_pts = 0; av_init_packet(&avpkt); @@ -279,16 +324,24 @@ void cAudio::run() lt_info("%s: avcodec_alloc_frame failed\n", __func__); goto out2; } - driver = ao_default_driver_id(); - sformat.bits = 16; - sformat.channels = c->channels; - sformat.rate = c->sample_rate; - sformat.byte_format = AO_FMT_NATIVE; - sformat.matrix = 0; - adevice = ao_open_live(driver, &sformat, NULL); - ai = ao_driver_info(driver); - lt_info("libao driver: %d name '%s' short '%s' author '%s'\n", - driver, ai->name, ai->short_name, ai->author); + if (sformat.channels != c->channels || sformat.rate != c->sample_rate || + sformat.byte_format != AO_FMT_NATIVE || sformat.bits != 16 || adevice == NULL) + { + driver = ao_default_driver_id(); + sformat.bits = 16; + sformat.channels = c->channels; + sformat.rate = c->sample_rate; + sformat.byte_format = AO_FMT_NATIVE; + sformat.matrix = 0; + if (adevice) + ao_close(adevice); + adevice = ao_open_live(driver, &sformat, NULL); + ai = ao_driver_info(driver); + lt_info("%s: changed params ch %d srate %d bits %d adevice %p\n", + __func__, c->channels, c->sample_rate, 16, adevice);; + lt_info("libao driver: %d name '%s' short '%s' author '%s'\n", + driver, ai->name, ai->short_name, ai->author); + } #if 0 lt_info(" driver options:"); for (int i = 0; i < ai->option_count; ++i) @@ -309,7 +362,7 @@ void cAudio::run() } av_free_packet(&avpkt); } - ao_close(adevice); /* can take long :-( */ + // ao_close(adevice); /* can take long :-( */ avcodec_free_frame(&frame); out2: avcodec_close(c); diff --git a/generic-pc/dmx.cpp b/generic-pc/dmx.cpp index e771986..19d8fc4 100644 --- a/generic-pc/dmx.cpp +++ b/generic-pc/dmx.cpp @@ -76,6 +76,8 @@ static const char *devname[] = { static int dmx_tp_count = 0; #define MAX_TS_COUNT 8 +extern bool HAL_nodec; + cDemux::cDemux(int n) { if (n < 0 || n > 2) @@ -379,14 +381,20 @@ bool cDemux::pesFilter(const unsigned short pid) switch (dmx_type) { case DMX_PCR_ONLY_CHANNEL: p_flt.pes_type = DMX_PES_PCR; + if (HAL_nodec) + return true; break; case DMX_AUDIO_CHANNEL: p_flt.pes_type = DMX_PES_OTHER; p_flt.output = DMX_OUT_TSDEMUX_TAP; + if (HAL_nodec) /* no need to demux if we don't decode... */ + return true; break; case DMX_VIDEO_CHANNEL: p_flt.pes_type = DMX_PES_OTHER; p_flt.output = DMX_OUT_TSDEMUX_TAP; + if (HAL_nodec) + return true; break; case DMX_PES_CHANNEL: p_flt.pes_type = DMX_PES_OTHER; diff --git a/generic-pc/dmx_lib.h b/generic-pc/dmx_lib.h index ed38048..754511e 100644 --- a/generic-pc/dmx_lib.h +++ b/generic-pc/dmx_lib.h @@ -8,6 +8,8 @@ #include #include "../common/cs_types.h" +#define MAX_DMX_UNITS 4 + typedef enum { DMX_INVALID = 0, diff --git a/generic-pc/init.cpp b/generic-pc/init.cpp index ad272f9..5fadc88 100644 --- a/generic-pc/init.cpp +++ b/generic-pc/init.cpp @@ -9,6 +9,7 @@ static bool initialized = false; GLFramebuffer *glfb = NULL; +bool HAL_nodec = false; void init_td_api() { @@ -35,6 +36,10 @@ void init_td_api() glfb = new GLFramebuffer(x, y); /* hard coded to PAL resolution for now */ } + /* allow disabling of Audio/video decoders in case we just want to + * valgrind-check other parts... export HAL_NOAVDEC=1 */ + if (getenv("HAL_NOAVDEC")) + HAL_nodec = true; initialized = true; } diff --git a/generic-pc/video.cpp b/generic-pc/video.cpp index 429c3d9..bcce38a 100644 --- a/generic-pc/video.cpp +++ b/generic-pc/video.cpp @@ -50,6 +50,8 @@ extern cDemux *videoDemux; extern GLFramebuffer *glfb; int system_rev = 0; +extern bool HAL_nodec; + static uint8_t *dmxbuf; static int bufpos; @@ -66,7 +68,8 @@ cVideo::cVideo(int, void *, void *) { lt_debug("%s\n", __func__); av_register_all(); - dmxbuf = (uint8_t *)malloc(DMX_BUF_SZ); + if (!HAL_nodec) + dmxbuf = (uint8_t *)malloc(DMX_BUF_SZ); bufpos = 0; thread_running = false; w_h_changed = false; @@ -135,7 +138,7 @@ int cVideo::setCroppingMode(int) int cVideo::Start(void *, unsigned short, unsigned short, void *) { lt_info("%s running %d >\n", __func__, thread_running); - if (!thread_running) + if (!thread_running && !HAL_nodec) OpenThreads::Thread::start(); lt_info("%s running %d <\n", __func__, thread_running); return 0; @@ -206,8 +209,106 @@ void cVideo::SetVideoMode(analog_mode_t) { } -void cVideo::ShowPicture(const char *) +void cVideo::ShowPicture(const char *fname) { + lt_info("%s(%s)\n", __func__, fname); + if (access(fname, R_OK)) + return; + + unsigned int i; + int stream_id = -1; + int got_frame = 0; + int len; + AVFormatContext *avfc = NULL; + AVCodecContext *c = NULL; + AVCodec *codec; + AVFrame *frame, *rgbframe; + AVPacket avpkt; + + if (avformat_open_input(&avfc, fname, NULL, NULL) < 0) { + lt_info("%s: Could not open file %s\n", __func__, fname); + return; + } + + if (avformat_find_stream_info(avfc, NULL) < 0) { + lt_info("%s: Could not find file info %s\n", __func__, fname); + goto out_close; + } + for (i = 0; i < avfc->nb_streams; i++) { + if (avfc->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + stream_id = i; + break; + } + } + if (stream_id < 0) + goto out_close; + c = avfc->streams[stream_id]->codec; + codec = avcodec_find_decoder(c->codec_id); + if (!avcodec_open2(c, codec, NULL) < 0) { + lt_info("%s: Could not find/open the codec, id 0x%x\n", __func__, c->codec_id); + goto out_close; + } + frame = avcodec_alloc_frame(); + rgbframe = avcodec_alloc_frame(); + if (!frame || !rgbframe) { + lt_info("%s: Could not allocate video frame\n", __func__); + goto out_free; + } + av_init_packet(&avpkt); + if (av_read_frame(avfc, &avpkt) < 0) { + lt_info("%s: av_read_frame < 0\n", __func__); + goto out_free; + } + len = avcodec_decode_video2(c, frame, &got_frame, &avpkt); + if (len < 0) { + lt_info("%s: avcodec_decode_video2 %d\n", __func__, len); + av_free_packet(&avpkt); + goto out_free; + } + if (avpkt.size > len) + lt_info("%s: WARN: pkt->size %d != len %d\n", __func__, avpkt.size, len); + if (got_frame) { + unsigned int need = avpicture_get_size(PIX_FMT_RGB32, c->width, c->height); + struct SwsContext *convert = sws_getContext(c->width, c->height, c->pix_fmt, + c->width, c->height, PIX_FMT_RGB32, + SWS_BICUBIC, 0, 0, 0); + if (!convert) + lt_info("%s: ERROR setting up SWS context\n", __func__); + else { + buf_m.lock(); + SWFramebuffer *f = &buffers[buf_in]; + if (f->size() < need) + f->resize(need); + avpicture_fill((AVPicture *)rgbframe, &(*f)[0], PIX_FMT_RGB32, + c->width, c->height); + sws_scale(convert, frame->data, frame->linesize, 0, c->height, + rgbframe->data, rgbframe->linesize); + sws_freeContext(convert); + f->width(c->width); + f->height(c->height); + f->pts(AV_NOPTS_VALUE); + AVRational a = av_guess_sample_aspect_ratio(avfc, avfc->streams[stream_id], frame); + f->AR(a); + buf_in++; + buf_in %= VDEC_MAXBUFS; + buf_num++; + if (buf_num > (VDEC_MAXBUFS - 1)) { + lt_info("%s: buf_num overflow\n", __func__); + buf_out++; + buf_out %= VDEC_MAXBUFS; + buf_num--; + } + buf_m.unlock(); + } + } + av_free_packet(&avpkt); + out_free: + avcodec_close(c); + avcodec_free_frame(&frame); + avcodec_free_frame(&rgbframe); + out_close: + avformat_close_input(&avfc); + lt_debug("%s(%s) end\n", __func__, fname); } void cVideo::StopPicture() diff --git a/libspark/dmx_lib.h b/libspark/dmx_lib.h index e85dc3c..af87a02 100644 --- a/libspark/dmx_lib.h +++ b/libspark/dmx_lib.h @@ -8,6 +8,8 @@ #include #include "../common/cs_types.h" +#define MAX_DMX_UNITS 4 + typedef enum { DMX_INVALID = 0, diff --git a/libtriple/dmx_td.h b/libtriple/dmx_td.h index e657592..a253f3c 100644 --- a/libtriple/dmx_td.h +++ b/libtriple/dmx_td.h @@ -14,6 +14,8 @@ extern "C" { #endif #define DMX_FILTER_SIZE FILTER_LENGTH +#define MAX_DMX_UNITS 4 + typedef enum { DMX_INVALID = 0,