diff options
| author | Michele Calgaro <michele.calgaro@yahoo.it> | 2020-09-11 14:38:47 +0900 |
|---|---|---|
| committer | Michele Calgaro <michele.calgaro@yahoo.it> | 2020-09-11 14:38:47 +0900 |
| commit | 884c8093d63402a1ad0b502244b791e3c6782be3 (patch) | |
| tree | a600d4ab0d431a2bdfe4c15b70df43c14fbd8dd0 /debian/transcode/transcode-1.1.7/import/decode_dv.c | |
| parent | 14e1aa2006796f147f3f4811fb908a6b01e79253 (diff) | |
| download | extra-dependencies-884c8093d63402a1ad0b502244b791e3c6782be3.tar.gz extra-dependencies-884c8093d63402a1ad0b502244b791e3c6782be3.zip | |
Added debian extra dependency packages.
Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
Diffstat (limited to 'debian/transcode/transcode-1.1.7/import/decode_dv.c')
| -rw-r--r-- | debian/transcode/transcode-1.1.7/import/decode_dv.c | 615 |
1 files changed, 615 insertions, 0 deletions
diff --git a/debian/transcode/transcode-1.1.7/import/decode_dv.c b/debian/transcode/transcode-1.1.7/import/decode_dv.c new file mode 100644 index 00000000..0026924e --- /dev/null +++ b/debian/transcode/transcode-1.1.7/import/decode_dv.c @@ -0,0 +1,615 @@ +/* + * decode_dv.c - Digital Video decoding routines, using libdv + * Written by Andrew Church <achurch@achurch.org> + * + * This file is part of transcode, a video stream processing tool. + * transcode is free software, distributable under the terms of the GNU + * General Public License (version 2 or later). See the file COPYING + * for details. + */ + +#include "transcode.h" +#include "tcinfo.h" +#include "libtcvideo/tcvideo.h" +#include "ioaux.h" /* for import_exit() prototype */ +#include "tc.h" /* for function prototypes */ + +#ifdef HAVE_LIBDV +# include <libdv/dv.h> +#endif + +#define DV_FRAME_SIZE_525_60 120000 +#define DV_FRAME_SIZE_625_50 144000 + +/* Redefine libdv constants to match our naming style */ +#define DV_SYSTEM_525_60 e_dv_system_525_60 +#define DV_SYSTEM_625_50 e_dv_system_625_50 +#define DV_COLOR_YUV e_dv_color_yuv +#define DV_COLOR_RGB e_dv_color_rgb + +/*************************************************************************/ + +#ifdef HAVE_LIBDV + +/** + * check_yuy2: Internal routine to check whether libdv returns YUY2 or + * YV12 data for PAL DV frames. + * + * Parameters: + * None. + * Return value: + * 1 if the decoded video data is in YUY2 format, + * 0 if the decoded video data is in YV12 format, + * -1 if the decoded video data format is unknown. + */ + +static int check_yuy2(void) +{ + static uint8_t dv_frame[12][150][80]; /* Input DV frame (generated) */ + static uint8_t Y[720*576*2]; /* Output Y/YUY2 plane */ + static uint8_t U[(720/2)*(576/2)]; /* Output U plane */ + static uint8_t V[(720/2)*(576/2)]; /* Output V plane */ + uint8_t *video[3] = {Y, U, V}; + int linesize[3] = {720*2, 720/2, 720/2}; + dv_decoder_t *decoder; + int i, j, k; + + /* Generate an off-white PAL DV frame (Y=0xD0 U/V=0x80) */ + for (i = 0; i < 12; i++) { + dv_frame[i][0][0] = 0x1F; + dv_frame[i][0][1] = i<<4 | 0x07; + dv_frame[i][0][2] = 0x00; + dv_frame[i][0][3] = 0xBF; + dv_frame[i][0][4] = 0x68; + dv_frame[i][0][5] = 0x78; + dv_frame[i][0][6] = 0x78; + dv_frame[i][0][7] = 0x78; + memset(&dv_frame[i][0][8], 0xFF, 72); + for (j = 0; j < 2; j++) { + dv_frame[i][j+1][0] = 0x3F; + dv_frame[i][j+1][1] = i<<4 | 0x07; + dv_frame[i][j+1][2] = j; + dv_frame[i][j+1][3] = (i>=6 ? 0x80 : 0) | ((i+12) >> 3); + dv_frame[i][j+1][4] = ((i+12) << 5) | (j*6); + memset(&dv_frame[i][j+1][5], 0xFF, 75); + } + for (j = 0; j < 3; j++) { + dv_frame[i][j+3][0] = 0x5F; + dv_frame[i][j+3][1] = i<<4 | 0x07; + dv_frame[i][j+3][2] = j; + memset(&dv_frame[i][j+3][3], 0xFF, 77); + if (i == 0 && j == 0) { + dv_frame[i][j+3][ 3] = 0x70; + dv_frame[i][j+3][ 4] = 0xC5; + dv_frame[i][j+3][ 5] = 0x41; + dv_frame[i][j+3][ 6] = 0x20; + dv_frame[i][j+3][ 7] = 0xFF; + dv_frame[i][j+3][ 8] = 0x71; + dv_frame[i][j+3][ 9] = 0xFF; + dv_frame[i][j+3][10] = 0x7F; + dv_frame[i][j+3][11] = 0xFF; + dv_frame[i][j+3][12] = 0xFF; + dv_frame[i][j+3][13] = 0x7F; + dv_frame[i][j+3][14] = 0xFF; + dv_frame[i][j+3][15] = 0xFF; + dv_frame[i][j+3][16] = 0x38; + dv_frame[i][j+3][17] = 0x81; + } else if (j == 2) { + dv_frame[i][j+3][48] = 0x60; + dv_frame[i][j+3][48] = 0xFF; + dv_frame[i][j+3][48] = 0xFF; + dv_frame[i][j+3][48] = 0x20; + dv_frame[i][j+3][48] = 0xFF; + dv_frame[i][j+3][48] = 0x61; + dv_frame[i][j+3][48] = 0x33; + dv_frame[i][j+3][48] = 0xC8; + dv_frame[i][j+3][48] = 0xFD; + dv_frame[i][j+3][48] = 0xFF; + } + } + for (j = 0; j < 9; j++) { + dv_frame[i][j*16+6][0] = 0x7B; + dv_frame[i][j*16+6][1] = i<<4 | 0x07; + dv_frame[i][j*16+6][2] = j; + if (j == 0) { + dv_frame[i][j*16+6][3] = 0x50; + dv_frame[i][j*16+6][4] = 0xD8; + dv_frame[i][j*16+6][5] = i>=6 ? 0x01 : 0x00; + dv_frame[i][j*16+6][6] = 0xE0; + dv_frame[i][j*16+6][7] = 0xC0; + } else if (j == 1) { + dv_frame[i][j*16+6][3] = 0x51; + dv_frame[i][j*16+6][4] = 0x33; + dv_frame[i][j*16+6][5] = 0xCF; + dv_frame[i][j*16+6][6] = 0xA0; + dv_frame[i][j*16+6][7] = 0xFF; + } else { + dv_frame[i][j*16+6][3] = 0xFF; + dv_frame[i][j*16+6][4] = 0xFF; + dv_frame[i][j*16+6][5] = 0xFF; + dv_frame[i][j*16+6][6] = 0xFF; + dv_frame[i][j*16+6][7] = 0xFF; + } + memset(&dv_frame[i][j*16+6][8], 0, 72); + for (k = 0; k < 15; k++) { + dv_frame[i][j*16+k+7][0] = 0x9B; + dv_frame[i][j*16+k+7][1] = i<<4 | 0x07; + dv_frame[i][j*16+k+7][2] = j*15 + k; + dv_frame[i][j*16+k+7][3] = 0x0F; + memset(&dv_frame[i][4], 0, 76); + dv_frame[i][j*16+k+7][ 4] = 0x50; + dv_frame[i][j*16+k+7][ 5] = 0x06; + dv_frame[i][j*16+k+7][18] = 0x50; + dv_frame[i][j*16+k+7][19] = 0x06; + dv_frame[i][j*16+k+7][32] = 0x50; + dv_frame[i][j*16+k+7][33] = 0x06; + dv_frame[i][j*16+k+7][46] = 0x50; + dv_frame[i][j*16+k+7][47] = 0x06; + dv_frame[i][j*16+k+7][61] = 0x16; + dv_frame[i][j*16+k+7][71] = 0x26; + } + } + } + + /* Decode the generated frame */ + decoder = dv_decoder_new(1, 0, 0); + if (!decoder) { + if (verbose & TC_DEBUG) { + tc_log_warn(__FILE__, + "check_yuy2: Unable to initialize DV decoder"); + } + return -1; + } + decoder->quality = DV_QUALITY_BEST; + if (dv_parse_header(decoder, (uint8_t *)dv_frame) < 0) { + if (verbose & TC_DEBUG) { + tc_log_warn(__FILE__, + "check_yuy2: Parsing test DV frame header failed"); + } + return -1; + } + dv_decode_full_frame(decoder, (uint8_t *)dv_frame, DV_COLOR_YUV, + video, linesize); + dv_decoder_free(decoder); + + /* Return whether the frame is YUY2-encoded or not */ + if (Y[0] >= 0xCF && Y[0] <= 0xD1) { + if (Y[1] >= 0xCF && Y[1] <= 0xD1) { + /* Planar YUV data */ + return 0; + } else if (Y[1] >= 0x7F && Y[1] <= 0x81) { + /* Packed YUY2 data */ + return 1; + } + } + /* Else a buggy library? */ + if (verbose & TC_DEBUG) { + tc_log_warn(__FILE__, + "check_yuy2: Bad video data (Y=%02X %02X %02X %02X," + " U=%02X %02X, V=%02X %02X)", Y[0], Y[1], Y[2], Y[3], + U[0], U[1], V[0], V[1]); + } + + return -1; +} + +#endif // HAVE_LIBDV + +/*************************************************************************/ + +/** + * decode_dv: DV decoding loop, called from tcdecode. Reads raw DV frames + * from stdin and writes the decoded video or audio data to stdout. + * + * Parameters: + * decode: Pointer to decoding parameter structure. + * Return value: + * None. + */ + +void decode_dv(decode_t *decode) +{ +#ifdef HAVE_LIBDV + + dv_decoder_t *decoder; + /* FIXME: should this buffer be static instead (to reduce stack usage)? */ + uint8_t framebuf[DV_FRAME_SIZE_625_50]; /* Buffer for input frame */ + uint8_t *video[3]; /* Decoded video data */ + uint8_t *video_conv_buf[3]; /* For YUY2/420P conversion */ + TCVHandle tcvhandle; /* For YUY2/420P conversion */ + ImageFormat srcfmt = 0, destfmt = 0; /* For YUY2/420P conversion */ + dv_color_space_t colorspace = 0; /* For dv_decode_full_frame() */ + int linesize[3], planesize[3]; /* video[] line/plane size */ + int video_conv_linesize[3]; /* Same, for video_conv_buf[] */ + int16_t audio_in[4][DV_AUDIO_MAX_SAMPLES]; /* Decoded audio data */ + int16_t *audio_inptr[4]; /* List of pointers for same */ + int16_t audio_out[4*DV_AUDIO_MAX_SAMPLES]; /* Interleaved audio data */ + int yuy2_mode; /* libdv YUY2/YV12 selector */ + int error = 0; /* Set to signal an error */ + int ispal; /* Is it a 625/50 stream? */ + int nread; /* Result of tc_pread() */ + + + /**** Sanity check and variable setup ****/ + + if (!decode) { + tc_log_error(__FILE__, "Invalid parameter to decode_dv()"); + import_exit(1); + return; + } + audio_inptr[0] = audio_in[0]; + audio_inptr[1] = audio_in[1]; + audio_inptr[2] = audio_in[2]; + audio_inptr[3] = audio_in[3]; + + /**** Initialize libtcvideo for potential image format conversion ****/ + + tcvhandle = tcv_init(); + if (!tcvhandle) { + tc_log_error(__FILE__, "Unable to initialize libtcvideo"); + import_exit(1); + return; + } + + /**** Initialize libdv decoder ****/ + + decoder = dv_decoder_new(1, 0, 0); + if (!decoder) { + tc_log_error(__FILE__, "Unable to initialize DV decoder"); + import_exit(1); + return; + } + switch (decode->quality) { + case 1: decoder->quality = DV_QUALITY_FASTEST; break; + case 2: decoder->quality = DV_QUALITY_AC_1; break; + case 3: decoder->quality = DV_QUALITY_AC_2; break; + case 4: decoder->quality = DV_QUALITY_AC_1 | DV_QUALITY_COLOR; break; + case 5: + default: decoder->quality = DV_QUALITY_BEST; break; + } + + /**** Set up image formats and line size per plane (*16) ****/ + + switch (decode->format) { + case TC_CODEC_YUV420P: + srcfmt = IMG_UNKNOWN; /* Source format not yet known */ + destfmt = IMG_YUV420P; + colorspace = DV_COLOR_YUV; + linesize[0] = 16; + linesize[1] = linesize[2] = 8; + break; + case TC_CODEC_YUY2: + srcfmt = IMG_UNKNOWN; /* Source format not yet known */ + destfmt = IMG_YUY2; + colorspace = DV_COLOR_YUV; + linesize[0] = 32; + linesize[1] = linesize[2] = 0; + break; + case TC_CODEC_RGB: + srcfmt = destfmt = IMG_RGB24; + colorspace = DV_COLOR_RGB; + linesize[0] = 48; + linesize[1] = linesize[2] = 0; + break; + case TC_CODEC_PCM: + linesize[0] = linesize[1] = linesize[2] = 0; // what video? ;) + break; + default: + tc_log_error(__FILE__, "Invalid output format (%08lX)", + decode->format); + import_exit(1); + return; + } + + /**** Read the first frame and analyze the frame header. We start **** + **** by reading in enough data for an NTSC frame; if it turns out **** + **** to be PAL instead, we read the rest of it once we find that **** + **** out. ****/ + + nread = tc_pread(decode->fd_in, framebuf, DV_FRAME_SIZE_525_60); + if (nread != DV_FRAME_SIZE_525_60) { + tc_log_error(__FILE__, "No DV frames found!"); + import_exit(1); + return; + } + if (dv_parse_header(decoder, framebuf) < 0) { + tc_log_error(__FILE__, "Unable to parse frame header!"); + import_exit(1); + return; + } + if (decoder->system == DV_SYSTEM_525_60) { + ispal = 0; + } else if (decoder->system == DV_SYSTEM_625_50) { + ispal = 1; + } else { + tc_log_error(__FILE__, "Unknown or invalid DV frame type!"); + import_exit(1); + return; + } + if (ispal) { + nread = tc_pread(decode->fd_in, framebuf + DV_FRAME_SIZE_525_60, + DV_FRAME_SIZE_625_50 - DV_FRAME_SIZE_525_60); + if (nread != DV_FRAME_SIZE_625_50 - DV_FRAME_SIZE_525_60) { + tc_log_error(__FILE__, "No DV frames found!"); + import_exit(1); + return; + } + } + + /**** Print a stream information summary ****/ + + if (verbose) { + if (decode->format == TC_CODEC_PCM) { + tc_log_info(__FILE__, "audio: %d Hz, %d channels", + decoder->audio->frequency, + decoder->audio->num_channels); + } else { + tc_log_info(__FILE__, "%s video: %dx%d framesize=%lu sampling=%d", + ispal ? "PAL" : "NTSC", decoder->width, + decoder->height, (unsigned long)decoder->frame_size, + decoder->sampling); + } + } + + /**** Allocate video buffers ****/ + + /* Plane 0: packed RGB, packed YUV, or planar Y */ + linesize[0] = (linesize[0] * decoder->width) / 16; + planesize[0] = linesize[0] * decoder->height; + + /* Plane 1: planar U (half height) */ + linesize[1] = (linesize[1] * decoder->width) / 16; + planesize[1] = linesize[1] * (decoder->height/2); + + /* Plane 2: planar V (half height) */ + linesize[2] = (linesize[2] * decoder->width) / 16; + planesize[2] = linesize[2] * (decoder->height/2); + + /* Set up pointers into a contiguous buffer */ + video[0] = tc_bufalloc(planesize[0] + planesize[1] + planesize[2]); + video[1] = video[0] + planesize[0]; + video[2] = video[1] + planesize[1]; + + /* Conversion buffer (allocate just in case) */ + video_conv_buf[0] = tc_bufalloc(decoder->width * decoder->height * 2); + video_conv_buf[1] = video_conv_buf[0] + decoder->width * decoder->height; + video_conv_buf[2] = video_conv_buf[1] + (decoder->width/2)*decoder->height; + + /* Make sure we got everything we need */ + if (!video[0] || !video_conv_buf[0]) { + tc_log_error(__FILE__, "No memory for video buffers!"); + tc_buffree(video_conv_buf[0]); + tc_buffree(video[0]); + import_exit(1); + return; + } + + /**** Determine whether YUV data is YUY2 or YV12 (really I420??) ****/ + + if (ispal) { + if (decode->dv_yuy2_mode != -1) { + /* User specified --dv_yuy2_mode or --dv_yv12_mode */ + yuy2_mode = decode->dv_yuy2_mode; + } else { + int result = check_yuy2(); + if (result >= 1) + yuy2_mode = result; + else /* we don't know, use the libdv default of YUY2 as a guess */ + yuy2_mode = 1; + } + } else { + /* NTSC is always returned in YUY2 format */ + yuy2_mode = 1; + } + if (srcfmt == IMG_UNKNOWN) { + if (yuy2_mode) { + srcfmt = IMG_YUY2; + video_conv_linesize[0] = decoder->width * 2; + video_conv_linesize[1] = video_conv_linesize[2] = 0; + } else { + srcfmt = IMG_YUV420P; + video_conv_linesize[0] = decoder->width; + video_conv_linesize[1] = video_conv_linesize[2] = decoder->width/2; + } + } + + /**** Decoding loop ****/ + + for (;;) { + int toread; + + /* Process the data as requested */ + + switch (decode->format) { + + case TC_CODEC_YUV420P: + case TC_CODEC_YUY2: + case TC_CODEC_RGB: + if (srcfmt == destfmt) { + dv_decode_full_frame(decoder, framebuf, colorspace, video, + linesize); + } else { + dv_decode_full_frame(decoder, framebuf, colorspace, + video_conv_buf, video_conv_linesize); + if (!tcv_convert(tcvhandle, video_conv_buf[0], video[0], + decoder->width, decoder->height, + srcfmt, destfmt)) { + tc_log_error(__FILE__, "Image format conversion failed!"); + error = 1; + goto done; + } + } + if ((planesize[0] && tc_pwrite(decode->fd_out, video[0], + planesize[0]) != planesize[0]) + || (planesize[1] && tc_pwrite(decode->fd_out, video[1], + planesize[1]) != planesize[1]) + || (planesize[2] && tc_pwrite(decode->fd_out, video[2], + planesize[2]) != planesize[2]) + ) { + tc_log_error(__FILE__, "Write failed: %s", strerror(errno)); + error = 1; + goto done; + } + break; + + case TC_CODEC_PCM: { + int i, ch; + int16_t *outptr = audio_out; + dv_decode_full_audio(decoder, framebuf, audio_inptr); + for (i = 0; i < decoder->audio->samples_this_frame; i++) { + for (ch = 0; ch < decoder->audio->num_channels; ch++) { + *outptr++ = audio_in[ch][i]; + } + } + i = decoder->audio->samples_this_frame + * decoder->audio->num_channels * 2; + if (tc_pwrite(decode->fd_out, (void *)audio_out, i) != i) { + tc_log_error(__FILE__, "Write failed: %s", strerror(errno)); + error = 1; + goto done; + } + break; + } /* case TC_CODEC_PCM */ + + } /* switch (decode->format) */ + + /* Read in the next frame, if any, and parse the header */ + + retry: + toread = ispal ? DV_FRAME_SIZE_625_50 : DV_FRAME_SIZE_525_60; + nread = tc_pread(decode->fd_in, framebuf, toread); + if (nread != toread) { + if (verbose & TC_DEBUG) + tc_log_info(__FILE__, "End of stream reached."); + break; + } + if (dv_parse_header(decoder, framebuf) < 0) { + tc_log_warn(__FILE__, "Unable to parse frame header, skipping..."); + goto retry; + } + /* Sanity check: make sure it's the same video system */ + if (decoder->system != (ispal ? DV_SYSTEM_625_50 : DV_SYSTEM_525_60)) { + tc_log_error(__FILE__, "Video system (NTSC/PAL) changed" + " midstream! Aborting."); + error = 1; + break; + } + + } /* end decoding loop */ + + /**** All done ****/ + + done: + tc_buffree(video_conv_buf[0]); + tc_buffree(video[0]); + dv_decoder_free(decoder); + tcv_free(tcvhandle); + + import_exit(error ? 1 : 0); + +#else /* !HAVE_LIBDV */ + + tc_log_error(__FILE__, "No support for Digital Video configured - exit."); + import_exit(1); + +#endif +} + +/*************************************************************************/ + +/** + * probe_dv: Probe the input stream (on stdin) and set stream parameters + * as appropriate. + * + * Parameters: info: Pointer to stream parameter structure. + * Return value: None. + * Preconditions: None. + */ + +void probe_dv(info_t *info) +{ +#ifdef HAVE_LIBDV + dv_decoder_t *decoder; + uint8_t framebuf[DV_FRAME_SIZE_525_60]; // FIXME: too big for the stack? + int nread, ispal; +#endif + + if (!info) { + tc_log_error(__FILE__, "Invalid parameter to probe_dv()"); + return; + } + +#ifdef HAVE_LIBDV + + /* Read in an NTSC frame; for probing, this is enough for PAL as well */ + nread = tc_pread(info->fd_in, framebuf, sizeof(framebuf)); + if (nread < sizeof(framebuf)) { + tc_log_error(__FILE__, "Stream too short"); + info->error = 1; + return; + } + + /* Initialize libdv decoder */ + decoder = dv_decoder_new(1, 0, 0); + if (!decoder) { + tc_log_error(__FILE__, "Unable to initialize DV decoder"); + info->error = 1; + return; + } + + /* Parse frame header and check video system type */ + if (dv_parse_header(decoder, framebuf) < 0) { + tc_log_error(__FILE__, "No valid DV frame found"); + info->error = 1; + return; + } + if (decoder->system == DV_SYSTEM_525_60) { + ispal = 0; + } else if (decoder->system == DV_SYSTEM_625_50) { + ispal = 1; + } else { + tc_log_error(__FILE__, "Unknown or invalid DV frame type"); + info->error = 1; + return; + } + + /* Set stream parameters */ + + info->probe_info->magic = ispal ? TC_MAGIC_PAL : TC_MAGIC_NTSC; + + info->probe_info->width = decoder->width; + info->probe_info->height = decoder->height; + info->probe_info->fps = ispal ? PAL_FPS : NTSC_VIDEO; + info->probe_info->frc = ispal ? 3 : 4; + info->probe_info->asr = dv_format_wide(decoder) ? 3 : + dv_format_normal(decoder) ? 2 : 0; + + info->probe_info->track[0].samplerate = decoder->audio->frequency; + info->probe_info->track[0].chan = decoder->audio->num_channels; + info->probe_info->track[0].bits = 16; + info->probe_info->track[0].format = CODEC_PCM; + info->probe_info->track[0].bitrate = + (decoder->audio->frequency * decoder->audio->num_channels * 16) / 1000; + info->probe_info->num_tracks = 1; + + /* All done */ + dv_decoder_free(decoder); + +#endif /* HAVE_LIBDV */ + + /* Even without libdv, we know this much... */ + info->probe_info->codec = TC_CODEC_DV; + +} + +/*************************************************************************/ + +/* + * Local variables: + * c-file-style: "stroustrup" + * c-file-offsets: ((case-label . *) (statement-case-intro . *)) + * indent-tabs-mode: nil + * End: + * + * vim: expandtab shiftwidth=4: + */ |
