diff options
Diffstat (limited to 'debian/transcode/transcode-1.1.7/import/framegen/import_framegen.c')
| -rw-r--r-- | debian/transcode/transcode-1.1.7/import/framegen/import_framegen.c | 534 |
1 files changed, 534 insertions, 0 deletions
diff --git a/debian/transcode/transcode-1.1.7/import/framegen/import_framegen.c b/debian/transcode/transcode-1.1.7/import/framegen/import_framegen.c new file mode 100644 index 00000000..ba8c77ed --- /dev/null +++ b/debian/transcode/transcode-1.1.7/import/framegen/import_framegen.c @@ -0,0 +1,534 @@ +/* + * import_framegen.c -- generate an infinite stream of synthetic frames + * for testing purposes. + * (C) 2009-2010 Francesco Romani <fromani at gmail dot com> + * using some video frame filling code which is + * Copyright (C) Thomas Oestreich - June 2001 + * some code derived by alsa-utils/speakertest, which is + * Copyright (C) 2005 Nathan Hurst + * + * This file is part of transcode, a video stream processing tool. + * + * transcode 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 2 of the License, or + * (at your option) any later version. + * + * transcode 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/>. + */ + +/*%* + *%* DESCRIPTION + *%* This module produces an infinite stream of raw synthetic frames. + *%* It is intended for testing purposes. + *%* + *%* #BUILD-DEPENDS + *%* + *%* #DEPENDS + *%* + *%* PROCESSING + *%* import/demuxer + *%* + *%* MEDIA + *%* video, audio + *%* + *%* #INPUT + *%* + *%* OUTPUT + *%* YUV420P, PCM + *%* + *%* #OPTION + *%*/ + +/* + * TODO (unordered): + * - add more generators (at least a video/RGB one) + * - review internal generator API + * -- to emit cooked frames instead of raw bytes it is better? + * -- need to explicitely separate A/V generators? + * -- need to distinguish the function to call for A/V? + * - accepts (and use!) random seed as module options + */ + +#include "src/transcode.h" +#include "aclib/imgconvert.h" +#include "libtc/optstr.h" +#include "libtc/tcmodule-plugin.h" + +#include "pink.h" + +#include "config.h" + +#define LEGACY 1 + +#ifdef LEGACY +# define MOD_NAME "import_framegen.so" +#else +# define MOD_NAME "demultiplex_framegen.so" +#endif + + +#define MOD_VERSION "v0.1.0 (2009-06-21)" +#define MOD_CAP "generate stream of testframes" +#define MOD_AUTHOR "Francesco Romani" + +#define MOD_FEATURES \ + TC_MODULE_FEATURE_DEMULTIPLEX|TC_MODULE_FEATURE_AUDIO|TC_MODULE_FEATURE_VIDEO +#define MOD_FLAGS \ + TC_MODULE_FLAG_RECONFIGURABLE + +/*************************************************************************/ + +typedef struct tcframegensource_ TCFrameGenSource; + +struct tcframegensource_ { + void *priv; + const char *name; + const char *media; + + int32_t seed; + + int (*get_data)(TCFrameGenSource *handle, + uint8_t *data, int maxdata, int *datalen); + + int (*close)(TCFrameGenSource *handle); +}; + +static int tc_framegen_source_get_data(TCFrameGenSource *handle, + uint8_t *data, int maxdata, + int *datalen) +{ + return handle->get_data(handle, data, maxdata, datalen); +} + +static int tc_framegen_source_close(TCFrameGenSource *handle) +{ + return handle->close(handle); +} + +static int framegen_generic_close(TCFrameGenSource *handle) +{ + tc_free(handle); + return TC_OK; +} + +/*************************************************************************/ + +typedef struct pinknoisedata_ PinkNoiseData; +struct pinknoisedata_ { + pink_noise_t pink; +}; + +/* only signed 16 bits LE samples supported so far */ +static int framegen_pink_noise_get_data(TCFrameGenSource *handle, + uint8_t *data, int maxdata, int *datalen) +{ + PinkNoiseData *PN = handle->priv; + int16_t *samples = (int16_t*)data; + int i; + + for (i = 0; i < maxdata; i++) { + int32_t res = generate_pink_noise_sample(&(PN->pink)) * 0x03fffffff; /* Don't use MAX volume */ + samples[i] = res >> 16; + } + + return TC_OK; +} + +static int framegen_pink_noise_init(PinkNoiseData *PN, vob_t *vob) +{ + int ret = TC_ERROR; + if (vob->a_bits == 16) { + initialize_pink_noise(&(PN->pink), 16); + /* this doesn't depend to the sample size */ + + ret = TC_OK; + } + return ret; +} + +static TCFrameGenSource *tc_framegen_source_open_audio_pink_noise(vob_t *vob, + int32_t seed) +{ + uint8_t *p = tc_zalloc(sizeof(TCFrameGenSource) + sizeof(PinkNoiseData)); + TCFrameGenSource *FG = (TCFrameGenSource*)p; + PinkNoiseData *PN = (PinkNoiseData*)(p + sizeof(TCFrameGenSource)); + if (FG) { + int ret = framegen_pink_noise_init(PN, vob); + if (ret != TC_OK) { + tc_free(p); + FG = NULL; + PN = NULL; + } else { + FG->priv = PN; + FG->name = "pink noise generator"; + FG->media = "audio"; + + FG->get_data = framegen_pink_noise_get_data; + FG->close = framegen_generic_close; + } + } + return FG; +} + +/*************************************************************************/ + +typedef struct colorwavedata_ ColorWaveData; +struct colorwavedata_ { + int width; + int height; + int index; +}; + +static int framegen_color_wave_get_data(TCFrameGenSource *handle, + uint8_t *data, int maxdata, int *datalen) + +{ + ColorWaveData *CW = handle->priv; + uint8_t *planes[3] = { NULL, NULL, NULL }; + int size = CW->width * CW->height * 3 / 2; + int x, y; + + if (maxdata < size) { + return TC_ERROR; + } + + YUV_INIT_PLANES(planes, data, IMG_YUV_DEFAULT, CW->width, CW->height); + + memset(data, 0x80, size); /* FIXME */ + + for (y = 0; y < CW->height; y++) { + for (x = 0; x < CW->width; x++) { + planes[0][y * CW->width + x] = x + y + CW->index * 3; + } + } + + for (y = 0; y < CW->height/2; y++) { + for (x = 0; x < CW->width/2; x++) { + planes[1][y * CW->width/2 + x] = 128 + y + CW->index * 2; + planes[2][y * CW->width/2 + x] = 64 + x + CW->index * 5; + } + } + + CW->index++; + *datalen = size; + + return TC_OK; +} + +static int framegen_color_wave_init(ColorWaveData *CW, vob_t *vob) +{ + int ret = TC_ERROR; + if (vob->im_v_codec == TC_CODEC_YUV420P || vob->im_v_codec == CODEC_YUV) { + CW->index = 0; + CW->width = vob->im_v_width; + CW->height = vob->im_v_height; + ret = TC_OK; + } + return ret; +} + +static TCFrameGenSource *tc_framegen_source_open_video_color_wave(vob_t *vob, + int32_t seed) +{ + uint8_t *p = tc_zalloc(sizeof(TCFrameGenSource) + sizeof(ColorWaveData)); + TCFrameGenSource *FG = (TCFrameGenSource*)p; + ColorWaveData *CW = (ColorWaveData*)(p + sizeof(TCFrameGenSource)); + if (FG) { + int ret = framegen_color_wave_init(CW, vob); + if (ret != TC_OK) { + tc_free(p); + FG = NULL; + CW = NULL; + } else { + FG->priv = CW; + FG->name = "color wave generator"; + FG->media = "video"; + + FG->get_data = framegen_color_wave_get_data; + FG->close = framegen_generic_close; + } + } + return FG; +} + +/*************************************************************************/ + +#define RETURN_IF_FAILED(RET, MSG) do { \ + if ((RET) < 0) { \ + tc_log_error(MOD_NAME, "%s", (MSG)); \ + return TC_ERROR; \ + } \ +} while (0) + +#define RETURN_IF_ERROR(RET, MSG) do { \ + if ((RET) != TC_OK) { \ + tc_log_error(MOD_NAME, "%s", (MSG)); \ + return RET; \ + } \ +} while (0) + +#define RETURN_IF_NULL(PTR, MSG) do { \ + if (!(PTR)) { \ + tc_log_error(MOD_NAME, "%s", (MSG)); \ + return TC_ERROR; \ + } \ +} while (0) + + +/*************************************************************************/ +/* New-Style module interface */ + +static const char tc_framegen_help[] = "" + "Overview:\n" + " This module reads audio samples from an ALSA device using libalsa.\n" + "Options:\n" + " device=dev selects ALSA device to use\n" + " help produce module overview and options explanations\n"; + + + +typedef struct tcframegenprivatedata_ TCFrameGenPrivateData; +struct tcframegenprivatedata_ { + TCFrameGenSource *video_gen; + TCFrameGenSource *audio_gen; +}; + + +TC_MODULE_GENERIC_INIT(tc_framegen, TCFrameGenPrivateData) + +TC_MODULE_GENERIC_FINI(tc_framegen) + +static int tc_framegen_configure(TCModuleInstance *self, + const char *options, vob_t *vob) +{ + TCFrameGenPrivateData *priv = NULL; + + TC_MODULE_SELF_CHECK(self, "configure"); + + priv = self->userdata; + + /* FIXME: add proper option handling/mode selection */ + + priv->video_gen = tc_framegen_source_open_video_color_wave(vob, 0); + RETURN_IF_NULL((priv->video_gen), + "configure: failed to open the video frame generator"); + + priv->audio_gen = tc_framegen_source_open_audio_pink_noise(vob, 0); + RETURN_IF_NULL((priv->audio_gen), + "configure: failed to open the audio frame generator"); + + return TC_OK; +} + +static int tc_framegen_inspect(TCModuleInstance *self, + const char *param, const char **value) +{ + TC_MODULE_SELF_CHECK(self, "inspect"); + + if (optstr_lookup(param, "help")) { + *value = tc_framegen_help; + } + + return TC_OK; +} + +static int tc_framegen_stop(TCModuleInstance *self) +{ + TCFrameGenPrivateData *priv = NULL; + int ret = 0; + + TC_MODULE_SELF_CHECK(self, "stop"); + + priv = self->userdata; + + ret = tc_framegen_source_close(priv->video_gen); + RETURN_IF_ERROR(ret, "stop: failed to close the video frame generator"); + + ret = tc_framegen_source_close(priv->audio_gen); + RETURN_IF_ERROR(ret, "stop: failed to close the audio frame generator"); + + return TC_OK; +} + +static int tc_framegen_demultiplex(TCModuleInstance *self, + TCFrameVideo *vframe, TCFrameAudio *aframe) +{ + int vret = 0, aret = 0; + TCFrameGenPrivateData *priv = NULL; + + TC_MODULE_SELF_CHECK(self, "demultiplex"); + + priv = self->userdata; + + if (vframe != NULL) { + vret = tc_framegen_source_get_data(priv->video_gen, + vframe->video_buf, + vframe->video_size, + &vframe->video_len); + RETURN_IF_FAILED(vret, "demux: failed to pull a new video frame"); + } + + if (aframe != NULL) { + aret = tc_framegen_source_get_data(priv->audio_gen, + aframe->audio_buf, + aframe->audio_size, + &aframe->audio_len); + RETURN_IF_FAILED(aret, "demux: failed to pull a new audio frame"); + } + return (vret + aret); +} + +/*************************************************************************/ + +static const TCCodecID tc_framegen_codecs_in[] = { TC_CODEC_ERROR }; + +/* a demultiplexor is at the begin of the pipeline */ +static const TCCodecID tc_framegen_codecs_out[] = { + TC_CODEC_YUV420P, + TC_CODEC_PCM, + TC_CODEC_ERROR, +}; + +static const TCFormatID tc_framegen_formats_in[] = { + TC_FORMAT_ERROR, +}; + +static const TCFormatID tc_framegen_formats_out[] = { TC_FORMAT_ERROR }; + +static const TCModuleInfo tc_framegen_info = { + .features = MOD_FEATURES, + .flags = MOD_FLAGS, + .name = MOD_NAME, + .version = MOD_VERSION, + .description = MOD_CAP, + .codecs_in = tc_framegen_codecs_in, + .codecs_out = tc_framegen_codecs_out, + .formats_in = tc_framegen_formats_in, + .formats_out = tc_framegen_formats_out +}; + +static const TCModuleClass tc_framegen_class = { + TC_MODULE_CLASS_HEAD(tc_framegen), + + .init = tc_framegen_init, + .fini = tc_framegen_fini, + .configure = tc_framegen_configure, + .stop = tc_framegen_stop, + .inspect = tc_framegen_inspect, + + .demultiplex = tc_framegen_demultiplex, +}; + +TC_MODULE_ENTRY_POINT(tc_framegen) + +/*************************************************************************/ +/* Old-Style module interface */ +/*************************************************************************/ + + +static TCFrameGenPrivateData mod_framegen; + +static int verbose_flag = TC_QUIET; +static int capability_flag = TC_CAP_YUV|TC_CAP_PCM; + +#define MOD_PRE framegen +#define MOD_CODEC "(video) YUV | (audio) PCM" + +#include "import_def.h" + +/*************************************************************************/ + +#define RETURN_WITH_MSG(RET, MSG) do { \ + if ((RET) != TC_OK) { \ + tc_log_error(MOD_NAME, "%s", (MSG)); \ + return RET; \ + } \ + return TC_OK; \ +} while (0) + + + +MOD_open +{ + if(param->flag == TC_AUDIO) { + param->fd = NULL; + mod_framegen.audio_gen = tc_framegen_source_open_audio_pink_noise(vob, 0); + + RETURN_IF_NULL((mod_framegen.audio_gen), + "MOD_open: failed to open the audio frame generator"); + return TC_OK; + } + + if(param->flag == TC_VIDEO) { + param->fd = NULL; + mod_framegen.video_gen = tc_framegen_source_open_video_color_wave(vob, 0); + + RETURN_IF_NULL((mod_framegen.video_gen), + "configure: failed to open the video frame generator"); + return TC_OK; + } + + return TC_ERROR; +} + +MOD_decode +{ + int ret; + + if (param->flag == TC_AUDIO) { + ret = tc_framegen_source_get_data(mod_framegen.audio_gen, + param->buffer, + param->size, + ¶m->size); + RETURN_WITH_MSG(ret, "MOD_decode: failed to pull a new audio frame"); + } + + if(param->flag == TC_VIDEO) { + ret = tc_framegen_source_get_data(mod_framegen.video_gen, + param->buffer, + param->size, + ¶m->size); + RETURN_WITH_MSG(ret, "MOD_decode: failed to pull a new video frame"); + } + + return TC_ERROR; +} + +MOD_close +{ + int ret; + + if(param->flag == TC_AUDIO) { + ret = tc_framegen_source_close(mod_framegen.audio_gen); + RETURN_WITH_MSG(ret, + "MOD_close: failed to close the audio frame generator"); + } + + if(param->flag == TC_VIDEO) { + ret = tc_framegen_source_close(mod_framegen.video_gen); + RETURN_WITH_MSG(ret, + "MOD_close: failed to close the video frame generator"); + } + + return TC_ERROR; +} + +/*************************************************************************/ + +/* + * Local variables: + * c-file-style: "stroustrup" + * c-file-offsets: ((case-label . *) (statement-case-intro . *)) + * indent-tabs-mode: nil + * End: + * + * vim: expandtab shiftwidth=4: + */ + |
