diff options
Diffstat (limited to 'debian/transcode/transcode-1.1.7/src/encoder-buffer.c')
| -rw-r--r-- | debian/transcode/transcode-1.1.7/src/encoder-buffer.c | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/debian/transcode/transcode-1.1.7/src/encoder-buffer.c b/debian/transcode/transcode-1.1.7/src/encoder-buffer.c new file mode 100644 index 00000000..53af7cba --- /dev/null +++ b/debian/transcode/transcode-1.1.7/src/encoder-buffer.c @@ -0,0 +1,408 @@ +/* + * encoder-buffer.c -- encoder interface to transcode frame ringbuffers. + * + * Copyright (C) Thomas Oestreich - June 2001 + * Updated and partially rewritten by + * Francesco Romani - January 2006 + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "transcode.h" +#include "decoder.h" +#include "encoder.h" +#include "filter.h" +#include "framebuffer.h" +#include "counter.h" +#include "video_trans.h" +#include "audio_trans.h" +#include "frame_threads.h" + +#include <stdint.h> +#include <sys/types.h> + +/* + * Quick Summary: + * + * This code provide glue between frames ringbuffer and real encoder + * code, in order to make encoder modular and independent from + * a single frame source, to promote reusability (tcexport). + * This code also take acare of some oddities like handling filtering + * if no frame threads are avalaible. + * + * This code isn't clean as one (i.e.: me) would like since it + * must cope with a lot of legacy constraints and some other nasty + * stuff. Of course situation will be improved in future releases + * when we keep going away from legacy oddities and continue + * sanitize/modernize the codebase. + * + * NOTE about counter/condition/mutex handling inside various + * encoder helpers. + * + * Code are still a little bit confusing since things aren't + * updated or used at the same function level. + * Code works, but isn't still well readable. + * We need stil more cleanup and refactoring for future releases. + */ + + +/*************************************************************************/ +/*************************************************************************/ + +static int have_aud_threads = 0; +static int have_vid_threads = 0; + +/*************************************************************************/ + +/* + * apply_{video,audio}_filters: + * Apply the filter chain to current respectively video + * or audio frame. + * This function is used if no frame threads are avalaible, + * but of course filtering still must be applied. + * This function should be never exported. + * + * Parameters: + * vptr, aptr: respectively video or aufio framebuffer + * pointer to frame to be filtered. + * vob: pointer to vob_t structure holding stream + * parameters. + */ +static void apply_video_filters(vframe_list_t *vptr, vob_t *vob); +static void apply_audio_filters(aframe_list_t *aptr, vob_t *vob); + +/* + * encoder_acquire_{v,a}frame: + * Get respectively a new video or audio framebuffer for encoding. + * This roughly means: + * 1. to wait for a new frame avalaible for encoder + * 2. apply the filters if no frame threads are avalaible + * 3. apply the encoder filters (POST_S_PROCESS) + * 4. verify the status of audio framebuffer after all filtering. + * if acquired framebuffer is skipped, we must acquire a new one + * before continue with encoding, so we must restart from step 1. + * + * Parameters: + * buf: encoder buffer to use (and fullfull with acquired frame). + * vob: pointer to vob_t structure describing stream parameters. + * Used Internally. + * Return Value: + * 0 when a new framebuffer is avalaible for encoding; + * <0 if no more framebuffers are avalaible. + * As for encoder_wait_{v,a}frame, this usually happens + * when video/audio stream ends. + */ +static int encoder_acquire_vframe(TCEncoderBuffer *buf, vob_t *vob); +static int encoder_acquire_aframe(TCEncoderBuffer *buf, vob_t *vob); + +/* + * encoder_dispose_{v,a}frame: + * Mark a framebuffer (respectively video or audio) as completed + * from encoder viewpoint, so release it to source ringbuffer, + * update counters and do all cleanup actions needed internally. + * + * Parameters: + * buf: encoder buffer to use (release currente framebuffers + * and update related counters and internal variables). + * Return Value: + * None. + */ +static void encoder_dispose_vframe(TCEncoderBuffer *buf); +static void encoder_dispose_aframe(TCEncoderBuffer *buf); + + +/*************************************************************************/ + +static void apply_video_filters(vframe_list_t *vptr, vob_t *vob) +{ + if (!have_vid_threads) { + if (TC_FRAME_NEED_PROCESSING(vptr)) { + /* external plugin pre-processing */ + vptr->tag = TC_VIDEO|TC_PRE_M_PROCESS; + tc_filter_process((frame_list_t *)vptr); + + /* internal processing of video */ + vptr->tag = TC_VIDEO; + process_vid_frame(vob, vptr); + + /* external plugin post-processing */ + vptr->tag = TC_VIDEO|TC_POST_M_PROCESS; + tc_filter_process((frame_list_t *)vptr); + } + } + + if (TC_FRAME_NEED_PROCESSING(vptr)) { + /* second stage post-processing - (synchronous) */ + vptr->tag = TC_VIDEO|TC_POST_S_PROCESS; + tc_filter_process((frame_list_t *)vptr); + postprocess_vid_frame(vob, vptr); + /* preview _after_ all post-processing */ + vptr->tag = TC_VIDEO|TC_PREVIEW; + tc_filter_process((frame_list_t *)vptr); + } +} + +static void apply_audio_filters(aframe_list_t *aptr, vob_t *vob) +{ + /* now we try to process the audio frame */ + if (!have_aud_threads) { + if (TC_FRAME_NEED_PROCESSING(aptr)) { + /* external plugin pre-processing */ + aptr->tag = TC_AUDIO|TC_PRE_M_PROCESS; + tc_filter_process((frame_list_t *)aptr); + + /* internal processing of audio */ + aptr->tag = TC_AUDIO; + process_aud_frame(vob, aptr); + + /* external plugin post-processing */ + aptr->tag = TC_AUDIO|TC_POST_M_PROCESS; + tc_filter_process((frame_list_t *)aptr); + } + } + + if (TC_FRAME_NEED_PROCESSING(aptr)) { + /* second stage post-processing - (synchronous) */ + aptr->tag = TC_AUDIO|TC_POST_S_PROCESS; + tc_filter_process((frame_list_t *)aptr); + /* preview _after_ all post-processing */ + aptr->tag = TC_AUDIO|TC_PREVIEW; + tc_filter_process((frame_list_t *)aptr); + } +} + +static int encoder_acquire_vframe(TCEncoderBuffer *buf, vob_t *vob) +{ + int got_frame = TC_TRUE; + + do { + buf->vptr = vframe_retrieve(); + if (!buf->vptr) { + if (verbose >= TC_THREADS) + tc_log_msg(__FILE__, "frame retrieve interrupted!"); + return -1; /* can't acquire video frame */ + } + got_frame = TC_TRUE; + buf->frame_id = buf->vptr->id + tc_get_frames_skipped_cloned(); + + if (verbose & TC_STATS) { + tc_log_info(__FILE__, "got frame %p (id=%i)", + buf->vptr, buf->frame_id); + } + + /* + * now we do the post processing ... this way, if just a video frame is + * skipped, we'll know. + * + * we have to check to make sure that before we do any processing + * that this frame isn't out of range (if it is, and one is using + * the "-t" split option, we'll see this frame again. + */ + apply_video_filters(buf->vptr, vob); + + if (buf->vptr->attributes & TC_FRAME_IS_SKIPPED) { + if (buf->vptr != NULL + && (buf->vptr->attributes & TC_FRAME_WAS_CLONED) + ) { + /* XXX do we want to track skipped cloned flags? */ + tc_update_frames_cloned(1); + } + + if (buf->vptr != NULL + && (buf->vptr->attributes & TC_FRAME_IS_CLONED) + ) { + /* XXX what to do when a frame is cloned and skipped? */ + /* + * I'd like to say they cancel, but perhaps they will end + * up also skipping the clone? or perhaps they'll keep, + * but modify the clone? Best to do the whole drill :/ + */ + if (verbose & TC_DEBUG) { + tc_log_info (__FILE__, "(%i) V pointer done. " + "Skipped and Cloned: (%i)", + buf->vptr->id, + (buf->vptr->attributes)); + } + + /* update flags */ + buf->vptr->attributes &= ~TC_FRAME_IS_CLONED; + buf->vptr->attributes |= TC_FRAME_WAS_CLONED; + /* + * this has to be done here, + * frame_threads.c won't see the frame again + */ + } + if (buf->vptr != NULL + && !(buf->vptr->attributes & TC_FRAME_IS_CLONED) + ) { + vframe_remove(buf->vptr); + /* reset pointer for next retrieve */ + buf->vptr = NULL; + } + // tc_update_frames_skipped(1); + got_frame = TC_FALSE; + } + } while (!got_frame); + + return 0; +} + +static int encoder_acquire_aframe(TCEncoderBuffer *buf, vob_t *vob) +{ + int got_frame = TC_TRUE; + + do { + buf->aptr = aframe_retrieve(); + if (!buf->aptr) { + if (verbose >= TC_THREADS) + tc_log_msg(__FILE__, "frame retrieve interrupted!"); + return -1; + } + got_frame = TC_TRUE; + + if (verbose & TC_STATS) { + tc_log_info(__FILE__, "got audio frame (id=%i)", buf->aptr->id); + } + + apply_audio_filters(buf->aptr, vob); + + if (buf->aptr->attributes & TC_FRAME_IS_SKIPPED) { + if (buf->aptr != NULL + && !(buf->aptr->attributes & TC_FRAME_IS_CLONED) + ) { + aframe_remove(buf->aptr); + /* reset pointer for next retrieve */ + buf->aptr = NULL; + } + + if (buf->aptr != NULL + && (buf->aptr->attributes & TC_FRAME_IS_CLONED) + ) { + if (verbose & TC_DEBUG) { + tc_log_info(__FILE__, "(%i) A pointer done. Skipped and Cloned: (%i)", + buf->aptr->id, (buf->aptr->attributes)); + } + + /* adjust clone flags */ + buf->aptr->attributes &= ~TC_FRAME_IS_CLONED; + buf->aptr->attributes |= TC_FRAME_WAS_CLONED; + + /* + * this has to be done here, + * frame_threads.c won't see the frame again + */ + } + got_frame = TC_FALSE; + } + } while (!got_frame); + + return 0; +} + + +static void encoder_dispose_vframe(TCEncoderBuffer *buf) +{ + if (buf->vptr != NULL + && (buf->vptr->attributes & TC_FRAME_WAS_CLONED) + ) { + tc_update_frames_cloned(1); + } + + if (buf->vptr != NULL + && !(buf->vptr->attributes & TC_FRAME_IS_CLONED) + ) { + vframe_remove(buf->vptr); + /* reset pointer for next retrieve */ + buf->vptr = NULL; + } + + if (buf->vptr != NULL + && (buf->vptr->attributes & TC_FRAME_IS_CLONED) + ) { + if(verbose & TC_DEBUG) { + tc_log_info(__FILE__, "(%i) V pointer done. Cloned: (%i)", + buf->vptr->id, (buf->vptr->attributes)); + } + buf->vptr->attributes &= ~TC_FRAME_IS_CLONED; + buf->vptr->attributes |= TC_FRAME_WAS_CLONED; + // update counter + //tc_update_frames_cloned(1); + } +} + + +static void encoder_dispose_aframe(TCEncoderBuffer *buf) +{ + if (buf->aptr != NULL + && !(buf->aptr->attributes & TC_FRAME_IS_CLONED) + ) { + aframe_remove(buf->aptr); + /* reset pointer for next retrieve */ + buf->aptr = NULL; + } + + if (buf->aptr != NULL + && (buf->aptr->attributes & TC_FRAME_IS_CLONED) + ) { + if (verbose & TC_DEBUG) { + tc_log_info(__FILE__, "(%i) A pointer done. Cloned: (%i)", + buf->aptr->id, (buf->aptr->attributes)); + } + + buf->aptr->attributes &= ~TC_FRAME_IS_CLONED; + buf->aptr->attributes |= TC_FRAME_WAS_CLONED; + } +} + + +static TCEncoderBuffer tc_builtin_buffer = { + .frame_id = 0, + + .vptr = NULL, + .aptr = NULL, + + .acquire_video_frame = encoder_acquire_vframe, + .acquire_audio_frame = encoder_acquire_aframe, + .dispose_video_frame = encoder_dispose_vframe, + .dispose_audio_frame = encoder_dispose_aframe, +}; + +/* default main transcode buffer */ +TCEncoderBuffer *tc_get_ringbuffer(int aworkers, int vworkers) +{ + have_aud_threads = aworkers; + have_vid_threads = vworkers; + + return &tc_builtin_buffer; +} + +/*************************************************************************/ + +/* + * Local variables: + * c-file-style: "stroustrup" + * c-file-offsets: ((case-label . *) (statement-case-intro . *)) + * indent-tabs-mode: nil + * End: + * + * vim: expandtab shiftwidth=4: + */ |
