version update
[goodguy/cinelerra.git] / cinelerra-5.1 / mplexlo / mplex.c
1 #include <stdio.h>
2 #include <stdlib.h>
3
4
5 #include "libzmpeg3.h"
6
7 #define PACKET_SIZE 2048
8
9 class multiplexer_t {
10 public:
11         int derivative;
12         unsigned char packet_buffer[PACKET_SIZE];
13         FILE *out_file;
14 };
15
16 class track_t {
17 public:
18         void *operator new(size_t n) {
19                 void *t = (void*) new char[n];
20                 memset(t,0,n);
21                 return t;
22         }
23         void operator delete(void *t,size_t n) {
24                 delete[](char*)t;
25         }
26         long bytes_decoded;
27         long frames_decoded;
28         long samples_decoded;
29         mpeg3_t *file;
30         FILE *raw_file;
31         int stream_number;
32         int end_of_data;
33 };
34
35 int write_pack_header(unsigned char *ptr, 
36                 multiplexer_t *mplex, 
37                 float seconds,
38                 int stream_id,
39                 int ac3)
40 {
41         int packet_length;
42 // PACK START CODE
43         *ptr++ = 0x00;
44         *ptr++ = 0x00;
45         *ptr++ = 0x01;
46         *ptr++ = 0xba;
47
48         if(mplex->derivative == 1)
49         {
50                 unsigned long timestamp = (unsigned long)(seconds * 90000);
51                 *ptr = 0x20;
52                 *ptr++ |= ((timestamp & 0xc0000000) >> 29) | 1;
53                 *ptr++ =  (timestamp & 0x3fc00000) >> 22;
54                 *ptr++ =  ((timestamp & 0x003f8000) >> 14) | 1;
55                 *ptr++ =  (timestamp & 0x00007f80) >> 7;
56                 *ptr++ =  ((timestamp & 0x0000007f) << 1) | 1;
57
58                 *ptr++ = 0;
59                 *ptr++ = 0;
60                 *ptr++ = 0;
61         }
62         else
63         if(mplex->derivative == 2)
64         {
65                 *ptr = 0x40;
66         }
67
68         *ptr++ = 0x00;
69         *ptr++ = 0x00;
70         *ptr++ = 0x01;
71         if(ac3) 
72                 *ptr++ = 0xbd;
73         else
74                 *ptr++ = stream_id;
75
76 // Packet length
77         packet_length = PACKET_SIZE - (ptr - mplex->packet_buffer) - 2;
78         *ptr++ = (packet_length & 0xff00) >> 8;
79         *ptr++ = packet_length & 0xff;
80
81 // Pts/dts flags
82         *ptr++ = 0x0f;
83
84 // AC3 stream_id
85         if(ac3)
86         {
87                 *ptr++ = stream_id;
88                 *ptr++ = 0x00;
89                 *ptr++ = 0x00;
90                 *ptr++ = 0x00;
91         }
92
93         return PACKET_SIZE - (ptr - mplex->packet_buffer);
94 }
95
96 int write_packet(track_t *track, 
97                 float start_time, 
98                 float end_time, 
99                 multiplexer_t *mplex,
100                 int stream_id,
101                 int ac3)
102 {
103         int result = 0;
104         
105         long bytes_needed = track->bytes_decoded - ftell(track->raw_file);
106         long current_byte = 0;
107
108         while(current_byte < bytes_needed)
109         {
110 // Write packet header
111                 float current_time = start_time + (float)current_byte / bytes_needed * (end_time - start_time);
112                 int packet_bytes = write_pack_header(mplex->packet_buffer, 
113                         mplex, 
114                         current_time,
115                         stream_id,
116                         ac3);
117                 unsigned char *ptr = mplex->packet_buffer + PACKET_SIZE - packet_bytes;
118                 /*int bytes_read =*/ fread(ptr, 1, packet_bytes, track->raw_file);
119
120                 result = !fwrite(mplex->packet_buffer, PACKET_SIZE, 1, mplex->out_file);
121                 current_byte += packet_bytes;
122         }
123         return result;
124 }
125
126 int main(int argc, char *argv[])
127 {
128         int streams = 0;
129         int stream = 0;
130         int result = 0;
131         track_t *atracks[streams + 1];
132         track_t *vtracks[streams + 1];
133         int total_atracks = 0;
134         int total_vtracks = 0;
135         float frame_rate = 30000.0 / 1001.0;
136         float sample_rate = 48000;
137         long frames_decoded = 0;
138         float *audio_temp = new float[1];
139         long audio_temp_allocated = 0;
140         float current_time = 0, previous_time = 0;
141         int video_completed = 0;
142         int audio_completed = 0;
143         int i;
144         int ac3 = 0;
145         multiplexer_t mplex;
146         char **path;
147         char *output_path = 0;
148         int old_percentage = 0;
149         
150         path = new char*[argc];
151         mplex.derivative = 1;
152         mplex.out_file = 0;
153
154         if(argc < 4)
155         {
156                 printf("Tiny MPLEX by Heroine Virtual Ltd.\n");
157                 printf("Usage: mplex [-a] <stream 1> <stream2> ... <output>\n");
158                 printf("        -a use ac3 packet headers\n");
159                 exit(1);
160         }
161
162         for(i = 1; i < argc; i++)
163         {
164                 if(!strcmp(argv[i], "-a"))
165                 {
166                         ac3 = 1;
167                 }
168                 else
169                 if(i == argc - 1)
170                 {
171                         output_path = argv[i];
172                 }
173                 else
174                 {
175                         path[stream] = new char[strlen(argv[i])+1];
176                         strcpy(path[stream], argv[i]);
177                         streams++;
178                         stream++;
179                 }
180         }
181
182 // Open files
183         for(stream = 0; stream < streams; stream++)
184         {
185                 int is_audio, is_video;
186                 int error_return;
187                 mpeg3_t *file = mpeg3_open(path[stream], &error_return);
188
189                 if(!file)
190                 {
191                         printf("Couldn't open %s\n", path[stream]);
192                         result = 1;
193                 }
194                 else
195                 {
196                         is_audio = mpeg3_has_audio(file);
197                         is_video = mpeg3_has_video(file);
198                         mpeg3_set_cpus(file, 2);
199
200                         if(is_audio && is_video)
201                         {
202                                 printf("%s: Can't multiplex a system stream.\n", path[stream]);
203                                 result = 1;
204                         }
205                         else
206                         if(is_audio)
207                         {
208                                 atracks[total_atracks] = new track_t();
209                                 atracks[total_atracks]->file = file;
210                                 sample_rate = mpeg3_sample_rate(file, 0);
211                                 atracks[total_atracks]->raw_file = fopen(path[stream], "rb");
212                                 atracks[total_atracks]->stream_number = total_atracks;
213                                 total_atracks++;
214                         }
215                         else
216                         if(is_video)
217                         {
218                                 vtracks[total_vtracks] = new track_t();
219                                 vtracks[total_vtracks]->file = file;
220                                 frame_rate = mpeg3_frame_rate(file, 0);
221                                 vtracks[total_vtracks]->raw_file = fopen(path[stream], "rb");
222                                 vtracks[total_vtracks]->stream_number = total_vtracks;
223 // Get the first frame
224                                 mpeg3_skip_video_frame(vtracks[total_vtracks]->file,0);
225                                 total_vtracks++;
226                         }
227                         else
228                         {
229                                 printf("%s: Has neither audio or video.\n", path[stream]);
230                                 result = 1;
231                         }
232                 }
233         }
234
235         if(!result)
236         {
237                 if(!total_vtracks)
238                 {
239                         printf("You must supply at least 1 video track.\n");
240                         result = 1;
241                 }
242         }
243
244 // Open output
245         if(!result)
246                 if(!(mplex.out_file = fopen(output_path, "wb")))
247                 {
248                         printf("Couldn't open output file\n");
249                         result = 1;
250                 }
251
252 // Write multiplexed stream
253         if(!result)
254         {
255                 while(!result && !(video_completed && audio_completed))
256                 {
257                         previous_time = current_time;
258 // Want the frame to come before the audio that goes with it.
259                         for(stream = 0; stream < total_vtracks && !result; stream++)
260                         {
261 // Decode a frame and write it
262                                 track_t *track = vtracks[stream];
263
264                                 if(!track->end_of_data)
265                                 {
266                                         int percentage;
267                                         mpeg3_skip_video_frame(track->file,0);
268                                         track->frames_decoded++;
269                                         track->bytes_decoded = mpeg3_video_tell_byte(track->file,0);
270                                         if(track->frames_decoded > frames_decoded)
271                                         {
272                                                 frames_decoded = track->frames_decoded;
273                                                 current_time = (float)frames_decoded / frame_rate;
274                                         }
275
276                                         result = write_packet(track, 
277                                                                         previous_time, 
278                                                                         current_time, 
279                                                                         &mplex,
280                                                                         0xe0 | track->stream_number,
281                                                                         0);
282                                     track->end_of_data = mpeg3_end_of_video(track->file, 0);
283                                         percentage = (int)(mpeg3_video_tell_byte(track->file,0) * 100 / 
284                                                 mpeg3_get_bytes(track->file));
285                                         if(percentage - old_percentage >= 1)
286                                         {
287                                                 printf("\t%d%% completed\r", percentage);
288                                                 old_percentage = percentage;
289                                         }
290                                         fflush(stdout);
291                                 }
292                         }
293
294 // Decode audio until the last frame is covered
295                         for(stream = 0; stream < total_atracks && !result; stream++)
296                         {
297                                 track_t *track = atracks[stream];
298 //printf("mplex decode audio 1\n");
299                                 if(!track->end_of_data &&
300                                         (track->samples_decoded < current_time * sample_rate ||
301                                                 video_completed))
302                                 {
303                                         if(!video_completed)
304                                         {
305                                                 long samples_needed = (long)(current_time * sample_rate) - track->samples_decoded;
306                                                 if(audio_temp_allocated < samples_needed)
307                                                 {
308                                                         delete [] audio_temp;
309                                                         audio_temp = new float[samples_needed];
310                                                         audio_temp_allocated = samples_needed;
311                                                 }
312
313                                                 mpeg3_read_audio(track->file,
314                                                         audio_temp,
315                                                         0,
316                                                         0,
317                                                         samples_needed,
318                                                         0);
319                                                 track->bytes_decoded = mpeg3_audio_tell_byte(track->file,0);
320                                                 if(!track->end_of_data) track->bytes_decoded -= 2048;
321                                                 track->samples_decoded += samples_needed;
322                                                 track->end_of_data = mpeg3_end_of_audio(track->file, 0);
323                                         }
324                                         else
325                                         {
326                                                 track->bytes_decoded = mpeg3_get_bytes(track->file);
327                                                 track->end_of_data = 1;
328                                         }
329
330 //printf("mplex decode audio 2\n");
331                                         result = write_packet(track, 
332                                                 previous_time, 
333                                                 current_time, 
334                                                 &mplex,
335                                                 ac3 ? track->stream_number : (0xc0 | track->stream_number),
336                                                 ac3);
337                                 }
338                         }
339
340                         for(stream = 0; stream < total_vtracks; stream++)
341                         {
342                                 if(vtracks[stream]->end_of_data) video_completed++;
343                         }
344                         if(video_completed < total_vtracks) video_completed = 0;
345
346                         for(stream = 0; stream < total_atracks; stream++)
347                         {
348                                 if(atracks[stream]->end_of_data) audio_completed++;
349                         }
350                         if(audio_completed < total_atracks) audio_completed = 0;
351                 }
352         }
353
354 // Close streams
355         for(stream = 0; stream < total_atracks; stream++)
356         {
357                 mpeg3_close(atracks[stream]->file);
358                 fclose(atracks[stream]->raw_file);
359                 delete atracks[stream];
360         }
361
362         for(stream = 0; stream < total_vtracks; stream++)
363         {
364                 mpeg3_close(vtracks[stream]->file);
365                 fclose(vtracks[stream]->raw_file);
366                 delete vtracks[stream];
367         }
368         
369         if(mplex.out_file) fclose(mplex.out_file);
370
371         return result;
372 }
373
374