1 /*
2  *  export_dvraw.c
3  *
4  *  Copyright (C) Thomas Oestreich - June 2001
5  *
6  *  This file is part of transcode, a video stream processing tool
7  *
8  *  transcode is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2, or (at your option)
11  *  any later version.
12  *
13  *  transcode is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with GNU Make; see the file COPYING.  If not, write to
20  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */
23 
24 #define MOD_NAME    "export_dvraw.so"
25 #define MOD_VERSION "v0.4.1 (2007-08-17)"
26 #define MOD_CODEC   "(video) Digital Video | (audio) PCM"
27 
28 #include "transcode.h"
29 #include "libtc/libtc.h"
30 #include "libtc/optstr.h"
31 #include "libtcvideo/tcvideo.h"
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <libdv/dv.h>
36 
37 static int verbose_flag=TC_QUIET;
38 static int capability_flag=TC_CAP_PCM|TC_CAP_RGB|TC_CAP_YUV|TC_CAP_VID|TC_CAP_YUV422;
39 
40 #define MOD_PRE dvraw
41 #include "export_def.h"
42 
43 static int fd = -1;
44 
45 /* only 2 channesl supported */
46 #define MAX_CHANNELS 2
47 static int16_t *audio_bufs[MAX_CHANNELS] = { NULL, NULL };
48 
49 static uint8_t *target = NULL, *vbuf = NULL;
50 
51 static dv_encoder_t *encoder = NULL;
52 static uint8_t *pixels[3] = { NULL, NULL, NULL }, *tmp_buf = NULL;
53 static TCVHandle tcvhandle;
54 
55 static int frame_size = 0, format = 0;
56 static int pass_through = 0;
57 
58 static int chans = 0, rate = 0;
59 static int dv_yuy2_mode = 0;
60 static int dv_uyvy_mode = 0;
61 static int is_PAL = 0;
62 
63 /* ------------------------------------------------------------
64  *
65  * init codec
66  *
67  * ------------------------------------------------------------*/
68 
69 MOD_init
70 {
71     int i;
72 
73     if (param->flag == TC_VIDEO) {
74         is_PAL = (vob->ex_v_height == PAL_H);
75         target = tc_bufalloc(TC_FRAME_DV_PAL);
76         vbuf   = tc_bufalloc(PAL_W * PAL_H * 3);
77 
78         tcvhandle = tcv_init();
79 
80         if (vob->dv_yuy2_mode == 1) {
81             tmp_buf = tc_bufalloc(PAL_W * PAL_H * 2); //max frame
82             dv_yuy2_mode = 1;
83         }
84 
85         if (vob->im_v_codec == CODEC_YUV422) {
86             tmp_buf = tc_bufalloc(PAL_W * PAL_H * 2); //max frame
87             dv_uyvy_mode = 1;
88         }
89 
90         encoder = dv_encoder_new(FALSE, FALSE, FALSE);
91         return TC_OK;
92     }
93 
94     if (param->flag == TC_AUDIO) {
95         // tmp audio buffer
96         for ( i = 0; i < MAX_CHANNELS; i++) {
97             audio_bufs[i] = tc_malloc(DV_AUDIO_MAX_SAMPLES * sizeof(int16_t));
98             if (!(audio_bufs[i])) {
99                 tc_log_error(MOD_NAME, "out of memory");
100                 return TC_ERROR;
101             }
102         }
103         return TC_OK;
104     }
105 
106     return(TC_ERROR);
107 }
108 
109 /* ------------------------------------------------------------
110  *
111  * open outputfile
112  *
113  * ------------------------------------------------------------*/
114 
115 MOD_open
116 {
117     int bytealignment = 0, bytespersecond = 0, bytesperframe = 0;
118 
119     if (param->flag == TC_VIDEO) {
120         fd = open(vob->video_out_file, O_RDWR|O_CREAT|O_TRUNC,
121 		          S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
122         if (fd < 0) {
123             tc_log_perror(MOD_NAME, "open file");
124             return TC_ERROR;
125         }
126 
127         switch (vob->im_v_codec) {
128           case CODEC_RGB:
129             format = 0;
130             if (verbose >= TC_DEBUG)
131                 tc_log_info(MOD_NAME, "raw format is RGB");
132             break;
133           case CODEC_YUV:
134             format = 1;
135             if (verbose >= TC_DEBUG)
136                 tc_log_info(MOD_NAME, "raw format is YUV420P");
137             break;
138           case CODEC_YUV422:
139             format = 2;
140             if (verbose >= TC_DEBUG)
141                 tc_log_info(MOD_NAME, "raw format is YUV422");
142             break;
143           case CODEC_RAW:
144           case CODEC_RAW_YUV:
145             format = 1;
146             pass_through = 1;
147             break;
148           default:
149             tc_log_warn(MOD_NAME, "codec not supported");
150             return TC_ERROR;
151         }
152 
153         frame_size = (is_PAL) ?TC_FRAME_DV_PAL :TC_FRAME_DV_NTSC;
154 
155         if (verbose >= TC_DEBUG)
156             tc_log_info(MOD_NAME, "encoding to %s DV",
157                         (is_PAL) ?"PAL" :"NTSC");
158 
159         // Store aspect ratio - ex_asr uses the value 3 for 16x9 (XXX: tricky)
160         encoder->is16x9 = (((vob->ex_asr < 0) ?vob->im_asr :vob->ex_asr) == 3);
161         encoder->isPAL = is_PAL;
162         encoder->vlc_encode_passes = 3;
163         encoder->static_qno = 0;
164         if (vob->ex_v_string != NULL)
165             if (optstr_get(vob->ex_v_string, "qno", "%d", &encoder->static_qno) == 1)
166                 tc_log_info(MOD_NAME, "using quantisation: %d", encoder->static_qno);
167         encoder->force_dct = DV_DCT_AUTO;
168 
169         return TC_OK;
170     }
171 
172     if (param->flag == TC_AUDIO) {
173         if (!encoder) {
174             tc_log_warn(MOD_NAME, "-y XXX,dvraw is not possible without the video");
175             tc_log_warn(MOD_NAME, "export module also being dvraw");
176             return TC_ERROR;
177         }
178         chans = vob->dm_chan;
179         //re-sampling only with -J resample possible
180         rate = vob->a_rate;
181 
182         bytealignment = (chans == 2) ?4 :2;
183         bytespersecond = rate * bytealignment;
184         bytesperframe = bytespersecond/(is_PAL ?25 :30);
185 
186         if(verbose >= TC_DEBUG)
187             tc_log_info(MOD_NAME, "audio: CH=%d, f=%d, balign=%d, bps=%d, bpf=%d",
188 		                chans, rate, bytealignment, bytespersecond, bytesperframe);
189 
190         return TC_OK;
191     }
192     return TC_ERROR;
193 }
194 
195 /* ------------------------------------------------------------
196  *
197  * encode and export
198  *
199  * ------------------------------------------------------------*/
200 
201 MOD_encode
202 {
203     int i;
204 
205     if (param->flag == TC_VIDEO) {
206         if (pass_through) {
207             ac_memcpy(target, param->buffer, frame_size);
208         } else {
209             ac_memcpy(vbuf, param->buffer, param->size);
210         }
211 
212         return TC_OK;
213     }
214 
215     if (param->flag == TC_AUDIO) {
216         int16_t *abufs[2] = { audio_bufs[0], audio_bufs[1] }; /* working copies */
217         time_t now = time(NULL);
218         int achans = chans;
219 
220         if (!pass_through) {
221             if (dv_uyvy_mode) {
222                 tcv_convert(tcvhandle,
223                 		    vbuf, tmp_buf, PAL_W, (encoder->isPAL) ? PAL_H : NTSC_H,
224 		                    (format==2) ? IMG_YUV422P : IMG_YUV420P, IMG_UYVY);
225                 pixels[0] = pixels[1] = pixels[2] = tmp_buf;
226             } else if (dv_yuy2_mode) {
227             	tcv_convert(tcvhandle,
228 		                    vbuf, tmp_buf, PAL_W, (encoder->isPAL) ? PAL_H : NTSC_H,
229                 		    (format==2) ? IMG_YUV422P : IMG_YUV420P, IMG_YUY2);
230             	pixels[0] = pixels[1] = pixels[2] = tmp_buf;
231             } else {
232                 pixels[0] = vbuf;
233                 if (encoder->isPAL) {
234                     pixels[1] = pixels[0] + PAL_W*PAL_H;
235                     pixels[2] = pixels[1] + (PAL_W/2)*(format==2?PAL_H:PAL_H/2);
236                 } else {
237                     pixels[1] = pixels[0] + NTSC_W*NTSC_H;
238                     pixels[2] = pixels[1] + (NTSC_W/2)*(format==2?NTSC_H:NTSC_H/2);
239                 }
240             }
241 
242             dv_encode_full_frame(encoder, pixels, (format)?e_dv_color_yuv:e_dv_color_rgb, target);
243         } //no pass-through
244         /*
245          * samples * channels * bits = size;
246          * so
247          * samples = size / (channels * bits)
248          */
249         encoder->samples_this_frame = param->size / (chans * sizeof(int16_t));
250         dv_encode_metadata(target, encoder->isPAL, encoder->is16x9, &now, 0);
251         dv_encode_timecode(target, encoder->isPAL, 0);
252 
253 #ifdef WORDS_BIGENDIAN
254         for (i=0; i<param->size; i+=2) {
255 	        uint8_t tmp = param->buffer[i];
256             param->buffer[i] = param->buffer[i+1];
257             param->buffer[i+1] = tmp;
258         }
259 #endif
260 
261         // Although dv_encode_full_audio supports 4 channels, the internal
262         // PCM data (param->buffer) is only carrying 2 channels so only deal
263         // with 1 or 2 channel audio.
264         // Work around apparent bug in dv_encode_full_audio when chans == 1
265         // by putting silence in 2nd channel and calling with chans = 2
266         if (chans == 1) {
267             abufs[0] = (int16_t *)param->buffer; /* avoid ac_memcpy */
268             memset(abufs[1], 0, DV_AUDIO_MAX_SAMPLES * 2);
269             achans = 2;
270         } else {
271             // assume 2 channel, demultiplex for libdv API
272             for(i = 0; i < param->size/4; i++) { // XXX magic number
273                 abufs[0][i] = ((int16_t *)param->buffer)[i * 2    ];
274                 abufs[1][i] = ((int16_t *)param->buffer)[i * 2 + 1];
275             }
276         }
277         dv_encode_full_audio(encoder, abufs, achans, rate, target);
278 
279         if (tc_pwrite(fd, target, frame_size) != frame_size) {
280             tc_log_perror(MOD_NAME, "write frame");
281             return TC_ERROR;
282         }
283 
284         return TC_OK;
285     }
286 
287     return TC_ERROR;
288 }
289 
290 /* ------------------------------------------------------------
291  *
292  * stop encoder
293  *
294  * ------------------------------------------------------------*/
295 
296 MOD_stop
297 {
298     int i;
299 
300     if (param->flag == TC_VIDEO) {
301         dv_encoder_free(encoder);
302         tcv_free(tcvhandle);
303         return TC_OK;
304     }
305 
306     if (param->flag == TC_AUDIO) {
307         for(i = 0; i < MAX_CHANNELS; i++)
308             tc_free(audio_bufs[i]);
309         return TC_OK;
310     }
311 
312     return TC_ERROR;
313 }
314 
315 /* ------------------------------------------------------------
316  *
317  * close outputfiles
318  *
319  * ------------------------------------------------------------*/
320 
321 MOD_close
322 {
323     if(param->flag == TC_VIDEO) {
324         close(fd);
325         return TC_OK;
326     }
327 
328     if (param->flag == TC_AUDIO)
329         return TC_OK;
330 
331     return TC_ERROR;
332 }
333 
334 
335