1 /*******************************************************************************
2  dv.c
3 
4  libquicktime - A library for reading and writing quicktime/avi/mp4 files.
5  http://libquicktime.sourceforge.net
6 
7  Copyright (C) 2002 Heroine Virtual Ltd.
8  Copyright (C) 2002-2011 Members of the libquicktime project.
9 
10  This library is free software; you can redistribute it and/or modify it under
11  the terms of the GNU Lesser General Public License as published by the Free
12  Software Foundation; either version 2.1 of the License, or (at your option)
13  any later version.
14 
15  This library is distributed in the hope that it will be useful, but WITHOUT
16  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18  details.
19 
20  You should have received a copy of the GNU Lesser General Public License along
21  with this library; if not, write to the Free Software Foundation, Inc., 51
22  Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 *******************************************************************************/
24 
25 #include "lqt_private.h"
26 #include <quicktime/colormodels.h>
27 #include <libdv/dv.h>
28 #include <pthread.h>
29 #include <string.h>
30 
31 #include "dv.h"
32 
33 // Buffer sizes
34 #define DV_NTSC_SIZE 120000
35 #define DV_PAL_SIZE 144000
36 
37 typedef struct
38 {
39 	dv_decoder_t *dv_decoder;
40 	dv_encoder_t *dv_encoder;
41 	unsigned char *data;
42 	unsigned char *temp_frame, **temp_rows;
43 
44 	/* Parameters */
45 	int decode_quality;
46 	int anamorphic16x9;
47 	int vlc_encode_passes;
48 	int clamp_luma, clamp_chroma;
49 
50 	int add_ntsc_setup;
51 
52 	int rem_ntsc_setup;
53 
54 	int parameters_changed;
55 } quicktime_dv_codec_t;
56 
57 static pthread_mutex_t libdv_init_mutex = PTHREAD_MUTEX_INITIALIZER;
58 
delete_codec(quicktime_codec_t * codec_base)59 static int delete_codec(quicktime_codec_t *codec_base)
60 {
61 	quicktime_dv_codec_t *codec = codec_base->priv;
62 
63 	if(codec->dv_decoder)
64 	{
65 		dv_decoder_free( codec->dv_decoder );
66 		codec->dv_decoder = NULL;
67 	}
68 
69 	if(codec->dv_encoder)
70 	{
71 		dv_encoder_free( codec->dv_encoder );
72 		codec->dv_encoder = NULL;
73 	}
74 
75 	if(codec->temp_frame) free(codec->temp_frame);
76 	if(codec->temp_rows) free(codec->temp_rows);
77 	free(codec->data);
78 	free(codec);
79 	return 0;
80 }
81 
check_sequentiality(unsigned char ** row_pointers,int bytes_per_row,int height)82 static int check_sequentiality( unsigned char **row_pointers,
83 								int bytes_per_row,
84 								int height )
85 {
86 	int i = 0;
87 
88 	for(; i < height-1; i++)
89 	{
90 		if( row_pointers[i+1] - row_pointers[i] != bytes_per_row )
91 		{
92 			return 0;
93 		}
94 	}
95 	return 1;
96 }
97 
encode(quicktime_t * file,unsigned char ** row_pointers,int track)98 static int encode(quicktime_t *file, unsigned char **row_pointers, int track)
99 {
100 	quicktime_video_map_t *vtrack = &file->vtracks[track];
101 	quicktime_dv_codec_t *codec = vtrack->codec->priv;
102 	quicktime_trak_t *trak = vtrack->track;
103 	int width = trak->tkhd.track_width;
104 	int height = trak->tkhd.track_height;
105 	int width_i = 720;
106 	int height_i = (height <= 480) ? 480 : 576;
107 	int i;
108 	unsigned char **input_rows;
109 	int isPAL = (height_i == 480) ? 0 : 1;
110 	int data_length = isPAL ? DV_PAL_SIZE : DV_NTSC_SIZE;
111 	int result = 0;
112 	dv_color_space_t encode_dv_colormodel = 0;
113 
114         if(!row_pointers)
115           {
116           vtrack->stream_cmodel = BC_YUV422;
117           vtrack->interlace_mode = LQT_INTERLACE_BOTTOM_FIRST;
118           return 0;
119           }
120 
121 
122 	if( codec->dv_encoder != NULL && codec->parameters_changed )
123 	{
124 		dv_encoder_free( codec->dv_encoder );
125 		codec->dv_encoder = NULL;
126 		codec->parameters_changed = 0;
127 	}
128 
129 	if( ! codec->dv_encoder )
130 	{
131 		pthread_mutex_lock( &libdv_init_mutex );
132 
133 
134 		codec->dv_encoder = dv_encoder_new( codec->rem_ntsc_setup,
135 											codec->clamp_luma,
136 											codec->clamp_chroma );
137 
138 		codec->parameters_changed = 0;
139 		pthread_mutex_unlock( &libdv_init_mutex );
140 	}
141 
142 	if(codec->dv_encoder)
143 	{
144 		int is_sequential =
145 			check_sequentiality( row_pointers,
146                                              width_i * cmodel_calculate_pixelsize(BC_YUV422),
147                                              height );
148 
149                 encode_dv_colormodel = e_dv_color_yuv;
150 		if( width == width_i &&
151                     height == height_i &&
152                     is_sequential )
153 		{
154 			input_rows = row_pointers;
155 		}
156 		else
157 		{
158 			if(!codec->temp_frame)
159 			{
160 				codec->temp_frame = malloc(720 * 576 * 2);
161 				codec->temp_rows = malloc(sizeof(unsigned char*) * 576);
162 				for(i = 0; i < 576; i++)
163 					codec->temp_rows[i] = codec->temp_frame + 720 * 2 * i;
164 			}
165 
166                         for(i = 0; i < MIN(height, height_i); i++)
167                           {
168                           memcpy(codec->temp_rows[i], row_pointers[i], MIN(width, width_i));
169                           }
170 
171 
172 			input_rows = codec->temp_rows;
173 		}
174 
175 		// Setup the encoder
176 		codec->dv_encoder->is16x9 = codec->anamorphic16x9;
177 		codec->dv_encoder->vlc_encode_passes = codec->vlc_encode_passes;
178 		codec->dv_encoder->static_qno = 0;
179 		codec->dv_encoder->force_dct = DV_DCT_AUTO;
180 		codec->dv_encoder->isPAL = isPAL;
181 
182 
183 		dv_encode_full_frame( codec->dv_encoder,
184                                       input_rows, encode_dv_colormodel, codec->data );
185 
186                 lqt_write_frame_header(file, track, vtrack->current_position,
187                                        -1, 0);
188 
189                 result = !quicktime_write_data(file, codec->data, data_length);
190 
191                 lqt_write_frame_footer(file, track);
192 	}
193 
194 	return result;
195 }
196 
197 // Logic: DV contains a mixture of 420 and 411 so can only
198 // output/input 444 or 422 and libdv can output/input RGB as well so
199 // we include that.
200 
201 // This function is used as both reads_colormodel and writes_colormodel
202 
set_parameter(quicktime_t * file,int track,const char * key,const void * value)203 static int set_parameter(quicktime_t *file,
204 		int track,
205 		const char *key,
206 		const void *value)
207 {
208 	quicktime_dv_codec_t *codec = file->vtracks[track].codec->priv;
209 
210 	if(!strcasecmp(key, "dv_decode_quality"))
211 	{
212 		codec->decode_quality = *(int*)value;
213 	}
214 	else if(!strcasecmp(key, "dv_anamorphic16x9"))
215 	{
216 		codec->anamorphic16x9 = *(int*)value;
217 	}
218 	else if(!strcasecmp(key, "dv_vlc_encode_passes"))
219 	{
220 		codec->vlc_encode_passes = *(int*)value;
221 	}
222 	else if(!strcasecmp(key, "dv_clamp_luma"))
223 	{
224 		codec->clamp_luma = *(int*)value;
225 	}
226 	else if(!strcasecmp(key, "dv_clamp_chroma"))
227 	{
228 		codec->clamp_chroma = *(int*)value;
229 	}
230 	else if(!strcasecmp(key, "dv_add_ntsc_setup"))
231 	{
232 		codec->add_ntsc_setup = *(int*)value;
233 	}
234 	else if(!strcasecmp(key, "dv_rem_ntsc_setup"))
235 	{
236 		codec->rem_ntsc_setup = *(int*)value;
237 	}
238 	else
239 	{
240 		return 0;
241 	}
242 
243 	codec->parameters_changed = 1;
244 	return 0;
245 }
246 
quicktime_init_codec_dv(quicktime_codec_t * codec_base,quicktime_audio_map_t * atrack,quicktime_video_map_t * vtrack)247 void quicktime_init_codec_dv(quicktime_codec_t * codec_base,
248                              quicktime_audio_map_t *atrack,
249                              quicktime_video_map_t *vtrack)
250 {
251 	quicktime_dv_codec_t *codec;
252 
253 /* Init public items */
254         codec = calloc(1, sizeof(*codec));
255         codec_base->priv = codec;
256 
257         codec_base->delete_codec = delete_codec;
258 	codec_base->encode_video = encode;
259 	codec_base->set_parameter = set_parameter;
260         /* Init private items */
261 
262 	codec->decode_quality = DV_QUALITY_BEST;
263 	codec->vlc_encode_passes = 3;
264 
265 	codec->data = calloc(1, 144000);
266 }
267