1 /*******************************************************************************
2  lqt_transcode.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 /*
26  *  Simple quicktime->quicktime transcoder
27  *  Used mainly for testing the encoder capabilities
28  *  of libquicktime
29  */
30 
31 /* Limitation: Handles only 1 audio- and one video stream per file */
32 
33 #include <config.h> // ONLY for the PACKAGE macro. Usually, applications never need
34                     // to include config.h
35 
36 #define _(str) dgettext(PACKAGE, str)
37 #include <libintl.h>
38 #include <locale.h>
39 
40 #include <quicktime/lqt.h>
41 #include <quicktime/colormodels.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45 
46 
47 
48 /* Supported colormodels */
49 
50 int colormodels[] =
51   {
52     BC_RGB565,
53     BC_BGR565,
54     BC_BGR888,
55     BC_BGR8888,
56     BC_RGB888,
57     BC_RGBA8888,
58     BC_RGB161616,
59     BC_RGBA16161616,
60     BC_YUVA8888,
61     BC_YUV422,
62     BC_YUV420P,
63     BC_YUV422P,
64     BC_YUV444P,
65     BC_YUV411P,
66     LQT_COLORMODEL_NONE
67   };
68 
69 static struct
70   {
71   char * name;
72   lqt_file_type_t type;
73   char * extension;
74   char * description;
75   char * default_audio_codec;
76   char * default_video_codec;
77   }
78 formats[] =
79   {
80     { "qt",       LQT_FILE_QT,        "mov", "Quicktime (QT7 compatible)",   "faac", "ffmpeg_mpg4" },
81     { "qtold",    LQT_FILE_QT_OLD,    "mov", "Quicktime (qt4l and old lqt)", "twos", "mjpa" },
82     { "avi",      LQT_FILE_AVI,       "avi", "AVI (< 2G)",                   "lame", "ffmpeg_msmpeg4v3" },
83     { "avi_odml", LQT_FILE_AVI_ODML, "avi", "AVI (> 2G)",                   "lame", "ffmpeg_msmpeg4v3" },
84     { "mp4",      LQT_FILE_MP4,       "mp4", "ISO MPEG-4",                    "faac", "ffmpeg_mpg4" },
85     { "m4a",      LQT_FILE_M4A,       "m4a", "m4a (iTunes compatible)",       "faac", "ffmpeg_mpg4"  },
86   };
87 
list_formats()88 static void list_formats()
89   {
90   int i;
91   printf(_("Supported formats\n"));
92   for(i = 0; i < sizeof(formats)/sizeof(formats[0]); i++)
93     {
94     printf(_("%8s: %s (default codecs: %s/%s)\n"), formats[i].name, formats[i].description,
95            formats[i].default_audio_codec, formats[i].default_video_codec);
96     }
97   }
98 
99 typedef struct
100   {
101   quicktime_t * in_file;
102   quicktime_t * out_file;
103 
104   int64_t num_video_frames;
105   int64_t video_duration;
106 
107   int64_t num_audio_samples;
108 
109   int64_t audio_samples_written;
110   int64_t video_frames_written;
111 
112   unsigned char ** video_buffer;
113 
114   float   ** audio_buffer_f;
115   int16_t ** audio_buffer_i;
116   int samples_per_frame;
117 
118   int do_audio;
119   int do_video;
120 
121   /* Format information */
122 
123   int colormodel;
124   int width;
125   int height;
126   int rowspan;
127   int rowspan_uv;
128 
129   int frame_duration;
130   int timescale;
131   int samplerate;
132   int num_channels;
133   int audio_bits;
134 
135   /* Progress (0..1) */
136 
137   float progress;
138   } transcode_handle;
139 
print_usage()140 static void print_usage()
141   {
142   printf(_("Usage: lqt_transcode [[-avi]|[-f <format>]] [-floataudio] [-qtvr <obj|pano>] [-qtvr_columns <columns>] [-qtvr_rows <rows>] [-ac <audio_codec>] [-vc <video_codec>] <in_file> <out_file>\n"));
143   printf(_("       Transcode <in_file> to <out_file> using <audio_codec> and <video_codec>\n\n"));
144   printf(_("       lqt_transcode -lv\n"));
145   printf(_("       List video encoders\n\n"));
146   printf(_("       lqt_transcode -la\n"));
147   printf(_("       List audio encoders\n"));
148   printf(_("       lqt_transcode -lf\n"));
149   printf(_("       List output formats\n"));
150   }
151 
list_info(lqt_codec_info_t ** info)152 static void list_info(lqt_codec_info_t ** info)
153   {
154   int i, j;
155   int max_len;
156   int len;
157   max_len = 0;
158   i = 0;
159   while(info[i])
160     {
161     len = strlen(info[i]->name);
162     if(len > max_len)
163       max_len = len;
164     i++;
165     }
166   max_len++;
167   i = 0;
168 
169   while(info[i])
170     {
171     len = strlen(info[i]->name);
172 
173     printf("%s:", info[i]->name);
174     len = strlen(info[i]->name);
175 
176     for(j = 0; j < max_len - len; j++)
177       printf(" ");
178 
179     printf("%s\n", info[i]->long_name);
180 
181     i++;
182     }
183 
184   }
185 
list_video_codecs()186 static void list_video_codecs()
187   {
188   lqt_codec_info_t ** info;
189   info = lqt_query_registry(0, 1, 1, 0);
190   list_info(info);
191   lqt_destroy_codec_info(info);
192   }
193 
list_audio_codecs()194 static void list_audio_codecs()
195   {
196   lqt_codec_info_t ** info;
197   info = lqt_query_registry(1, 0, 1, 0);
198   list_info(info);
199   lqt_destroy_codec_info(info);
200   }
201 
transcode_init(transcode_handle * h,char * in_file,char * out_file,char * video_codec,char * audio_codec,int floataudio,lqt_file_type_t type,char * qtvr,int qtvr_rows,int qtvr_columns)202 static int transcode_init(transcode_handle * h,
203                           char * in_file,
204                           char * out_file,
205                           char * video_codec,
206                           char * audio_codec,
207                           int floataudio,
208                           lqt_file_type_t type,
209                           char * qtvr,
210                           int qtvr_rows,
211                           int qtvr_columns)
212   {
213   lqt_codec_info_t ** codec_info;
214   int i;
215   int in_cmodel, out_cmodel;
216   char * extension;
217 
218   h->in_file = quicktime_open(in_file, 1, 0);
219   if(!h->in_file)
220     {
221     fprintf(stderr, _("Cannot open input file %s\n"), in_file);
222     return 0;
223     }
224 
225   /* Get the output format */
226 
227   if(type == LQT_FILE_NONE)
228     {
229     extension = strrchr(out_file, '.');
230     if(!extension)
231       {
232       fprintf(stderr, _("Need a file extension when autoguessing output format\n"));
233       return 0;
234       }
235     extension++;
236 
237     for(i = 0; i < sizeof(formats)/sizeof(formats[0]); i++)
238       {
239       if(!strcasecmp(extension, formats[i].extension))
240         {
241         type = formats[i].type;
242         break;
243         }
244       }
245     }
246   if(type == LQT_FILE_NONE)
247     {
248     fprintf(stderr, _("Cannot detect output format. Specify a valid extension or use -f <format>\n"));
249     return 0;
250     }
251 
252   if(!audio_codec || !video_codec)
253     {
254     for(i = 0; i < sizeof(formats)/sizeof(formats[0]); i++)
255       {
256       if(type == formats[i].type)
257         {
258         if(!audio_codec) audio_codec = formats[i].default_audio_codec;
259         if(!video_codec) video_codec = formats[i].default_video_codec;
260         }
261       }
262 
263     }
264 
265   h->out_file = lqt_open_write(out_file, type);
266   if(!h->out_file)
267     {
268     fprintf(stderr, _("Cannot open output file %s\n"), out_file);
269     return 0;
270     }
271 
272   /* Check for video */
273 
274   if(quicktime_video_tracks(h->in_file) &&
275      quicktime_supported_video(h->in_file, 0))
276     h->do_video = 1;
277 
278   if(h->do_video)
279     {
280     h->width     = quicktime_video_width(h->in_file, 0);
281     h->height    = quicktime_video_height(h->in_file, 0);
282 
283     h->timescale      = lqt_video_time_scale(h->in_file, 0);
284     h->frame_duration = lqt_frame_duration(h->in_file, 0, NULL);
285 
286     /* Codec info for encoding */
287 
288     codec_info = lqt_find_video_codec_by_name(video_codec);
289     if(!codec_info)
290       {
291       fprintf(stderr, _("Unsupported video cocec %s, try -lv\n"), video_codec);
292       return 0;
293       }
294 
295     /* Set up the output track */
296 
297     lqt_set_video(h->out_file, 1, h->width, h->height, h->frame_duration, h->timescale, codec_info[0]);
298 
299     /* Get colormodel */
300     in_cmodel = lqt_get_cmodel(h->in_file, 0);
301     out_cmodel = lqt_get_cmodel(h->out_file, 0);
302 
303     if(quicktime_reads_cmodel(h->in_file, out_cmodel, 0))
304       {
305       h->colormodel = out_cmodel;
306       }
307     else if(quicktime_writes_cmodel(h->out_file, in_cmodel, 0))
308       {
309       h->colormodel = in_cmodel;
310       }
311     else
312       {
313       h->colormodel = BC_RGB888;
314       }
315 
316     h->video_buffer = lqt_rows_alloc(h->width, h->height, h->colormodel, &(h->rowspan), &(h->rowspan_uv));
317 
318     quicktime_set_cmodel(h->in_file,  h->colormodel);
319     quicktime_set_cmodel(h->out_file, h->colormodel);
320 
321     lqt_destroy_codec_info(codec_info);
322 
323     h->num_video_frames = quicktime_video_length(h->in_file, 0);
324     h->video_duration = lqt_video_duration(h->in_file, 0);
325     }
326   /* Check for audio */
327 
328   if(quicktime_audio_tracks(h->in_file) &&
329      quicktime_supported_audio(h->in_file, 0))
330     h->do_audio = 1;
331 
332   if(h->do_audio)
333     {
334     h->audio_bits = quicktime_audio_bits(h->in_file, 0);
335     h->samplerate = quicktime_sample_rate(h->in_file, 0);
336     h->num_channels = lqt_total_channels(h->in_file);
337 
338     /* Codec info for encoding */
339 
340     codec_info = lqt_find_audio_codec_by_name(audio_codec);
341     if(!codec_info)
342       {
343       fprintf(stderr, _("Unsupported audio codec %s, try -la\n"), audio_codec);
344       return 0;
345       }
346 
347     /* Set up audio track */
348 
349     lqt_set_audio(h->out_file, h->num_channels,
350                   h->samplerate, h->audio_bits,
351                   codec_info[0]);
352     lqt_destroy_codec_info(codec_info);
353 
354     /* Decide about audio frame size */
355 
356     /* Ok, we must take care about the audio frame size.
357        The sample count, we pass to encode_audio() directly affects interleaving.
358        Many small audio chunks make decoding inefficient, few large chunks make seeking
359        slower because many samples inside a chunk have to be skipped.
360 
361        Ok, then lets just take half a second and see how it works :-)
362 
363        On a 25 fps system this means, that one audio chunks comes after an average of
364        12.5 video frames. This is roughly what we see in files created with other
365        Software
366     */
367 
368     h->samples_per_frame = h->samplerate / 2;
369     /* Avoid too odd numbers */
370     h->samples_per_frame = 16 * ((h->samples_per_frame + 15) / 16);
371 
372     /* Allocate output buffer */
373 
374     if(floataudio)
375       {
376       h->audio_buffer_f = malloc(h->num_channels * sizeof(float*));
377       h->audio_buffer_f[0] = malloc(h->num_channels * h->samples_per_frame * sizeof(float));
378       for(i = 1; i < h->num_channels; i++)
379         h->audio_buffer_f[i] = &(h->audio_buffer_f[0][i*h->samples_per_frame]);
380       }
381     else
382       {
383       h->audio_buffer_i = malloc(h->num_channels * sizeof(int16_t*));
384       h->audio_buffer_i[0] = malloc(h->num_channels * h->samples_per_frame * sizeof(int16_t));
385       for(i = 1; i < h->num_channels; i++)
386         h->audio_buffer_i[i] = &(h->audio_buffer_i[0][i*h->samples_per_frame]);
387       }
388     h->num_audio_samples = quicktime_audio_length(h->in_file, 0);
389     }
390 
391     if (qtvr) {
392 	if(strncmp(qtvr,"obj", 3) == 0) {
393 	    lqt_qtvr_set_type(h->out_file, QTVR_OBJ, h->width , h->height, h->frame_duration, h->timescale, 0);
394 	}
395 
396 	if(strncmp(qtvr,"pano", 4) == 0) {
397 	    lqt_qtvr_set_type(h->out_file, QTVR_PAN, h->width/2, h->width, h->frame_duration, h->timescale, 0);
398 	}
399 
400 	if(qtvr_columns && qtvr_rows) {
401 	    lqt_qtvr_set_rows(h->out_file, qtvr_rows);
402 	    lqt_qtvr_set_columns(h->out_file, qtvr_columns);
403 	}
404     }
405 
406   return 1;
407   }
408 
transcode_iteration(transcode_handle * h)409 static int transcode_iteration(transcode_handle * h)
410   {
411   double audio_time;
412   double video_time;
413   int num_samples;
414   int do_audio = 0;
415   float progress;
416   int64_t frame_time;
417 
418   if(h->do_audio && h->do_video)
419     {
420     audio_time = (float)(h->audio_samples_written)/(float)(h->samplerate);
421     video_time = (float)(h->video_frames_written * h->frame_duration)/h->timescale;
422 
423     if(audio_time < video_time)
424       do_audio = 1;
425     }
426   else if(h->do_audio)
427     {
428     do_audio = 1;
429     }
430 
431   /* Audio Iteration */
432 
433   if(do_audio)
434     {
435     //    lqt_decode_audio(h->in_file, h->audio_buffer_i, h->audio_buffer_f, h->samples_per_frame);
436     lqt_decode_audio_track(h->in_file, h->audio_buffer_i, h->audio_buffer_f, h->samples_per_frame, 0);
437     num_samples = lqt_last_audio_position(h->in_file, 0) - h->audio_samples_written;
438     //    fprintf(stderr, "Num samples: %d\n",num_samples);
439     quicktime_encode_audio(h->out_file, h->audio_buffer_i, h->audio_buffer_f, num_samples);
440     h->audio_samples_written += num_samples;
441 
442     if(num_samples < h->samples_per_frame)
443       h->do_audio = 0;
444     progress = (float)(h->audio_samples_written)/(float)(h->num_audio_samples);
445 
446     }
447   /* Video Iteration */
448   else
449     {
450     frame_time = lqt_frame_time(h->in_file, 0);
451     lqt_decode_video(h->in_file, h->video_buffer, 0);
452     lqt_encode_video(h->out_file, h->video_buffer, 0, frame_time);
453 
454     h->video_frames_written++;
455     if(h->video_frames_written >= h->num_video_frames)
456       h->do_video = 0;
457     progress = (float)(h->video_frames_written)/(float)(h->num_video_frames);
458     }
459   if(!h->do_audio && !h->do_video)
460     return 0;
461 
462   /* Calculate the progress */
463 
464   if(progress > h->progress)
465     h->progress = progress;
466   return 1;
467   }
468 
transcode_cleanup(transcode_handle * h)469 static void transcode_cleanup(transcode_handle * h)
470   {
471   quicktime_close(h->in_file);
472   quicktime_close(h->out_file);
473   if(h->video_buffer)
474     lqt_rows_free(h->video_buffer);
475 
476   if(h->audio_buffer_i)
477     {
478     free(h->audio_buffer_i[0]);
479     free(h->audio_buffer_i);
480     }
481   if(h->audio_buffer_f)
482     {
483     free(h->audio_buffer_f[0]);
484     free(h->audio_buffer_f);
485     }
486   }
487 
488 
main(int argc,char ** argv)489 int main(int argc, char ** argv)
490   {
491   char * in_file = (char*)0;
492   char * out_file = (char*)0;
493   char * video_codec = (char*)0;
494   char * audio_codec = (char*)0;
495   char * format = (char*)0;
496   char * qtvr = (char*)0;
497   unsigned short qtvr_rows = 0;
498   unsigned short qtvr_columns = 0;
499   int i;
500   lqt_file_type_t type = LQT_FILE_NONE, floataudio = 0;
501   transcode_handle handle;
502   int progress_written = 0;
503 
504   memset(&handle, 0, sizeof(handle));
505 
506   switch(argc)
507     {
508     case 1:
509       print_usage();
510       exit(0);
511       break;
512     case 2:
513       if(!strcmp(argv[1], "-lv"))
514         list_video_codecs();
515       else if(!strcmp(argv[1], "-la"))
516         list_audio_codecs();
517       else if(!strcmp(argv[1], "-lf"))
518         list_formats();
519       else
520         print_usage();
521       exit(0);
522       break;
523     default:
524       for(i = 1; i < argc - 2; i++)
525         {
526         if(!strcmp(argv[i], "-vc"))
527           {
528           video_codec = argv[i+1];
529           i++;
530           }
531         else if(!strcmp(argv[i], "-ac"))
532           {
533           audio_codec = argv[i+1];
534           i++;
535           }
536         else if(!strcmp(argv[i], "-f"))
537           {
538           format = argv[i+1];
539           i++;
540           }
541         else if(!strcmp(argv[i], "-avi"))
542           format = "avi";
543         else if(!strcmp(argv[i], "-floataudio"))
544           floataudio = 1;
545         else if(!strcmp(argv[i], "-qtvr")) {
546           qtvr = argv[i+1];
547 	  i++;
548 	  }
549 	else if(!strcmp(argv[i], "-qtvr_rows")) {
550           qtvr_rows = atoi(argv[i+1]);
551 	  i++;
552 	  }
553 	else if(!strcmp(argv[i], "-qtvr_columns")) {
554           qtvr_columns = atoi(argv[i+1]);
555 	  i++;
556 	  }
557         }
558       in_file = argv[argc-2];
559       out_file = argv[argc-1];
560     }
561 
562   /* Get file type */
563   if(format)
564     {
565     for(i = 0; i < sizeof(formats)/sizeof(formats[0]); i++)
566       {
567       if(!strcasecmp(format, formats[i].name))
568         {
569         type = formats[i].type;
570         break;
571         }
572       }
573     if(type == LQT_FILE_NONE)
574       {
575       fprintf(stderr, _("Unsupported format %s, try -lf"), format);
576       return -1;
577       }
578     }
579 
580   if(!transcode_init(&handle, in_file, out_file, video_codec, audio_codec,
581                      floataudio, type, qtvr, qtvr_rows, qtvr_columns))
582     {
583     return -1;
584     }
585 
586   i = 10;
587 
588   while(transcode_iteration(&handle))
589     {
590     if(i == 10)
591       {
592       if(progress_written)
593         putchar('\r');
594       printf(_("%6.2f%% Completed"), handle.progress*100.0);
595       fflush(stdout);
596       i = 0;
597       progress_written = 1;
598       }
599     i++;
600     }
601   printf(_("%6.2f%% Completed\n"), 100.0);
602 
603   if(handle.audio_samples_written)
604     printf("Transcoded %"PRId64" audio samples\n", handle.audio_samples_written);
605 
606   if(handle.video_frames_written)
607     printf("Transcoded %"PRId64" video frames\n", handle.video_frames_written);
608 
609   transcode_cleanup(&handle);
610   return 0;
611   }
612