Merge branch 'ct' of git.pipapo.org:cinelerra-ct into ct
[cinelerra_cv/ct.git] / libmpeg3 / mpeg3toc.c
blob50b201c686b28e5ecf31d5bd8f35a6b4d39a6b09
1 // New version.
2 // Very basic table of contents utility since most of the time it's going to be
3 // built inside a graphical program.
4 #if 1
7 #include "libmpeg3.h"
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
18 int main(int argc, char *argv[])
20 int i, j, l;
21 char *src = 0, *dst = 0;
22 int verbose = 0;
24 if(argc < 3)
26 fprintf(stderr, "Table of contents generator version %d.%d.%d\n"
27 "Create a table of contents for a DVD or mpeg stream.\n"
28 "Usage: mpeg3toc <path> <output>\n"
29 "\n"
30 "-v Print tracking information\n"
31 "\n"
32 "The path should be absolute unless you plan\n"
33 "to always run your movie editor from the same directory\n"
34 "as the filename. For renderfarms the filesystem prefix\n"
35 "should be / and the movie directory mounted under the same\n"
36 "directory on each node.\n\n"
37 "Example: mpeg3toc -v /cdrom/video_ts/vts_01_0.ifo titanic.toc\n",
38 mpeg3_major(),
39 mpeg3_minor(),
40 mpeg3_release());
41 exit(1);
44 for(i = 1; i < argc; i++)
46 if(!strcmp(argv[i], "-v"))
48 verbose = 1;
50 else
51 if(argv[i][0] == '-')
53 fprintf(stderr, "Unrecognized command %s\n", argv[i]);
54 exit(1);
56 else
57 if(!src)
59 src = argv[i];
61 else
62 if(!dst)
64 dst = argv[i];
66 else
68 fprintf(stderr, "Ignoring argument \"%s\"\n", argv[i]);
72 if(!src)
74 fprintf(stderr, "source path not supplied.\n");
75 exit(1);
78 if(!dst)
80 fprintf(stderr, "destination path not supplied.\n");
81 exit(1);
86 int64_t total_bytes;
87 mpeg3_t *file = mpeg3_start_toc(src, dst, &total_bytes);
88 if(!file) exit(1);
89 struct timeval new_time;
90 struct timeval prev_time;
91 struct timeval start_time;
92 struct timeval current_time;
93 gettimeofday(&prev_time, 0);
94 gettimeofday(&start_time, 0);
97 while(1)
99 int64_t bytes_processed = 0;
100 mpeg3_do_toc(file, &bytes_processed);
102 gettimeofday(&new_time, 0);
103 if(verbose && new_time.tv_sec - prev_time.tv_sec > 1)
105 gettimeofday(&current_time, 0);
106 int64_t elapsed_seconds = current_time.tv_sec - start_time.tv_sec;
107 int64_t total_seconds = elapsed_seconds * total_bytes / bytes_processed;
108 int64_t eta = total_seconds - elapsed_seconds;
109 fprintf(stderr, "%lld%% ETA: %dm%ds \r",
110 bytes_processed * 100 / total_bytes,
111 eta / 60,
112 eta % 60);
113 fflush(stdout);
114 prev_time = new_time;
117 if(bytes_processed >= total_bytes) break;
120 mpeg3_stop_toc(file);
121 gettimeofday(&current_time, 0);
122 int64_t elapsed = current_time.tv_sec - start_time.tv_sec;
123 if(verbose)
125 fprintf(stderr, "%dm%ds elapsed \n",
126 elapsed / 60,
127 elapsed % 60);
130 return 0;
139 #else
145 #include "libmpeg3.h"
146 #include "mpeg3protos.h"
148 #include <stdint.h>
149 #include <stdio.h>
150 #include <string.h>
151 #include <stdlib.h>
152 #include <sys/stat.h>
156 * Generate table of frame and sample offsets for editing.
160 #define INIT_VECTORS(data, size, allocation, tracks) \
162 int k; \
163 data = calloc(1, sizeof(int64_t*) * tracks); \
164 size = calloc(1, sizeof(int*) * tracks); \
165 allocation = calloc(1, sizeof(int*) * tracks); \
167 for(k = 0; k < tracks; k++) \
169 allocation[k] = 0x100; \
170 data[k] = calloc(1, sizeof(int64_t) * allocation[k]); \
174 #if 1
175 #define APPEND_VECTOR(data, size, allocation, track, value) \
177 uint64_t **track_data = &(data)[(track)]; \
178 int *track_allocation = &(allocation)[(track)]; \
179 int *track_size = &(size)[(track)]; \
181 if(!(*track_data) || (*track_allocation) <= (*track_size)) \
183 int64_t *new_data = calloc(1, sizeof(int64_t) * (*track_allocation) * 2); \
185 if((*track_data)) \
187 memcpy(new_data, (*track_data), sizeof(int64_t) * (*track_allocation)); \
188 free((*track_data)); \
190 (*track_allocation) *= 2; \
191 (*track_data) = new_data; \
194 (*track_data)[(*track_size)++] = (value); \
196 #else
197 #define APPEND_VECTOR(data, size, allocation, track, value) \
199 #endif
201 #define DELETE_VECTORS(data, size, allocation, tracks) \
203 int k; \
204 for(k = 0; k < tracks; k++) if(data[k]) free(data[k]); \
205 free(data); \
213 #define PUT_INT32(x) \
215 if(MPEG3_LITTLE_ENDIAN) \
217 fputc(((unsigned char*)&x)[3], output); \
218 fputc(((unsigned char*)&x)[2], output); \
219 fputc(((unsigned char*)&x)[1], output); \
220 fputc(((unsigned char*)&x)[0], output); \
222 else \
224 fputc(((unsigned char*)&x)[0], output); \
225 fputc(((unsigned char*)&x)[1], output); \
226 fputc(((unsigned char*)&x)[2], output); \
227 fputc(((unsigned char*)&x)[3], output); \
234 #define PUT_INT64(x) \
236 if(MPEG3_LITTLE_ENDIAN) \
238 fputc(((unsigned char*)&x)[7], output); \
239 fputc(((unsigned char*)&x)[6], output); \
240 fputc(((unsigned char*)&x)[5], output); \
241 fputc(((unsigned char*)&x)[4], output); \
242 fputc(((unsigned char*)&x)[3], output); \
243 fputc(((unsigned char*)&x)[2], output); \
244 fputc(((unsigned char*)&x)[1], output); \
245 fputc(((unsigned char*)&x)[0], output); \
247 else \
249 fwrite(&x, 1, 8, output); \
257 int main(int argc, char *argv[])
259 struct stat st;
260 int i, j, l;
261 char *src = 0, *dst = 0;
262 int astream_override = -1;
264 if(argc < 3)
266 fprintf(stderr, "Create a table of contents for a DVD or mpeg stream.\n"
267 " Usage: [-a audio streams] mpeg3toc <path> <output>\n"
268 "\n"
269 " -a override the number of audio streams to scan. Must be less than\n"
270 "the total number of audio streams.\n"
271 "\n"
272 " The path should be absolute unless you plan\n"
273 " to always run your movie editor from the same directory\n"
274 " as the filename. For renderfarms the filesystem prefix\n"
275 " should be / and the movie directory mounted under the same\n"
276 " directory on each node.\n"
277 "Example: mpeg3toc /cd2/video_ts/vts_01_0.ifo titanic.toc\n");
278 exit(1);
281 for(i = 1; i < argc; i++)
283 if(!strcmp(argv[i], "-a"))
285 if(i < argc - 1)
287 astream_override = atoi(argv[i + 1]);
288 if(astream_override < 0)
290 fprintf(stderr, "Total audio streams may not be negative\n");
291 exit(1);
293 else
295 fprintf(stderr,
296 "Using first %d audio streams.\n",
297 astream_override);
299 i++;
301 else
303 fprintf(stderr, "-a requires an argument.\n");
304 exit(1);
307 else
308 if(!src)
310 src = argv[i];
312 else
313 if(!dst)
315 dst = argv[i];
317 else
319 fprintf(stderr, "Ignoring argument \"%s\"\n", argv[i]);
323 if(!src)
325 fprintf(stderr, "source path not supplied.\n");
326 exit(1);
329 if(!dst)
331 fprintf(stderr, "source path not supplied.\n");
332 exit(1);
335 stat(src, &st);
337 if(!st.st_size)
339 fprintf(stderr, "%s is 0 length. Skipping\n", src);
341 else
343 int64_t size;
344 int vtracks;
345 int atracks;
346 mpeg3_t *input;
347 uint64_t **frame_offsets;
348 uint64_t **keyframe_numbers;
349 uint64_t **sample_offsets;
350 int *total_frame_offsets;
351 int *total_sample_offsets;
352 int *total_keyframe_numbers;
353 int *frame_offset_allocation;
354 int *sample_offset_allocation;
355 int *keyframe_numbers_allocation;
356 int done = 0;
357 double sample_rate;
358 double frame_rate;
359 FILE *output;
360 int total_samples = 0;
361 int total_frames = 0;
362 int rewind = 1;
364 //printf(__FUNCTION__ " 1\n");
365 input = mpeg3_open(src);
367 //printf(__FUNCTION__ " 2\n");
368 vtracks = mpeg3_total_vstreams(input);
369 atracks = mpeg3_total_astreams(input);
370 if(astream_override >= 0) atracks = astream_override;
372 if(atracks) sample_rate = mpeg3_sample_rate(input, 0);
373 if(vtracks) frame_rate = mpeg3_frame_rate(input, 0);
375 //printf(__FUNCTION__ " 3\n");
376 // Handle titles
377 INIT_VECTORS(frame_offsets, total_frame_offsets, frame_offset_allocation, vtracks);
378 INIT_VECTORS(keyframe_numbers, total_keyframe_numbers, keyframe_numbers_allocation, vtracks);
379 INIT_VECTORS(sample_offsets, total_sample_offsets, sample_offset_allocation, atracks);
381 //printf(__FUNCTION__ " 4\n");
382 while(!done)
384 int sample_count = MPEG3_AUDIO_CHUNKSIZE;
385 int frame_count;
386 int have_audio = 0;
387 int have_video = 0;
388 int64_t title_number = 0;
395 // Audio section
396 // Store current position and read sample_count from each atrack
397 for(j = 0; j < atracks; j++)
399 //printf(__FUNCTION__ " 3 %d\n", total_sample_offsets[j]);
400 if(rewind)
402 mpeg3_demuxer_t *demuxer = input->atrack[j]->demuxer;
403 mpeg3demux_seek_byte(demuxer, 0);
404 //demuxer->dump = 1;
407 if(!mpeg3_end_of_audio(input, j))
409 // Don't want to maintain separate vectors for offset and title.
410 int64_t position = mpeg3demux_tell_byte(input->atrack[j]->demuxer);
411 int64_t result;
413 if(position < MPEG3_IO_SIZE) position = MPEG3_IO_SIZE;
414 result = position;
416 have_audio = 1;
417 APPEND_VECTOR(sample_offsets,
418 total_sample_offsets,
419 sample_offset_allocation,
421 result);
424 //printf(__FUNCTION__ " 6 %d\n", j);
425 // Throw away samples
426 mpeg3_read_audio(input,
430 sample_count, /* Number of samples to decode */
433 printf("\n%lld %lld\n",
434 mpeg3demux_tell_byte(input->atrack[j]->demuxer),
435 mpeg3demux_movie_size(input->atrack[j]->demuxer));
436 //printf(__FUNCTION__ " 7 %d\n", total_sample_offsets[j]);
439 if(j == atracks - 1)
441 total_samples += sample_count;
442 fprintf(stderr, "Audio: title=%lld total_samples=%d ", title_number, total_samples);
446 //printf(__FUNCTION__ " 8\n");
447 if(have_audio)
449 frame_count =
450 (int)((double)total_samples / sample_rate * frame_rate + 0.5) -
451 total_frames;
453 else
455 frame_count = 1;
458 //printf(__FUNCTION__ " 9 %d\n", vtracks);
473 // Video section
474 for(j = 0; j < vtracks; j++)
476 mpeg3video_t *video = input->vtrack[j]->video;
477 mpeg3_demuxer_t *demuxer = input->vtrack[j]->demuxer;
478 if(rewind)
480 mpeg3demux_seek_byte(demuxer, 0);
484 for(l = 0; l < frame_count; l++)
486 if(!mpeg3_end_of_video(input, j))
488 // Transport streams always return one packet after the start of the frame.
489 int64_t position = mpeg3demux_tell_byte(demuxer) - 2048;
490 int64_t result;
491 uint32_t code = 0;
492 int got_top = 0;
493 int got_bottom = 0;
494 int got_keyframe = 0;
495 int fields = 0;
497 if(position < MPEG3_IO_SIZE) position = MPEG3_IO_SIZE;
498 result = position;
499 have_video = 1;
502 //printf("%llx\n", position);
503 // Store offset of every frame in table
504 APPEND_VECTOR(frame_offsets,
505 total_frame_offsets,
506 frame_offset_allocation,
508 result);
512 // Search for next frame start.
513 if(total_frame_offsets[j] == 1)
515 // Assume first frame is an I-frame and put its number in the keyframe number
516 // table.
517 APPEND_VECTOR(keyframe_numbers,
518 total_keyframe_numbers,
519 keyframe_numbers_allocation,
525 // Skip the first frame.
526 mpeg3video_get_header(video, 0);
527 video->current_repeat += 100;
533 // Get next frame
536 mpeg3video_get_header(video, 0);
537 video->current_repeat += 100;
539 if(video->pict_struct == TOP_FIELD)
541 got_top = 1;
543 else
544 if(video->pict_struct == BOTTOM_FIELD)
546 got_bottom = 1;
548 else
549 if(video->pict_struct == FRAME_PICTURE)
551 got_top = got_bottom = 1;
553 fields++;
555 // The way we do it, the I frames have the top field but both the I frame and
556 // subsequent P frame make the keyframe.
557 if(video->pict_type == I_TYPE)
558 got_keyframe = 1;
559 }while(!mpeg3_end_of_video(input, j) &&
560 !got_bottom &&
561 total_frame_offsets[j] > 1);
566 // Store number of a keyframe in the keyframe number table
567 if(got_keyframe)
568 APPEND_VECTOR(keyframe_numbers,
569 total_keyframe_numbers,
570 keyframe_numbers_allocation,
572 total_frame_offsets[j] - 1);
574 if(j == vtracks - 1 && l == frame_count - 1)
576 total_frames += frame_count;
577 fprintf(stderr, "Video: title=%lld total_frames=%d (%.1f \%)", title_number, total_frames,100*((float)position)/((float) mpeg3demux_movie_size(demuxer)));
583 if(!have_audio && !have_video) done = 1;
585 fprintf(stderr, "\r");
586 fflush(stderr);
588 * if(total_frames > 10000)
590 * printf("\n");
591 * return 0;
597 rewind = 0;
601 output = fopen(dst, "w");
605 // Write file type
606 fputc('T', output);
607 fputc('O', output);
608 fputc('C', output);
609 fputc(' ', output);
611 // Write version
612 fputc(MPEG3_TOC_VERSION, output);
614 if(input->is_program_stream)
616 fputc(FILE_TYPE_PROGRAM, output);
618 else
619 if(input->is_transport_stream)
621 fputc(FILE_TYPE_TRANSPORT, output);
623 else
624 if(input->is_audio_stream)
626 fputc(FILE_TYPE_AUDIO, output);
628 else
629 if(input->is_video_stream)
631 fputc(FILE_TYPE_VIDEO, output);
634 // Write stream ID's
635 // Only program and transport streams have these
636 for(i = 0; i < MPEG3_MAX_STREAMS; i++)
638 if(input->demuxer->astream_table[i])
640 fputc(STREAM_AUDIO, output);
641 PUT_INT32(i);
642 PUT_INT32(input->demuxer->astream_table[i]);
645 if(input->demuxer->vstream_table[i])
647 fputc(STREAM_VIDEO, output);
648 PUT_INT32(i);
649 PUT_INT32(input->demuxer->vstream_table[i]);
654 // Write titles
655 for(i = 0; i < input->demuxer->total_titles; i++)
657 mpeg3_title_t *title = input->demuxer->titles[i];
658 // Path
659 fputc(TITLE_PATH, output);
660 fprintf(output, title->fs->path);
661 fputc(0, output);
662 // Total bytes
663 PUT_INT64(title->total_bytes);
664 // Byte offsets of cells
665 PUT_INT32(input->demuxer->titles[i]->cell_table_size);
666 for(j = 0; j < title->cell_table_size; j++)
668 mpeg3_cell_t *cell = &title->cell_table[j];
669 PUT_INT64(cell->title_start);
670 PUT_INT64(cell->title_end);
671 PUT_INT64(cell->program_start);
672 PUT_INT64(cell->program_end);
673 PUT_INT32(cell->program);
684 fputc(ATRACK_COUNT, output);
685 PUT_INT32(atracks);
687 fputc(VTRACK_COUNT, output);
688 PUT_INT32(vtracks);
690 // Audio streams
691 for(j = 0; j < atracks; j++)
693 int channels = mpeg3_audio_channels(input, j);
694 PUT_INT32(channels);
695 PUT_INT32(total_sample_offsets[j]);
696 for(i = 0; i < total_sample_offsets[j]; i++)
698 PUT_INT64(sample_offsets[j][i]);
699 //printf("Audio: offset=%016llx\n", sample_offsets[j][i]);
703 // Video streams
704 for(j = 0; j < vtracks; j++)
706 PUT_INT32(total_frame_offsets[j]);
707 for(i = 0; i < total_frame_offsets[j]; i++)
709 PUT_INT64(frame_offsets[j][i]);
710 //printf("Video: offset=%016llx\n", frame_offsets[j][i]);
713 PUT_INT32(total_keyframe_numbers[j]);
714 for(i = 0; i < total_keyframe_numbers[j]; i++)
716 PUT_INT64(keyframe_numbers[j][i]);
717 //printf("Video: keyframe=%lld\n", keyframe_numbers[j][i]);
724 DELETE_VECTORS(frame_offsets, total_frame_offsets, frame_offset_allocation, vtracks);
725 DELETE_VECTORS(keyframe_numbers, total_keyframe_numbers, keyframe_numbers_allocation, vtracks);
726 DELETE_VECTORS(sample_offsets, total_sample_offsets, sample_offset_allocation, atracks);
729 mpeg3_close(input);
730 fclose(output);
736 return 0;
744 #endif