1 /* Concatenate elementary streams */
2 /* Mpeg3cat is useful for extracting elementary streams from program streams. */
6 #include "mpeg3protos.h"
13 #define MPEG3_SEQUENCE_START_CODE 0x000001b3
14 #define BUFFER_SIZE 1000000
16 int main(int argc
, char *argv
[])
18 char inpath
[1024], outpath
[1024], newpath
[1024];
22 int current_file
, current_output_file
= 0, i
;
24 unsigned char *buffer
;
27 long total_frames
= 0;
28 int do_audio
= 0, do_video
= 0;
30 int64_t total_written
= 0;
34 fprintf(stderr
, "Concatenate elementary streams or demultiplex a program stream.\n"
35 "Usage: mpeg3cat -[av0123456789] <infile> [infile...] > <outfile>\n\n"
36 "Example: Concatenate 2 video files: mpeg3cat xena1.m2v xena2.m2v > xena.m2v\n"
37 " Extract audio stream 0: mpeg3cat -a0 xena.vob > war_cry.ac3\n");
42 for(i
= 1; i
< argc
; i
++)
46 if(argv
[i
][1] != 'a' && argv
[i
][1] != 'v' && argv
[i
][1] != 'o')
48 fprintf(stderr
, "invalid option %s\n", argv
[i
]);
57 strcpy(outpath
, argv
[++i
]);
61 fprintf(stderr
, "-o requires an output file\n");
65 // Check if file exists
66 if(out
= fopen(outpath
, "r"))
68 fprintf(stderr
, "%s exists.\n", outpath
);
75 if(argv
[i
][1] == 'a') do_audio
= 1;
77 if(argv
[i
][1] == 'v') do_video
= 1;
81 stream
= argv
[i
][2] - 48;
87 buffer
= malloc(BUFFER_SIZE
);
90 if(!(out
= fopen(outpath
, "wb")))
92 fprintf(stderr
, "Failed to open %s for writing\n", outpath
);
99 for(current_file
= 1; current_file
< argc
; current_file
++)
101 if(argv
[current_file
][0] == '-') continue;
103 strcpy(inpath
, argv
[current_file
]);
104 if(!(in
= mpeg3_open(inpath
)))
106 fprintf(stderr
, "Skipping %s\n", inpath
);
114 //fprintf(stderr, "%d %d %d %d\n", in->is_transport_stream, in->is_program_stream, in->is_audio_stream, in->is_video_stream);
115 if((mpeg3_has_audio(in
) && in
->is_audio_stream
) ||
116 (do_audio
&& !in
->is_audio_stream
&& !in
->is_video_stream
))
119 /* Add audio stream to end */
120 mpeg3demux_seek_byte(in
->atrack
[stream
]->demuxer
, 0);
121 // mpeg3bits_refill(in->atrack[stream]->audio->astream);
122 while(!mpeg3_read_audio_chunk(in
,
128 result
= !fwrite(buffer
, output_size
, 1, out
);
131 perror("fwrite audio chunk");
137 if((mpeg3_has_video(in
) && in
->is_video_stream
) ||
138 (do_video
&& !in
->is_video_stream
&& !in
->is_audio_stream
))
140 /* Add video stream to end */
141 int hour
, minute
, second
, frame
;
147 mpeg3demux_seek_byte(in
->vtrack
[stream
]->demuxer
, 0);
148 mpeg3bits_refill(in
->vtrack
[stream
]->video
->vstream
);
150 while(!mpeg3_read_video_chunk(in
,
157 code
= (unsigned long)buffer
[output_size
- 4] << 24;
158 code
|= (unsigned long)buffer
[output_size
- 3] << 16;
159 code
|= (unsigned long)buffer
[output_size
- 2] << 8;
160 code
|= (unsigned long)buffer
[output_size
- 1];
162 /* Got a frame at the end of this buffer. */
163 if(code
== MPEG3_PICTURE_START_CODE
)
168 if(code
== MPEG3_SEQUENCE_END_CODE
)
170 /* Got a sequence end code at the end of this buffer. */
174 code
= (unsigned long)buffer
[0] << 24;
175 code
|= (unsigned long)buffer
[1] << 16;
176 code
|= (unsigned long)buffer
[2] << 8;
181 if(code
== MPEG3_SEQUENCE_START_CODE
&& current_output_file
> 0)
183 /* Skip the sequence start code */
185 while(i
< output_size
&&
186 code
!= MPEG3_GOP_START_CODE
)
195 /* Search for GOP header to fix */
196 code
= (unsigned long)buffer
[i
++] << 24;
197 code
|= (unsigned long)buffer
[i
++] << 16;
198 code
|= (unsigned long)buffer
[i
++] << 8;
200 while(i
< output_size
&&
201 code
!= MPEG3_GOP_START_CODE
)
207 if(code
== MPEG3_GOP_START_CODE
)
209 /* Get the time code */
210 code
= (unsigned long)buffer
[i
] << 24;
211 code
|= (unsigned long)buffer
[i
+ 1] << 16;
212 code
|= (unsigned long)buffer
[i
+ 2] << 8;
213 code
|= (unsigned long)buffer
[i
+ 3];
215 hour
= code
>> 26 & 0x1f;
216 minute
= code
>> 20 & 0x3f;
217 second
= code
>> 13 & 0x3f;
218 frame
= code
>> 7 & 0x3f;
220 gop_frame
= (long)(hour
* 3600 * mpeg3_frame_rate(in
, stream
) +
221 minute
* 60 * mpeg3_frame_rate(in
, stream
) +
222 second
* mpeg3_frame_rate(in
, stream
) +
224 /* fprintf(stderr, "old: %02d:%02d:%02d:%02d ", hour, minute, second, frame); */
225 /* Write a new time code */
226 hour
= (long)((float)(total_frames
- 1) / mpeg3_frame_rate(in
, stream
) / 3600);
227 carry
= hour
* 3600 * mpeg3_frame_rate(in
, stream
);
228 minute
= (long)((float)(total_frames
- 1 - carry
) / mpeg3_frame_rate(in
, stream
) / 60);
229 carry
+= minute
* 60 * mpeg3_frame_rate(in
, stream
);
230 second
= (long)((float)(total_frames
- 1 - carry
) / mpeg3_frame_rate(in
, stream
));
231 carry
+= second
* mpeg3_frame_rate(in
, stream
);
232 frame
= (total_frames
- 1 - carry
);
234 buffer
[i
] = ((code
>> 24) & 0x80) | (hour
<< 2) | (minute
>> 4);
235 buffer
[i
+ 1] = ((code
>> 16) & 0x08) | ((minute
& 0xf) << 4) | (second
>> 3);
236 buffer
[i
+ 2] = ((second
& 0x7) << 5) | (frame
>> 1);
237 buffer
[i
+ 3] = (code
& 0x7f) | ((frame
& 0x1) << 7);
238 /* fprintf(stderr, "new: %02d:%02d:%02d:%02d\n", hour, minute, second, frame); */
242 /* Test 32 bit overflow */
245 if(ftell(out
) > 0x7f000000)
249 sprintf(newpath
, "%s%03d", outpath
, out_counter
);
250 if(!(out
= fopen(newpath
, "wb")))
252 fprintf(stderr
, "Couldn't open %s for writing.\n", newpath
);
258 * fprintf(stderr, "mpeg3cat 5 %02x %02x %02x %02x\n",
259 * (buffer + offset)[0],
260 * (buffer + offset)[1],
261 * (buffer + offset)[2],
262 * (buffer + offset)[3]);
265 /* Write the frame */
266 result
= !fwrite(buffer
+ offset
, output_size
- offset
, 1, out
);
269 perror("fwrite video chunk");
275 if(in
->is_program_stream
)
277 mpeg3_demuxer_t
*demuxer
= in
->vtrack
[0]->demuxer
;
279 //fprintf(stderr, "mpeg3cat 1\n");
281 /* Append program stream with no changes */
282 demuxer
->read_all
= 1;
283 mpeg3demux_seek_byte(demuxer
, 0);
287 result
= mpeg3_advance_timecode(demuxer
, 0);
290 //fprintf(stderr, "mpeg3cat 1 %d\n", result);
293 result
= mpeg3demux_read_program(demuxer
);
295 fprintf(stderr
, "Hit end of data in %s\n", inpath
);
302 long decryption_offset
= demuxer
->last_packet_decryption
- demuxer
->last_packet_start
;
303 mpeg3_title_t
*title
= demuxer
->titles
[demuxer
->current_title
];
304 mpeg3io_seek(title
->fs
, demuxer
->last_packet_start
);
305 demuxer
->raw_size
= demuxer
->last_packet_end
- demuxer
->last_packet_start
;
306 //fprintf(stderr, "mpeg3cat 2 %d %x\n", decryption_offset, demuxer->raw_data[decryption_offset]);
309 * if(demuxer->raw_size != 0x800)
310 * fprintf(stderr, __FUNCTION__ " %llx", demuxer->last_packet_start);
313 mpeg3io_read_data(demuxer
->raw_data
, demuxer
->raw_size
, title
->fs
);
314 if(decryption_offset
> 0 &&
315 demuxer
->raw_data
[decryption_offset
] & 0x30)
317 //fprintf(stderr, "mpeg3cat 3\n");
318 if(mpeg3_decrypt_packet(title
->fs
->css
,
322 fprintf(stderr
, "get_ps_pes_packet: Decryption not available\n");
325 //fprintf(stderr, "mpeg3cat 4\n");
326 demuxer
->raw_data
[decryption_offset
] &= 0xcf;
330 //printf("mpeg3cat 3 %d\n", result);
334 result
= !fwrite(demuxer
->raw_data
,
338 total_written
+= demuxer
->raw_size
;
339 if(result
) fprintf(stderr
, "%s\n", strerror(errno
));
342 //fprintf(stderr, "%llx %llx\n", mpeg3demux_tell(demuxer), mpeg3demux_tell(demuxer) - total_written);
347 fprintf(stderr
, "Unsupported stream type.\n");
355 current_output_file
++;
358 /* Terminate output */
359 if(current_output_file
> 0 && do_video
)
361 /*fprintf(stderr, "\n"); */
362 /* Write new end of sequence */
363 buffer
[0] = MPEG3_SEQUENCE_END_CODE
>> 24;
364 buffer
[1] = (MPEG3_SEQUENCE_END_CODE
>> 16) & 0xff;
365 buffer
[2] = (MPEG3_SEQUENCE_END_CODE
>> 8) & 0xff;
366 buffer
[3] = MPEG3_SEQUENCE_END_CODE
& 0xff;
367 result
= !fwrite(buffer
, 4, 1, out
);
369 if(outpath
[0]) fclose(out
);