2 // Very basic table of contents utility since most of the time it's going to be
3 // built inside a graphical program.
18 int main(int argc
, char *argv
[])
21 char *src
= 0, *dst
= 0;
26 fprintf(stderr
, "Create a table of contents for a DVD or mpeg stream.\n"
27 "Usage: mpeg3toc <path> <output>\n"
29 "-v Print tracking information\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");
40 for(i
= 1; i
< argc
; i
++)
42 if(!strcmp(argv
[i
], "-v"))
49 fprintf(stderr
, "Unrecognized command %s\n", argv
[i
]);
64 fprintf(stderr
, "Ignoring argument \"%s\"\n", argv
[i
]);
70 fprintf(stderr
, "source path not supplied.\n");
76 fprintf(stderr
, "source path not supplied.\n");
83 mpeg3_t
*file
= mpeg3_start_toc(src
, dst
, &total_bytes
);
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);
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(¤t_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
,
110 prev_time
= new_time
;
113 if(bytes_processed
>= total_bytes
) break;
116 mpeg3_stop_toc(file
);
133 #include "libmpeg3.h"
134 #include "mpeg3protos.h"
140 #include <sys/stat.h>
144 * Generate table of frame and sample offsets for editing.
148 #define INIT_VECTORS(data, size, allocation, tracks) \
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]); \
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); \
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); \
185 #define APPEND_VECTOR(data, size, allocation, track, value) \
189 #define DELETE_VECTORS(data, size, allocation, tracks) \
192 for(k = 0; k < tracks; k++) if(data[k]) free(data[k]); \
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); \
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); \
237 fwrite(&x, 1, 8, output); \
245 int main(int argc
, char *argv
[])
249 char *src
= 0, *dst
= 0;
250 int astream_override
= -1;
254 fprintf(stderr
, "Create a table of contents for a DVD or mpeg stream.\n"
255 " Usage: [-a audio streams] mpeg3toc <path> <output>\n"
257 " -a override the number of audio streams to scan. Must be less than\n"
258 "the total number of audio streams.\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");
269 for(i
= 1; i
< argc
; i
++)
271 if(!strcmp(argv
[i
], "-a"))
275 astream_override
= atoi(argv
[i
+ 1]);
276 if(astream_override
< 0)
278 fprintf(stderr
, "Total audio streams may not be negative\n");
284 "Using first %d audio streams.\n",
291 fprintf(stderr
, "-a requires an argument.\n");
307 fprintf(stderr
, "Ignoring argument \"%s\"\n", argv
[i
]);
313 fprintf(stderr
, "source path not supplied.\n");
319 fprintf(stderr
, "source path not supplied.\n");
327 fprintf(stderr
, "%s is 0 length. Skipping\n", src
);
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
;
348 int total_samples
= 0;
349 int total_frames
= 0;
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");
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");
372 int sample_count
= MPEG3_AUDIO_CHUNKSIZE
;
376 int64_t title_number
= 0;
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]);
390 mpeg3_demuxer_t
*demuxer
= input
->atrack
[j
]->demuxer
;
391 mpeg3demux_seek_byte(demuxer
, 0);
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
);
401 if(position
< MPEG3_IO_SIZE
) position
= MPEG3_IO_SIZE
;
405 APPEND_VECTOR(sample_offsets
,
406 total_sample_offsets
,
407 sample_offset_allocation
,
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]);
429 total_samples
+= sample_count
;
430 fprintf(stderr
, "Audio: title=%lld total_samples=%d ", title_number
, total_samples
);
434 //printf(__FUNCTION__ " 8\n");
438 (int)((double)total_samples
/ sample_rate
* frame_rate
+ 0.5) -
446 //printf(__FUNCTION__ " 9 %d\n", vtracks);
462 for(j
= 0; j
< vtracks
; j
++)
464 mpeg3video_t
*video
= input
->vtrack
[j
]->video
;
465 mpeg3_demuxer_t
*demuxer
= input
->vtrack
[j
]->demuxer
;
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;
482 int got_keyframe
= 0;
485 if(position
< MPEG3_IO_SIZE
) position
= MPEG3_IO_SIZE
;
490 //printf("%llx\n", position);
491 // Store offset of every frame in table
492 APPEND_VECTOR(frame_offsets
,
494 frame_offset_allocation
,
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
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;
524 mpeg3video_get_header(video
, 0);
525 video
->current_repeat
+= 100;
527 if(video
->pict_struct
== TOP_FIELD
)
532 if(video
->pict_struct
== BOTTOM_FIELD
)
537 if(video
->pict_struct
== FRAME_PICTURE
)
539 got_top
= got_bottom
= 1;
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
)
547 }while(!mpeg3_end_of_video(input
, j
) &&
549 total_frame_offsets
[j
] > 1);
554 // Store number of a keyframe in the keyframe number table
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");
576 * if(total_frames > 10000)
589 output
= fopen(dst
, "w");
600 fputc(MPEG3_TOC_VERSION
, output
);
602 if(input
->is_program_stream
)
604 fputc(FILE_TYPE_PROGRAM
, output
);
607 if(input
->is_transport_stream
)
609 fputc(FILE_TYPE_TRANSPORT
, output
);
612 if(input
->is_audio_stream
)
614 fputc(FILE_TYPE_AUDIO
, output
);
617 if(input
->is_video_stream
)
619 fputc(FILE_TYPE_VIDEO
, output
);
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
);
630 PUT_INT32(input
->demuxer
->astream_table
[i
]);
633 if(input
->demuxer
->vstream_table
[i
])
635 fputc(STREAM_VIDEO
, output
);
637 PUT_INT32(input
->demuxer
->vstream_table
[i
]);
643 for(i
= 0; i
< input
->demuxer
->total_titles
; i
++)
645 mpeg3_title_t
*title
= input
->demuxer
->titles
[i
];
647 fputc(TITLE_PATH
, output
);
648 fprintf(output
, title
->fs
->path
);
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
);
675 fputc(VTRACK_COUNT
, output
);
679 for(j
= 0; j
< atracks
; j
++)
681 int channels
= mpeg3_audio_channels(input
, j
);
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]);
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
);