/* * export_dvraw.c * * Copyright (C) Thomas Östreich - June 2001 * * 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. * */ #include #include #include #include "transcode.h" #include "vid_aux.h" #include "optstr.h" #include "ioaux.h" #define MOD_NAME "export_dvraw.so" #define MOD_VERSION "v0.4a3 (2006-02-01)" #define MOD_CODEC "(video) Digital Video | (audio) PCM" static int verbose_flag=TC_QUIET; static int capability_flag=TC_CAP_PCM|TC_CAP_RGB|TC_CAP_YUV|TC_CAP_VID|TC_CAP_YUV422; #define MOD_PRE dvraw #include "export_def.h" static int fd; static int16_t *audio_bufs[4]; static uint8_t *target = NULL; static dv_encoder_t *encoder = NULL; static uint8_t *pixels[3], *tmp_buf; static int frame_size=0, format=0; static int pass_through=0; static int chans, rate; static int dv_yuy2_mode=0; static int dv_uyvy_mode=0; static int media_type = 0; /* Allocate a buffer aligned to the machine's page size, if known. The * buffer must be freed with buffree() (not free()). */ void *_tc_bufalloc(const char *file, int line, size_t size) { #ifdef HAVE_GETPAGESIZE unsigned long pagesize = getpagesize(); int8_t *base = malloc(size + sizeof(void *) + pagesize); int8_t *ptr = NULL; unsigned long offset = 0; if (base == NULL) { fprintf(stderr, "[%s:%d] tc_bufalloc(): can't allocate %lu bytes\n", file, line, (unsigned long)size); } else { ptr = base + sizeof(void *); offset = (unsigned long)ptr % pagesize; if (offset) ptr += (pagesize - offset); ((void **)ptr)[-1] = base; /* save the base pointer for freeing */ } return ptr; #else /* !HAVE_GETPAGESIZE */ return malloc(size); #endif } /* Free a buffer allocated with tc_bufalloc(). */ void tc_buffree(void *ptr) { #ifdef HAVE_GETPAGESIZE if (ptr) free(((void **)ptr)[-1]); #else free(ptr); #endif } #define tc_bufalloc(size) \ _tc_bufalloc(__FILE__, __LINE__, size) /* ------------------------------------------------------------ * * init codec * * ------------------------------------------------------------*/ MOD_init { int i; if (param->flag == TC_VIDEO) { int want_tmp_buf = 0; target = tc_bufalloc(TC_FRAME_DV_PAL); if (vob->dv_yuy2_mode) { tmp_buf = tc_bufalloc(PAL_W*PAL_H*2); //max frame dv_yuy2_mode = 1; want_tmp_buf = 1; } if (vob->im_v_codec == CODEC_YUV422) { tmp_buf = tc_bufalloc(PAL_W*PAL_H*2); //max frame dv_uyvy_mode = 1; want_tmp_buf = 1; } if (!target || (want_tmp_buf && !tmp_buf)) { fprintf(stderr, "[%s] can't allocate video buffers\n", MOD_NAME); return(TC_EXPORT_ERROR); } encoder = dv_encoder_new(FALSE, FALSE, FALSE); if (!encoder) { fprintf(stderr, "[%s] can't allocate video encoder\n", MOD_NAME); return(TC_EXPORT_ERROR); } media_type |= TC_VIDEO; return(TC_EXPORT_OK); } if (param->flag == TC_AUDIO) { if (!(media_type & TC_VIDEO)) { return(TC_EXPORT_ERROR); } // tmp audio buffer for (i = 0; i < 4; i++) { audio_bufs[i] = malloc(DV_AUDIO_MAX_SAMPLES * sizeof(int16_t)); if (!(audio_bufs[i])) { fprintf(stderr, "[%s] can't allocate audio buffers\n", MOD_NAME); return(TC_EXPORT_ERROR); } } media_type |= TC_AUDIO; return(TC_EXPORT_OK); } // invalid flag return(TC_EXPORT_ERROR); } /* ------------------------------------------------------------ * * open outputfile * * ------------------------------------------------------------*/ MOD_open { if (param->flag == TC_VIDEO) { // video if ((fd = open(vob->video_out_file, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH))<0) { perror("open file"); return(TC_EXPORT_ERROR); } switch (vob->im_v_codec) { case CODEC_RGB: format = 0; if (verbose & TC_DEBUG) { fprintf(stderr, "[%s] raw format is RGB\n", MOD_NAME); } break; case CODEC_YUV: format = 1; if (verbose & TC_DEBUG) { fprintf(stderr, "[%s] raw format is YV12\n", MOD_NAME); } break; case CODEC_YUV422: format = 1; if (verbose & TC_DEBUG) { fprintf(stderr, "[%s] raw format is UYVY\n", MOD_NAME); } break; case CODEC_RAW: /* fallthrough */ case CODEC_RAW_YUV: format = 1; pass_through = 1; break; default: fprintf(stderr, "[%s] codec not supported (0x%x)\n", MOD_NAME, vob->im_v_codec); return(TC_EXPORT_ERROR); } // for reading frame_size = (vob->ex_v_height==PAL_H) ? TC_FRAME_DV_PAL:TC_FRAME_DV_NTSC; if (verbose & TC_DEBUG) { fprintf(stderr, "[%s] encoding to %s DV\n", MOD_NAME, (vob->ex_v_height==PAL_H) ? "PAL":"NTSC"); } // Store aspect ratio - ex_asr uses the value 3 for 16x9 encoder->is16x9 = ((vob->ex_asr<0) ? vob->im_asr:vob->ex_asr) == 3; encoder->isPAL = (vob->ex_v_height==PAL_H); encoder->vlc_encode_passes = 3; encoder->static_qno = 0; if (vob->ex_v_string != NULL) { if (optstr_get (vob->ex_v_string, "qno", "%d", &encoder->static_qno) == 1) { fprintf(stderr, "[%s] using quantisation: %d\n", MOD_NAME, encoder->static_qno); } } encoder->force_dct = DV_DCT_AUTO; return(TC_EXPORT_OK); } if (param->flag == TC_AUDIO) { int bytealignment; int bytespersecond; int bytesperframe; chans = vob->dm_chan; //re-sampling only with -J resample possible rate = vob->a_rate; bytealignment = (chans==2) ? 4:2; bytespersecond = rate * bytealignment; bytesperframe = bytespersecond/(encoder->isPAL ? 25 : 30); if (verbose & TC_DEBUG) { fprintf(stderr, "[%s] audio: CH=%d, f=%d, balign=%d, bps=%d, bpf=%d\n", MOD_NAME, chans, rate, bytealignment, bytespersecond, bytesperframe); } return(TC_EXPORT_OK); } // invalid flag return(TC_EXPORT_ERROR); } /* ------------------------------------------------------------ * * encode and export * * ------------------------------------------------------------*/ MOD_encode { int i; time_t now = time(NULL); if (param->flag == TC_VIDEO) { if (pass_through) { tc_memcpy(target, param->buffer, frame_size); } else { pixels[0] = param->buffer; if (encoder->isPAL) { pixels[2] = param->buffer + PAL_W*PAL_H; pixels[1] = param->buffer + (PAL_W*PAL_H*5)/4; } else { pixels[2] = param->buffer + NTSC_W*NTSC_H; pixels[1] = param->buffer + (NTSC_W*NTSC_H*5)/4; } if (dv_yuy2_mode && !dv_uyvy_mode) { yv12toyuy2(pixels[0], pixels[1], pixels[2], tmp_buf, PAL_W, (encoder->isPAL)? PAL_H : NTSC_H); pixels[0]=tmp_buf; } if (dv_uyvy_mode) { uyvytoyuy2(pixels[0], tmp_buf, PAL_W, (encoder->isPAL)? PAL_H : NTSC_H); pixels[0]=tmp_buf; } dv_encode_full_frame(encoder, pixels, (format)?e_dv_color_yuv:e_dv_color_rgb, target); }//no pass-through #ifdef LIBDV_099 encoder->samples_this_frame = param->size; #endif dv_encode_metadata(target, encoder->isPAL, encoder->is16x9, &now, 0); dv_encode_timecode(target, encoder->isPAL, 0); if (media_type == TC_VIDEO) { /* only video */ if (p_write(fd, target, frame_size) != frame_size) { perror("write video frame"); return(TC_EXPORT_ERROR); } } /* * else (only case: this module used *also* for audio) be lazy * and wait for writing data after the audio encoding */ return(TC_EXPORT_OK); } if (param->flag == TC_AUDIO) { #ifdef WORDS_BIGENDIAN for (i = 0; i < param->size; i += 2) { char tmp = param->buffer[i]; param->buffer[i] = param->buffer[i+1]; param->buffer[i+1] = tmp; } #endif // Although dv_encode_full_audio supports 4 channels, the internal // PCM data (param->buffer) is only carrying 2 channels so only deal // with 1 or 2 channel audio. // Work around apparent bug in dv_encode_full_audio when chans == 1 // by putting silence in 2nd channel and calling with chans = 2 if (chans == 1) { audio_bufs[0] = (int16_t *)param->buffer; memset(audio_bufs[1], 0, DV_AUDIO_MAX_SAMPLES * 2); dv_encode_full_audio(encoder, audio_bufs, 2, rate, target); } else { // assume 2 channel, demultiplex for libdv API for (i = 0; i < param->size/4; i++) { audio_bufs[0][i] = ((int16_t *)param->buffer)[i*2]; audio_bufs[1][i] = ((int16_t *)param->buffer)[i*2+1]; } dv_encode_full_audio(encoder, audio_bufs, chans, rate, target); } /* write raw DV frame. */ if (p_write(fd, target, frame_size) != frame_size) { perror("write frame"); return(TC_EXPORT_ERROR); } return(TC_EXPORT_OK); } // invalid flag return(TC_EXPORT_ERROR); } /* ------------------------------------------------------------ * * stop encoder * * ------------------------------------------------------------*/ MOD_stop { int i; if (param->flag == TC_VIDEO) { dv_encoder_free(encoder); return(TC_EXPORT_OK); } if (param->flag == TC_AUDIO) { for (i = 0; i < 4; i++) { free(audio_bufs[i]); } return(TC_EXPORT_OK); } return(TC_EXPORT_ERROR); } /* ------------------------------------------------------------ * * close outputfiles * * ------------------------------------------------------------*/ MOD_close { if (param->flag == TC_VIDEO) { close(fd); return(TC_EXPORT_OK); } if (param->flag == TC_AUDIO) { return(TC_EXPORT_OK); } return(TC_EXPORT_ERROR); }