2
* $Id: y4mtoqt.c,v 1.13 2007/05/10 03:07:36 sms00 Exp $
4
* Utility to place 4:2:2 or 4:4:4 YUV4MPEG2 data in a Quicktime wrapper. An
5
* audio track can also be added by specifying '-a wavfile' (16bit pcm only).
6
* The interlacing, frame rate, frame size and field order are extracted
7
* from the YUV4MPEG2 header. This is the reverse of 'qttoy4m' which dumps
8
* planar data from a Quicktime file (and optionally a specified audio track
11
* Usage: y4mtoqt [-X] [-a wavfile] -o outputfile < 422yuv4mpeg2stream
13
* -X enables 10bit packed output, 2vuy becomes v210 and v308 becomes v410.
19
#include <quicktime.h>
21
#include <colormodels.h>
25
static void usage(void);
26
static void do_audio(quicktime_t *, uint8_t *, int, int, int);
29
main(int argc, char **argv)
31
char *outfilename = NULL;
32
char *audiofilename = NULL;
36
int fdin, y_len, u_len, v_len, nfields = 1, dominance = 0, afd = -1;
37
int imodel = 0, allow_wrong_yv12 = 0;
38
int err, i, c, frames, channels = 0, y4mchroma, tenbit = 0;
39
char *qtchroma = NULL;
41
quicktime_pasp_t pasp;
43
quicktime_colr_t colr;
45
quicktime_clap_t clap;
46
y4m_stream_info_t istream;
47
y4m_frame_info_t iframe;
48
y4m_ratio_t rate, sar;
49
struct wave_header wavhdr;
50
y4m_accept_extensions(1);
55
while ((c = getopt(argc, argv, "ko:a:X")) != -1)
69
audiofilename = optarg;
86
afd = open(audiofilename, O_RDONLY);
88
mjpeg_error_exit1("Can not open audio file '%s'",
90
if (AVI_read_wave_header(afd, &wavhdr) == -1)
91
mjpeg_error_exit1("'%s' is not a valid WAV file",
93
channels = wavhdr.common.wChannels;
96
y4m_init_stream_info(&istream);
97
y4m_init_frame_info(&iframe);
99
err = y4m_read_stream_header(fdin, &istream);
101
mjpeg_error_exit1("Input header error: %s", y4m_strerr(err));
103
if (y4m_si_get_plane_count(&istream) != 3)
104
mjpeg_error_exit1("Only 3 plane formats supported");
106
rate = y4m_si_get_framerate(&istream);
108
switch (y4mchroma = y4m_si_get_chroma(&istream))
110
case Y4M_CHROMA_420MPEG2:
111
case Y4M_CHROMA_420JPEG:
113
* Quicktime doesn't appear to have a way to reliably
114
* tell the two non-PALDV variants apart so treat them
115
* both the same (like most other software in the world)
117
qtchroma = QUICKTIME_YUV420; /* yv12 */
122
qtchroma = QUICKTIME_V210;
125
qtchroma = QUICKTIME_2VUY;
126
imodel = BC_YUV422P; /* Input is planar */
131
qtchroma = QUICKTIME_V410;
134
qtchroma = QUICKTIME_V308;
135
imodel = BC_YUV444P; /* Need this?? */
139
mjpeg_error_exit1("unsupported chroma sampling: %s",
140
y4m_chroma_keyword(y4mchroma));
144
y_len = y4m_si_get_plane_length(&istream, 0);
145
u_len = y4m_si_get_plane_length(&istream, 1);
146
v_len = y4m_si_get_plane_length(&istream, 2);
147
yuv[0] = malloc(y_len);
148
yuv[1] = malloc(u_len);
149
yuv[2] = malloc(v_len);
152
yuv10[0] = malloc(y_len * sizeof(uint16_t));
153
yuv10[1] = malloc(u_len * sizeof(uint16_t));
154
yuv10[2] = malloc(v_len * sizeof(uint16_t));
157
qtf = quicktime_open(outfilename, 0, 1);
159
mjpeg_error_exit1("quicktime_open(%s,0,1) failed", outfilename);
161
quicktime_set_video(qtf, 1,
162
y4m_si_get_width(&istream),
163
y4m_si_get_height(&istream),
164
(double) rate.n / rate.d,
168
lqt_set_cmodel(qtf, 0, imodel);
171
quicktime_set_audio(qtf, channels,
172
wavhdr.common.dwSamplesPerSec,
173
wavhdr.common.wBitsPerSample,
176
* http://developer.apple.com/quicktime/icefloe/dispatch019.html#fiel
178
* "dominance" is what Apple calls "detail". From what I can figure out
179
* the "bottom field" first corresponds to a "detail" setting of 14 and
180
* "top field first" is a "detail" setting of 9.
182
switch (y4m_si_get_interlace(&istream))
184
case Y4M_ILACE_BOTTOM_FIRST:
185
dominance = 14; /* Weird but that's what Apple says */
188
case Y4M_ILACE_TOP_FIRST:
197
case Y4M_ILACE_MIXED:
198
mjpeg_error_exit1("Mixed field dominance unsupported");
201
mjpeg_error_exit1("UNKNOWN field dominance %d",
202
y4m_si_get_interlace(&istream));
206
if (lqt_set_fiel(qtf, 0, nfields, dominance) == 0)
207
mjpeg_error_exit1("lqt_set_fiel(qtf, 0, %d, %d) failed",
210
sar = y4m_si_get_sampleaspect(&istream);
211
if (Y4M_RATIO_EQL(sar, y4m_sar_UNKNOWN))
212
pasp.hSpacing = pasp.vSpacing = 1;
215
pasp.hSpacing = sar.n;
216
pasp.vSpacing = sar.d;
218
if (lqt_set_pasp(qtf, 0, &pasp) == 0)
219
mjpeg_error_exit1("lqt_set_pasp(qtf, 0, %d/%d) failed",
220
pasp.hSpacing, pasp.vSpacing);
223
* Don't do this for now - it can crash FinalCutPro if the colr atom is
224
* not exactly correct.
227
colr.colorParamType = 'nclc';
229
colr.transferFunction = 2;
231
if (lqt_set_colr(qtf, 0, &colr) == 0)
232
mjpeg_error_exit1("lqt_set_colr(qtf, 0,...) failed");
234
clap.cleanApertureWidthN = y4m_si_get_width (&istream);;
235
clap.cleanApertureWidthD = 1;
236
clap.cleanApertureHeightN = y4m_si_get_height (&istream);
237
clap.cleanApertureHeightD = 1;
242
if (lqt_set_clap(qtf, 0, &clap) == 0)
243
mjpeg_error_exit1("lqt_set_clap(qtf, 0, ...) failed");
245
for (;y4m_read_frame(fdin,&istream,&iframe,yuv) == Y4M_OK; frames++)
251
for (i = 0; i < y_len; i++)
255
for (i = 0; i < u_len; i++)
259
for (i = 0; i < v_len; i++)
263
* What libquicktime calls 'yv12' (QUICKTIME_YUV420) is actually 'iyuv'
264
* (also known as 'i420'). In order to make the data match the fourcc/label
265
* the U and V planes need to be swapped. After all, if the file is labeled
266
* 'yv12' then the data should be in 'yv12' order!
268
* Breakage, for compatiblity with quicktime4linux, can be forced by using
269
* '-k'. This allows storing 'iyuv' ('i420') data inside a file that is
270
* labeled as 'yv12' :(
272
* It should be noted that very very little outside of V4L knows anything
273
* about uncompressed 4:2:0 - the 4:2:0 color space is used but only with
274
* compressed formats it seems.
277
if (strcmp(qtchroma, QUICKTIME_YUV420) == 0)
279
if (allow_wrong_yv12 == 0)
287
err = quicktime_encode_video(qtf, tenbit ? (uint8_t **)yuv10: yuv, 0);
289
mjpeg_error_exit1("quicktime_encode_video failed.");
297
mjpeg_info("channels %d SamplesPerSec %d bits_sample %d",
298
channels, wavhdr.common.dwSamplesPerSec,
299
wavhdr.common.wBitsPerSample);
301
bps = (wavhdr.common.wBitsPerSample + 7)/8;
302
bufsize = 8192 * channels * bps;
303
buffer = malloc(bufsize);
304
while ((n = AVI_read_wave_pcm_data(afd, buffer, bufsize)) > 0)
305
do_audio(qtf, buffer, channels, bps, n / (channels * bps));
307
quicktime_close(qtf);
312
do_audio(quicktime_t *qtf, uint8_t *buff, int channels, int bps, int samps)
316
int16_t *qt_audio = (int16_t *)buff, **qt_audion;
318
qt_audion = malloc(channels * sizeof (int16_t **));
319
for (i = 0; i < channels; i++)
320
qt_audion[i] = (int16_t *)malloc(samps * bps);
322
/* Deinterleave the audio into separate channel buffers */
323
for (i = 0; i < samps; i++)
325
for (j = 0; j < channels; j++)
326
qt_audion[j][i] = qt_audio[(channels*i) + j];
328
res = lqt_encode_audio_track(qtf, qt_audion, NULL, samps, 0);
329
for (j = 0; j < channels; j++)
337
mjpeg_warn("usage: [-k] [-X] [-a inputwavfile] -o outfile");
338
mjpeg_warn(" -X = use v210 (default 2vuy) for 4:2:2, v410 (default v308) for 4:4:4");
339
mjpeg_warn(" -k = do not perform lqt workaround (U and V plane swap) (default 0 - i.e. DO the workaround)");