r715: I forgot this one...
[cinelerra_cv/mob.git] / libmpeg3 / mpeg3toc.c
blob4838c919c59854648fc33d246b68e9607c68dfba
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, "Create a table of contents for a DVD or mpeg stream.\n"
27 "Usage: mpeg3toc <path> <output>\n"
28 "\n"
29 "-v Print tracking information\n"
30 "\n"
31 "The path should be absolute unless you plan\n"
32 "to always run your movie editor from the same directory\n"
33 "as the filename. For renderfarms the filesystem prefix\n"
34 "should be / and the movie directory mounted under the same\n"
35 "directory on each node.\n\n"
36 "Example: mpeg3toc -v /cdrom/video_ts/vts_01_0.ifo titanic.toc\n");
37 exit(1);
40 for(i = 1; i < argc; i++)
42 if(!strcmp(argv[i], "-v"))
44 verbose = 1;
46 else
47 if(argv[i][0] == '-')
49 fprintf(stderr, "Unrecognized command %s\n", argv[i]);
50 exit(1);
52 else
53 if(!src)
55 src = argv[i];
57 else
58 if(!dst)
60 dst = argv[i];
62 else
64 fprintf(stderr, "Ignoring argument \"%s\"\n", argv[i]);
68 if(!src)
70 fprintf(stderr, "source path not supplied.\n");
71 exit(1);
74 if(!dst)
76 fprintf(stderr, "source path not supplied.\n");
77 exit(1);
82 int64_t total_bytes;
83 mpeg3_t *file = mpeg3_start_toc(src, dst, &total_bytes);
84 if(!file) exit(1);
85 struct timeval new_time;
86 struct timeval prev_time;
87 struct timeval start_time;
88 struct timeval current_time;
89 gettimeofday(&prev_time, 0);
90 gettimeofday(&start_time, 0);
93 while(1)
95 int64_t bytes_processed = 0;
96 mpeg3_do_toc(file, &bytes_processed);
98 gettimeofday(&new_time, 0);
99 if(verbose && new_time.tv_sec - prev_time.tv_sec > 1)
101 gettimeofday(&current_time, 0);
102 int64_t elapsed_seconds = current_time.tv_sec - start_time.tv_sec;
103 int64_t total_seconds = elapsed_seconds * total_bytes / bytes_processed;
104 int64_t eta = total_seconds - elapsed_seconds;
105 fprintf(stderr, "%lld%% ETA: %dm%ds \r",
106 bytes_processed * 100 / total_bytes,
107 eta / 60,
108 eta % 60);
109 fflush(stdout);
110 prev_time = new_time;
113 if(bytes_processed >= total_bytes) break;
116 mpeg3_stop_toc(file);
118 return 0;
127 #else
133 #include "libmpeg3.h"
134 #include "mpeg3protos.h"
136 #include <stdint.h>
137 #include <stdio.h>
138 #include <string.h>
139 #include <stdlib.h>
140 #include <sys/stat.h>
144 * Generate table of frame and sample offsets for editing.
148 #define INIT_VECTORS(data, size, allocation, tracks) \
150 int k; \
151 data = calloc(1, sizeof(int64_t*) * tracks); \
152 size = calloc(1, sizeof(int*) * tracks); \
153 allocation = calloc(1, sizeof(int*) * tracks); \
155 for(k = 0; k < tracks; k++) \
157 allocation[k] = 0x100; \
158 data[k] = calloc(1, sizeof(int64_t) * allocation[k]); \
162 #if 1
163 #define APPEND_VECTOR(data, size, allocation, track, value) \
165 uint64_t **track_data = &(data)[(track)]; \
166 int *track_allocation = &(allocation)[(track)]; \
167 int *track_size = &(size)[(track)]; \
169 if(!(*track_data) || (*track_allocation) <= (*track_size)) \
171 int64_t *new_data = calloc(1, sizeof(int64_t) * (*track_allocation) * 2); \
173 if((*track_data)) \
175 memcpy(new_data, (*track_data), sizeof(int64_t) * (*track_allocation)); \
176 free((*track_data)); \
178 (*track_allocation) *= 2; \
179 (*track_data) = new_data; \
182 (*track_data)[(*track_size)++] = (value); \
184 #else
185 #define APPEND_VECTOR(data, size, allocation, track, value) \
187 #endif
189 #define DELETE_VECTORS(data, size, allocation, tracks) \
191 int k; \
192 for(k = 0; k < tracks; k++) if(data[k]) free(data[k]); \
193 free(data); \
201 #define PUT_INT32(x) \
203 if(MPEG3_LITTLE_ENDIAN) \
205 fputc(((unsigned char*)&x)[3], output); \
206 fputc(((unsigned char*)&x)[2], output); \
207 fputc(((unsigned char*)&x)[1], output); \
208 fputc(((unsigned char*)&x)[0], output); \
210 else \
212 fputc(((unsigned char*)&x)[0], output); \
213 fputc(((unsigned char*)&x)[1], output); \
214 fputc(((unsigned char*)&x)[2], output); \
215 fputc(((unsigned char*)&x)[3], output); \
222 #define PUT_INT64(x) \
224 if(MPEG3_LITTLE_ENDIAN) \
226 fputc(((unsigned char*)&x)[7], output); \
227 fputc(((unsigned char*)&x)[6], output); \
228 fputc(((unsigned char*)&x)[5], output); \
229 fputc(((unsigned char*)&x)[4], output); \
230 fputc(((unsigned char*)&x)[3], output); \
231 fputc(((unsigned char*)&x)[2], output); \
232 fputc(((unsigned char*)&x)[1], output); \
233 fputc(((unsigned char*)&x)[0], output); \
235 else \
237 fwrite(&x, 1, 8, output); \
245 int main(int argc, char *argv[])
247 struct stat st;
248 int i, j, l;
249 char *src = 0, *dst = 0;
250 int astream_override = -1;
252 if(argc < 3)
254 fprintf(stderr, "Create a table of contents for a DVD or mpeg stream.\n"
255 " Usage: [-a audio streams] mpeg3toc <path> <output>\n"
256 "\n"
257 " -a override the number of audio streams to scan. Must be less than\n"
258 "the total number of audio streams.\n"
259 "\n"
260 " The path should be absolute unless you plan\n"
261 " to always run your movie editor from the same directory\n"
262 " as the filename. For renderfarms the filesystem prefix\n"
263 " should be / and the movie directory mounted under the same\n"
264 " directory on each node.\n"
265 "Example: mpeg3toc /cd2/video_ts/vts_01_0.ifo titanic.toc\n");
266 exit(1);
269 for(i = 1; i < argc; i++)
271 if(!strcmp(argv[i], "-a"))
273 if(i < argc - 1)
275 astream_override = atoi(argv[i + 1]);
276 if(astream_override < 0)
278 fprintf(stderr, "Total audio streams may not be negative\n");
279 exit(1);
281 else
283 fprintf(stderr,
284 "Using first %d audio streams.\n",
285 astream_override);
287 i++;
289 else
291 fprintf(stderr, "-a requires an argument.\n");
292 exit(1);
295 else
296 if(!src)
298 src = argv[i];
300 else
301 if(!dst)
303 dst = argv[i];
305 else
307 fprintf(stderr, "Ignoring argument \"%s\"\n", argv[i]);
311 if(!src)
313 fprintf(stderr, "source path not supplied.\n");
314 exit(1);
317 if(!dst)
319 fprintf(stderr, "source path not supplied.\n");
320 exit(1);
323 stat(src, &st);
325 if(!st.st_size)
327 fprintf(stderr, "%s is 0 length. Skipping\n", src);
329 else
331 int64_t size;
332 int vtracks;
333 int atracks;
334 mpeg3_t *input;
335 uint64_t **frame_offsets;
336 uint64_t **keyframe_numbers;
337 uint64_t **sample_offsets;
338 int *total_frame_offsets;
339 int *total_sample_offsets;
340 int *total_keyframe_numbers;
341 int *frame_offset_allocation;
342 int *sample_offset_allocation;
343 int *keyframe_numbers_allocation;
344 int done = 0;
345 double sample_rate;
346 double frame_rate;
347 FILE *output;
348 int total_samples = 0;
349 int total_frames = 0;
350 int rewind = 1;
352 //printf(__FUNCTION__ " 1\n");
353 input = mpeg3_open(src);
355 //printf(__FUNCTION__ " 2\n");
356 vtracks = mpeg3_total_vstreams(input);
357 atracks = mpeg3_total_astreams(input);
358 if(astream_override >= 0) atracks = astream_override;
360 if(atracks) sample_rate = mpeg3_sample_rate(input, 0);
361 if(vtracks) frame_rate = mpeg3_frame_rate(input, 0);
363 //printf(__FUNCTION__ " 3\n");
364 // Handle titles
365 INIT_VECTORS(frame_offsets, total_frame_offsets, frame_offset_allocation, vtracks);
366 INIT_VECTORS(keyframe_numbers, total_keyframe_numbers, keyframe_numbers_allocation, vtracks);
367 INIT_VECTORS(sample_offsets, total_sample_offsets, sample_offset_allocation, atracks);
369 //printf(__FUNCTION__ " 4\n");
370 while(!done)
372 int sample_count = MPEG3_AUDIO_CHUNKSIZE;
373 int frame_count;
374 int have_audio = 0;
375 int have_video = 0;
376 int64_t title_number = 0;
383 // Audio section
384 // Store current position and read sample_count from each atrack
385 for(j = 0; j < atracks; j++)
387 //printf(__FUNCTION__ " 3 %d\n", total_sample_offsets[j]);
388 if(rewind)
390 mpeg3_demuxer_t *demuxer = input->atrack[j]->demuxer;
391 mpeg3demux_seek_byte(demuxer, 0);
392 //demuxer->dump = 1;
395 if(!mpeg3_end_of_audio(input, j))
397 // Don't want to maintain separate vectors for offset and title.
398 int64_t position = mpeg3demux_tell_byte(input->atrack[j]->demuxer);
399 int64_t result;
401 if(position < MPEG3_IO_SIZE) position = MPEG3_IO_SIZE;
402 result = position;
404 have_audio = 1;
405 APPEND_VECTOR(sample_offsets,
406 total_sample_offsets,
407 sample_offset_allocation,
409 result);
412 //printf(__FUNCTION__ " 6 %d\n", j);
413 // Throw away samples
414 mpeg3_read_audio(input,
418 sample_count, /* Number of samples to decode */
421 printf("\n%lld %lld\n",
422 mpeg3demux_tell_byte(input->atrack[j]->demuxer),
423 mpeg3demux_movie_size(input->atrack[j]->demuxer));
424 //printf(__FUNCTION__ " 7 %d\n", total_sample_offsets[j]);
427 if(j == atracks - 1)
429 total_samples += sample_count;
430 fprintf(stderr, "Audio: title=%lld total_samples=%d ", title_number, total_samples);
434 //printf(__FUNCTION__ " 8\n");
435 if(have_audio)
437 frame_count =
438 (int)((double)total_samples / sample_rate * frame_rate + 0.5) -
439 total_frames;
441 else
443 frame_count = 1;
446 //printf(__FUNCTION__ " 9 %d\n", vtracks);
461 // Video section
462 for(j = 0; j < vtracks; j++)
464 mpeg3video_t *video = input->vtrack[j]->video;
465 mpeg3_demuxer_t *demuxer = input->vtrack[j]->demuxer;
466 if(rewind)
468 mpeg3demux_seek_byte(demuxer, 0);
472 for(l = 0; l < frame_count; l++)
474 if(!mpeg3_end_of_video(input, j))
476 // Transport streams always return one packet after the start of the frame.
477 int64_t position = mpeg3demux_tell_byte(demuxer) - 2048;
478 int64_t result;
479 uint32_t code = 0;
480 int got_top = 0;
481 int got_bottom = 0;
482 int got_keyframe = 0;
483 int fields = 0;
485 if(position < MPEG3_IO_SIZE) position = MPEG3_IO_SIZE;
486 result = position;
487 have_video = 1;
490 //printf("%llx\n", position);
491 // Store offset of every frame in table
492 APPEND_VECTOR(frame_offsets,
493 total_frame_offsets,
494 frame_offset_allocation,
496 result);
500 // Search for next frame start.
501 if(total_frame_offsets[j] == 1)
503 // Assume first frame is an I-frame and put its number in the keyframe number
504 // table.
505 APPEND_VECTOR(keyframe_numbers,
506 total_keyframe_numbers,
507 keyframe_numbers_allocation,
513 // Skip the first frame.
514 mpeg3video_get_header(video, 0);
515 video->current_repeat += 100;
521 // Get next frame
524 mpeg3video_get_header(video, 0);
525 video->current_repeat += 100;
527 if(video->pict_struct == TOP_FIELD)
529 got_top = 1;
531 else
532 if(video->pict_struct == BOTTOM_FIELD)
534 got_bottom = 1;
536 else
537 if(video->pict_struct == FRAME_PICTURE)
539 got_top = got_bottom = 1;
541 fields++;
543 // The way we do it, the I frames have the top field but both the I frame and
544 // subsequent P frame make the keyframe.
545 if(video->pict_type == I_TYPE)
546 got_keyframe = 1;
547 }while(!mpeg3_end_of_video(input, j) &&
548 !got_bottom &&
549 total_frame_offsets[j] > 1);
554 // Store number of a keyframe in the keyframe number table
555 if(got_keyframe)
556 APPEND_VECTOR(keyframe_numbers,
557 total_keyframe_numbers,
558 keyframe_numbers_allocation,
560 total_frame_offsets[j] - 1);
562 if(j == vtracks - 1 && l == frame_count - 1)
564 total_frames += frame_count;
565 fprintf(stderr, "Video: title=%lld total_frames=%d (%.1f \%)", title_number, total_frames,100*((float)position)/((float) mpeg3demux_movie_size(demuxer)));
571 if(!have_audio && !have_video) done = 1;
573 fprintf(stderr, "\r");
574 fflush(stderr);
576 * if(total_frames > 10000)
578 * printf("\n");
579 * return 0;
585 rewind = 0;
589 output = fopen(dst, "w");
593 // Write file type
594 fputc('T', output);
595 fputc('O', output);
596 fputc('C', output);
597 fputc(' ', output);
599 // Write version
600 fputc(MPEG3_TOC_VERSION, output);
602 if(input->is_program_stream)
604 fputc(FILE_TYPE_PROGRAM, output);
606 else
607 if(input->is_transport_stream)
609 fputc(FILE_TYPE_TRANSPORT, output);
611 else
612 if(input->is_audio_stream)
614 fputc(FILE_TYPE_AUDIO, output);
616 else
617 if(input->is_video_stream)
619 fputc(FILE_TYPE_VIDEO, output);
622 // Write stream ID's
623 // Only program and transport streams have these
624 for(i = 0; i < MPEG3_MAX_STREAMS; i++)
626 if(input->demuxer->astream_table[i])
628 fputc(STREAM_AUDIO, output);
629 PUT_INT32(i);
630 PUT_INT32(input->demuxer->astream_table[i]);
633 if(input->demuxer->vstream_table[i])
635 fputc(STREAM_VIDEO, output);
636 PUT_INT32(i);
637 PUT_INT32(input->demuxer->vstream_table[i]);
642 // Write titles
643 for(i = 0; i < input->demuxer->total_titles; i++)
645 mpeg3_title_t *title = input->demuxer->titles[i];
646 // Path
647 fputc(TITLE_PATH, output);
648 fprintf(output, title->fs->path);
649 fputc(0, output);
650 // Total bytes
651 PUT_INT64(title->total_bytes);
652 // Byte offsets of cells
653 PUT_INT32(input->demuxer->titles[i]->cell_table_size);
654 for(j = 0; j < title->cell_table_size; j++)
656 mpeg3_cell_t *cell = &title->cell_table[j];
657 PUT_INT64(cell->title_start);
658 PUT_INT64(cell->title_end);
659 PUT_INT64(cell->program_start);
660 PUT_INT64(cell->program_end);
661 PUT_INT32(cell->program);
672 fputc(ATRACK_COUNT, output);
673 PUT_INT32(atracks);
675 fputc(VTRACK_COUNT, output);
676 PUT_INT32(vtracks);
678 // Audio streams
679 for(j = 0; j < atracks; j++)
681 int channels = mpeg3_audio_channels(input, j);
682 PUT_INT32(channels);
683 PUT_INT32(total_sample_offsets[j]);
684 for(i = 0; i < total_sample_offsets[j]; i++)
686 PUT_INT64(sample_offsets[j][i]);
687 //printf("Audio: offset=%016llx\n", sample_offsets[j][i]);
691 // Video streams
692 for(j = 0; j < vtracks; j++)
694 PUT_INT32(total_frame_offsets[j]);
695 for(i = 0; i < total_frame_offsets[j]; i++)
697 PUT_INT64(frame_offsets[j][i]);
698 //printf("Video: offset=%016llx\n", frame_offsets[j][i]);
701 PUT_INT32(total_keyframe_numbers[j]);
702 for(i = 0; i < total_keyframe_numbers[j]; i++)
704 PUT_INT64(keyframe_numbers[j][i]);
705 //printf("Video: keyframe=%lld\n", keyframe_numbers[j][i]);
712 DELETE_VECTORS(frame_offsets, total_frame_offsets, frame_offset_allocation, vtracks);
713 DELETE_VECTORS(keyframe_numbers, total_keyframe_numbers, keyframe_numbers_allocation, vtracks);
714 DELETE_VECTORS(sample_offsets, total_sample_offsets, sample_offset_allocation, atracks);
717 mpeg3_close(input);
718 fclose(output);
724 return 0;
732 #endif