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];
20 int total_infiles
= 0;
24 int current_file
, current_output_file
= 0, i
;
26 unsigned char *buffer
;
29 long total_frames
= 0;
30 int do_audio
= 0, do_video
= 0;
32 int64_t total_written
= 0;
36 fprintf(stderr
, "Concatenate elementary streams or demultiplex a program stream.\n"
37 "Usage: mpeg3cat -[av0123456789] <infile> [infile...] > <outfile>\n\n"
38 "Example: Concatenate 2 video files: mpeg3cat xena1.m2v xena2.m2v > xena.m2v\n"
39 " Extract audio stream 0: mpeg3cat -a0 xena.vob > war_cry.ac3\n");
44 for(i
= 1; i
< argc
; i
++)
48 if(argv
[i
][1] != 'a' && argv
[i
][1] != 'v' && argv
[i
][1] != 'o')
50 fprintf(stderr
, "invalid option %s\n", argv
[i
]);
59 strcpy(outpath
, argv
[++i
]);
63 fprintf(stderr
, "-o requires an output file\n");
67 // Check if file exists
68 if(out
= fopen(outpath
, "r"))
70 fprintf(stderr
, "%s exists.\n", outpath
);
77 if(argv
[i
][1] == 'a') do_audio
= 1;
79 if(argv
[i
][1] == 'v') do_video
= 1;
83 stream
= argv
[i
][2] - '0';
89 inpaths
[total_infiles
++] = argv
[i
];
93 buffer
= malloc(BUFFER_SIZE
);
96 if(!(out
= fopen(outpath
, "wb")))
98 fprintf(stderr
, "Failed to open %s for writing\n", outpath
);
105 for(current_file
= 0; current_file
< total_infiles
; current_file
++)
107 strcpy(inpath
, inpaths
[current_file
]);
110 if(!(in
= mpeg3_open(inpath
, &error
)))
112 fprintf(stderr
, "Skipping %s\n", inpath
);
120 /* output elementary audio stream */
121 if((mpeg3_has_audio(in
) && in
->is_audio_stream
) ||
122 (do_audio
&& !in
->is_audio_stream
&& !in
->is_video_stream
))
125 /* Add audio stream to end */
126 if(stream
>= in
->total_astreams
)
128 fprintf(stderr
, "No audio stream %d\n", stream
);
132 mpeg3demux_seek_byte(in
->atrack
[stream
]->demuxer
, 0);
133 // mpeg3bits_refill(in->atrack[stream]->audio->astream);
134 //printf("mpeg3cat 1\n");
135 while(!mpeg3_read_audio_chunk(in
,
141 //printf("mpeg3cat 2 0x%x\n", output_size);
142 result
= !fwrite(buffer
, output_size
, 1, out
);
145 perror("fwrite audio chunk");
149 //printf("mpeg3cat 3\n");
152 /* Output elementary video stream */
153 if((mpeg3_has_video(in
) && in
->is_video_stream
) ||
154 (do_video
&& !in
->is_video_stream
&& !in
->is_audio_stream
))
156 /* Add video stream to end */
157 int hour
, minute
, second
, frame
;
163 if(stream
>= in
->total_vstreams
)
165 fprintf(stderr
, "No audio stream %d\n", stream
);
169 mpeg3demux_seek_byte(in
->vtrack
[stream
]->demuxer
, 0);
170 mpeg3bits_refill(in
->vtrack
[stream
]->video
->vstream
);
172 while(!mpeg3_read_video_chunk(in
,
179 code
= (unsigned long)buffer
[output_size
- 4] << 24;
180 code
|= (unsigned long)buffer
[output_size
- 3] << 16;
181 code
|= (unsigned long)buffer
[output_size
- 2] << 8;
182 code
|= (unsigned long)buffer
[output_size
- 1];
184 /* Got a frame at the end of this buffer. */
185 if(code
== MPEG3_PICTURE_START_CODE
)
190 if(code
== MPEG3_SEQUENCE_END_CODE
)
192 /* Got a sequence end code at the end of this buffer. */
196 code
= (unsigned long)buffer
[0] << 24;
197 code
|= (unsigned long)buffer
[1] << 16;
198 code
|= (unsigned long)buffer
[2] << 8;
203 if(code
== MPEG3_SEQUENCE_START_CODE
&& current_output_file
> 0)
205 /* Skip the sequence start code */
207 while(i
< output_size
&&
208 code
!= MPEG3_GOP_START_CODE
)
217 /* Search for GOP header to fix */
218 code
= (unsigned long)buffer
[i
++] << 24;
219 code
|= (unsigned long)buffer
[i
++] << 16;
220 code
|= (unsigned long)buffer
[i
++] << 8;
222 while(i
< output_size
&&
223 code
!= MPEG3_GOP_START_CODE
)
229 if(code
== MPEG3_GOP_START_CODE
)
231 /* Get the time code */
232 code
= (unsigned long)buffer
[i
] << 24;
233 code
|= (unsigned long)buffer
[i
+ 1] << 16;
234 code
|= (unsigned long)buffer
[i
+ 2] << 8;
235 code
|= (unsigned long)buffer
[i
+ 3];
237 hour
= code
>> 26 & 0x1f;
238 minute
= code
>> 20 & 0x3f;
239 second
= code
>> 13 & 0x3f;
240 frame
= code
>> 7 & 0x3f;
242 gop_frame
= (long)(hour
* 3600 * mpeg3_frame_rate(in
, stream
) +
243 minute
* 60 * mpeg3_frame_rate(in
, stream
) +
244 second
* mpeg3_frame_rate(in
, stream
) +
246 /* fprintf(stderr, "old: %02d:%02d:%02d:%02d ", hour, minute, second, frame); */
247 /* Write a new time code */
248 hour
= (long)((float)(total_frames
- 1) / mpeg3_frame_rate(in
, stream
) / 3600);
249 carry
= hour
* 3600 * mpeg3_frame_rate(in
, stream
);
250 minute
= (long)((float)(total_frames
- 1 - carry
) / mpeg3_frame_rate(in
, stream
) / 60);
251 carry
+= minute
* 60 * mpeg3_frame_rate(in
, stream
);
252 second
= (long)((float)(total_frames
- 1 - carry
) / mpeg3_frame_rate(in
, stream
));
253 carry
+= second
* mpeg3_frame_rate(in
, stream
);
254 frame
= (total_frames
- 1 - carry
);
256 buffer
[i
] = ((code
>> 24) & 0x80) | (hour
<< 2) | (minute
>> 4);
257 buffer
[i
+ 1] = ((code
>> 16) & 0x08) | ((minute
& 0xf) << 4) | (second
>> 3);
258 buffer
[i
+ 2] = ((second
& 0x7) << 5) | (frame
>> 1);
259 buffer
[i
+ 3] = (code
& 0x7f) | ((frame
& 0x1) << 7);
260 /* fprintf(stderr, "new: %02d:%02d:%02d:%02d\n", hour, minute, second, frame); */
264 /* Test 32 bit overflow */
267 if(ftell(out
) > 0x7f000000)
271 sprintf(newpath
, "%s%03d", outpath
, out_counter
);
272 if(!(out
= fopen(newpath
, "wb")))
274 fprintf(stderr
, "Couldn't open %s for writing.\n", newpath
);
280 * fprintf(stderr, "mpeg3cat 5 %02x %02x %02x %02x\n",
281 * (buffer + offset)[0],
282 * (buffer + offset)[1],
283 * (buffer + offset)[2],
284 * (buffer + offset)[3]);
287 /* Write the frame */
288 result
= !fwrite(buffer
+ offset
, output_size
- offset
, 1, out
);
291 perror("fwrite video chunk");
297 /* Output program stream */
298 if(in
->is_program_stream
)
300 mpeg3_demuxer_t
*demuxer
= in
->vtrack
[0]->demuxer
;
303 /* Append program stream with no changes */
304 demuxer
->read_all
= 1;
305 mpeg3demux_seek_byte(demuxer
, 0);
306 // mpeg3demux_seek_byte(demuxer, 83886080);
311 result
= mpeg3_seek_phys(demuxer
);
316 demuxer
->data_size
= 0;
317 demuxer
->video_size
= 0;
318 demuxer
->audio_size
= 0;
319 result
= mpeg3demux_read_program(demuxer
);
321 fprintf(stderr
, "Hit end of data in %s\n", inpath
);
325 // Read again and decrypt it
326 unsigned char *raw_data
= malloc(0x10000);
330 mpeg3_title_t
*title
= demuxer
->titles
[demuxer
->current_title
];
331 int64_t temp_offset
= mpeg3io_tell(title
->fs
);
332 int64_t decryption_offset
= demuxer
->last_packet_decryption
- demuxer
->last_packet_start
;
333 raw_size
= demuxer
->last_packet_end
- demuxer
->last_packet_start
;
335 mpeg3io_seek(title
->fs
, demuxer
->last_packet_start
);
336 mpeg3io_read_data(raw_data
, raw_size
, title
->fs
);
337 mpeg3io_seek(title
->fs
, temp_offset
);
340 if(decryption_offset
> 0 &&
341 decryption_offset
< raw_size
&&
342 raw_data
[decryption_offset
] & 0x30)
344 if(mpeg3_decrypt_packet(title
->fs
->css
,
348 fprintf(stderr
, "get_ps_pes_packet: Decryption not available\n");
351 raw_data
[decryption_offset
] &= 0xcf;
358 result
= !fwrite(raw_data
,
362 total_written
+= raw_size
;
363 if(result
) fprintf(stderr
, "%s\n", strerror(errno
));
370 /* No transport stream support, yet */
372 fprintf(stderr
, "Unsupported stream type.\n");
380 current_output_file
++;
383 /* Terminate output */
384 if(current_output_file
> 0 && do_video
)
386 /*fprintf(stderr, "\n"); */
387 /* Write new end of sequence */
388 buffer
[0] = MPEG3_SEQUENCE_END_CODE
>> 24;
389 buffer
[1] = (MPEG3_SEQUENCE_END_CODE
>> 16) & 0xff;
390 buffer
[2] = (MPEG3_SEQUENCE_END_CODE
>> 8) & 0xff;
391 buffer
[3] = MPEG3_SEQUENCE_END_CODE
& 0xff;
392 result
= !fwrite(buffer
, 4, 1, out
);
394 if(outpath
[0]) fclose(out
);