diff --git a/Makefile b/Makefile index 5f0098b..d3e49b6 100644 --- a/Makefile +++ b/Makefile @@ -90,6 +90,7 @@ BINDIR = bin # All of our non-program source files SRCS = \ accessunit.c \ + ac3.c \ adts.c \ avs.c \ bitdata.c \ @@ -111,6 +112,7 @@ SRCS = \ OBJS = \ accessunit.o \ avs.o \ + ac3.o \ adts.o \ bitdata.o \ es.o \ @@ -149,6 +151,7 @@ PROG_OBJS = \ $(OBJDIR)/tsreport.o \ $(OBJDIR)/tsserve.o \ $(OBJDIR)/ts_packet_insert.o \ + $(OBJDIR)/m2ts2ts.o $(OBJDIR)/pcapreport.o #\ # $(OBJDIR)/test_ps.o @@ -183,6 +186,7 @@ PROGS = \ $(BINDIR)/tsplay \ $(BINDIR)/tsserve \ $(BINDIR)/ts_packet_insert \ + $(BINDIR)/m2ts2ts $(BINDIR)/pcapreport #\ # $(BINDIR)/test_ps @@ -266,6 +270,8 @@ $(BINDIR)/ts2ps: $(OBJDIR)/ts2ps.o $(LIB) $(BINDIR)/ts_packet_insert: $(OBJDIR)/ts_packet_insert.o $(LIB) $(CC) $< -o $(BINDIR)/ts_packet_insert $(LDFLAGS) $(LIBOPTS) +$(BINDIR)/m2ts2ts: $(OBJDIR)/m2ts2ts.o $(LIB) + $(CC) $< -o $(BINDIR)/m2ts2ts $(LDFLAGS) $(LIBOPTS) $(BINDIR)/pcapreport: $(OBJDIR)/pcapreport.o $(LIB) $(CC) $< -o $(BINDIR)/pcapreport $(LDFLAGS) $(LIBOPTS) @@ -295,7 +301,7 @@ H262_H = h262_fns.h h262_defns.h TSWRITE_H = tswrite_fns.h tswrite_defns.h REVERSE_H = reverse_fns.h reverse_defns.h FILTER_H = filter_fns.h filter_defns.h $(REVERSE_H) -AUDIO_H = adts_fns.h l2audio_fns.h audio_fns.h audio_defns.h adts_defns.h +AUDIO_H = adts_fns.h l2audio_fns.h ac3_fns.h audio_fns.h audio_defns.h adts_defns.h # Everyone depends upon the basic configuration file $(LIB)($(OBJS)) $(TEST_OBJS) $(PROG_OBJS): compat.h @@ -344,6 +350,8 @@ $(OBJDIR)/tsplay.o: tsplay.c $(TS_H) misc_fns.h $(PS_H) $(PES_H) version.h $(CC) -c $< -o $@ $(CFLAGS) $(OBJDIR)/tswrite.o: tswrite.c misc_fns.h version.h $(CC) -c $< -o $@ $(CFLAGS) +$(OBJDIR)/m2ts2ts.o: m2ts2ts.c $(TS_H) misc_fns.h version.h + $(CC) -c $< -o $@ $(CFLAGS) $(OBJDIR)/pcapreport.o: pcapreport.c pcap.h version.h misc_fns.h $(CC) -c $< -o $@ $(CFLAGS) diff --git a/Makefile.w32 b/Makefile.w32 index 4b505cc..f2bd439 100644 --- a/Makefile.w32 +++ b/Makefile.w32 @@ -74,6 +74,7 @@ PROGS = \ $(EXEDIR)\ts2es.exe \ $(EXEDIR)\es2ts.exe \ $(EXEDIR)\esreverse.exe \ + $(EXEDIR)\m2ts2ts.exe \ $(EXEDIR)\ps2ts.exe \ $(EXEDIR)\psreport.exe \ $(EXEDIR)\stream_type.exe \ @@ -85,6 +86,7 @@ PROGS = \ # Object files for the library LIB_OBJS = \ $(OBJDIR)\accessunit.obj \ + $(OBJDIR)\ac3.obj \ $(OBJDIR)\adts.obj \ $(OBJDIR)\avs.obj \ $(OBJDIR)\audio.obj \ @@ -111,6 +113,7 @@ PROG_OBJS = \ $(OBJDIR)/esmerge.obj \ $(OBJDIR)/esreport.obj \ $(OBJDIR)/esreverse.obj \ + $(OBJDIR)/m2ts2ts.obj \ $(OBJDIR)/ps2ts.obj \ $(OBJDIR)/psreport.obj \ $(OBJDIR)/stream_type.obj \ @@ -153,6 +156,9 @@ $(EXEDIR)\esreport.exe: $(OBJDIR)\esreport.obj $(LIBFILE) $(EXEDIR)\esreverse.exe: $(OBJDIR)\esreverse.obj $(LIBFILE) link /out:$@ $(LOPT) $** wsock32.lib +$(EXEDIR)\m2ts2ts.exe: $(OBJDIR)\m2ts2ts.obj $(LIBFILE) + link /out:$@ $(LOPT) $** wsock32.lib + $(EXEDIR)\stream_type.exe: $(OBJDIR)\stream_type.obj $(LIBFILE) link /out:$@ $(LOPT) $** wsock32.lib diff --git a/ac3.c b/ac3.c new file mode 100644 index 0000000..d33e9ff --- /dev/null +++ b/ac3.c @@ -0,0 +1,171 @@ +/* + * Support for ATSC Digital Audio Compression Standard, Revision B + * (AC3) audio streams. + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the MPEG TS, PS and ES tools. + * + * The Initial Developer of the Original Code is Amino Communications Ltd. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Kynesim Ltd, Cambridge UK + * + * ***** END LICENSE BLOCK ***** + */ + +#include +#include +#include +#include + +#include "compat.h" +#include "misc_fns.h" +#include "ac3_fns.h" + +static const unsigned int // Table 5.18, frame sizes +l_frmsizecod[19][3] = { + { 64, 69, 96 }, + { 80, 87, 120 }, + { 96, 104, 144 }, + { 112, 121, 168 }, + { 128, 139, 192 }, + { 160, 174, 240 }, + { 192, 208, 288 }, + { 224, 243, 336 }, + { 256, 278, 384 }, + { 320, 348, 480 }, + { 384, 417, 576 }, + { 448, 487, 672 }, + { 512, 557, 768 }, + { 640, 696, 960 }, + { 768, 835, 1152 }, + { 896, 975, 1344 }, + { 1024, 1114, 1536 }, + { 1152, 1253, 1728 }, + { 1280, 1393, 1920 } +}; + + +/* + * Read the next AC3 frame. + * + * Assumes that the input stream is synchronised - i.e., it does not + * try to cope if the next two bytes are not '0000 1011 0111 0111' + * + * - `file` is the file descriptor of the AC3 file to read from + * - `frame` is the AC3 frame that is read + * + * Returns 0 if all goes well, EOF if end-of-file is read, and 1 if something + * goes wrong. + */ +#define SYNCINFO_SIZE 5 + +int read_next_ac3_frame(int file, + audio_frame_p *frame) +{ + int i, err; + byte sync_info[SYNCINFO_SIZE]; + byte *data = NULL; + int fscod; + int frmsizecod; + int frame_length; + + offset_t posn = tell_file(file); + + err = read_bytes(file, SYNCINFO_SIZE, sync_info); + if (err == EOF) + return EOF; + else if (err) + { + fprintf(stderr, "### Error reading syncinfo from AC3 file\n"); + fprintf(stderr, " (in frame starting at " OFFSET_T_FORMAT ")\n", posn); + return 1; + } + + if (sync_info[0] != 0x0b || sync_info[1] != 0x77) + { + fprintf(stderr, "### AC3 frame does not start with 0x0b77" + " syncword - lost synchronisation?\n" + " Found 0x%02x%02x instead of 0x0b77\n", + (unsigned)sync_info[0], (unsigned)sync_info[1]); + fprintf(stderr, " (in frame starting at " OFFSET_T_FORMAT ")\n", posn); + return 1; + } + + fscod = sync_info[4] >> 6; + if (fscod == 3) + { + // Bad sample rate code + fprintf(stderr, "### Bad sample rate code in AC3 syncinfo\n"); + fprintf(stderr, " (in frame starting at " OFFSET_T_FORMAT ")\n", posn); + return 1; + } + + frmsizecod = sync_info[4] & 0x3f; + if (frmsizecod > 37) + { + fprintf(stderr, "### Bad frame size code %d in AC3 syncinfo\n", + frmsizecod); + fprintf(stderr, " (in frame starting at " OFFSET_T_FORMAT ")\n", posn); + return 1; + } + + frame_length = l_frmsizecod[frmsizecod >> 1][fscod]; + if (fscod == 1) + frame_length += frmsizecod & 1; + frame_length <<= 1; // Convert from 16-bit words to bytes + + data = malloc(frame_length); + if (data == NULL) + { + fprintf(stderr, "### Unable to extend data buffer for AC3 frame\n"); + return 1; + } + for (i = 0; i < SYNCINFO_SIZE; i++) + data[i] = sync_info[i]; + + err = read_bytes(file, frame_length - SYNCINFO_SIZE, + &data[SYNCINFO_SIZE]); + if (err) + { + if (err = EOF) + fprintf(stderr, "### Unexpected EOF reading rest of AC3 frame\n"); + else + fprintf(stderr, "### Error reading rest of AC3 frame\n"); + free(data); + return 1; + } + + err = build_audio_frame(frame); + if (err) + { + free(data); + return 1; + } + (*frame)->data = data; + (*frame)->data_len = frame_length; + + return 0; +} + + +// Local Variables: +// tab-width: 8 +// indent-tabs-mode: nil +// c-basic-offset: 2 +// End: +// vim: set tabstop=8 shiftwidth=2 expandtab: diff --git a/ac3_fns.h b/ac3_fns.h new file mode 100644 index 0000000..925f59d --- /dev/null +++ b/ac3_fns.h @@ -0,0 +1,59 @@ +/* + * Support for ATSC Digital Audio Compression Standard, Revision B + * (AC3) audio streams. + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the MPEG TS, PS and ES tools. + * + * The Initial Developer of the Original Code is Amino Communications Ltd. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Kynesim Ltd, Cambridge UK + * + * ***** END LICENSE BLOCK ***** + */ + +#ifndef _ac3_fns +#define _ac3_fns + +#include "audio_fns.h" + + +/* + * Read the next AC3 frame. + * + * Assumes that the input stream is synchronised - i.e., it does not + * try to cope if the next two bytes are not '0000 1011 0111 0111' + * + * - `file` is the file descriptor of the AC3 file to read from + * - `frame` is the AC3 frame that is read + * + * Returns 0 if all goes well, EOF if end-of-file is read, and 1 if something + * goes wrong. + */ +extern int read_next_ac3_frame(int file, + audio_frame_p *frame); + + +#endif // _ac3_fns + +// Local Variables: +// tab-width: 8 +// indent-tabs-mode: nil +// c-basic-offset: 2 +// End: +// vim: set tabstop=8 shiftwidth=2 expandtab: diff --git a/audio.c b/audio.c index ab8129a..6c6e54b 100644 --- a/audio.c +++ b/audio.c @@ -35,6 +35,7 @@ #include "audio_fns.h" #include "adts_fns.h" #include "l2audio_fns.h" +#include "ac3_fns.h" /* * Build a new generic audio frame datastructure @@ -106,6 +107,8 @@ extern int read_next_audio_frame(int file, return read_next_adts_frame(file,frame,0); case AUDIO_L2: return read_next_l2audio_frame(file,frame); + case AUDIO_AC3: + return read_next_ac3_frame(file, frame); default: fprintf(stderr,"### Unrecognised audio type %d - cannot get next audio frame\n", audio_type); diff --git a/audio_defns.h b/audio_defns.h index 57d2a50..e6f5eee 100644 --- a/audio_defns.h +++ b/audio_defns.h @@ -45,6 +45,7 @@ typedef struct audio_frame *audio_frame_p; #define AUDIO_UNKNOWN 0 // which is a reserved value #define AUDIO_ADTS ADTS_AUDIO_STREAM_TYPE #define AUDIO_L2 MPEG2_AUDIO_STREAM_TYPE +#define AUDIO_AC3 ATSC_DOLBY_AUDIO_STREAM_TYPE #define AUDIO_ADTS_MPEG2 0x100 #define AUDIO_ADTS_MPEG4 0x101 @@ -54,6 +55,7 @@ typedef struct audio_frame *audio_frame_p; (x)==AUDIO_ADTS_MPEG2?"ADTS-MPEG2": \ (x)==AUDIO_ADTS_MPEG4?"ADTS-MPEG4": \ (x)==AUDIO_L2 ?"MPEG2": \ + (x)==AUDIO_AC3 ?"ATSC-AC3": \ "???") diff --git a/esmerge.c b/esmerge.c index f57ab8a..45cacbe 100644 --- a/esmerge.c +++ b/esmerge.c @@ -55,6 +55,8 @@ #define ADTS_SAMPLES_PER_FRAME 1024 // For MPEG-1 audio layer 2, this is 1152 #define L2_SAMPLES_PER_FRAME 1152 +// For AC-3 this is 256 * 6 +#define AC3_SAMPLES_PER_FRAME (256 * 6) // ------------------------------------------------------------ #define TEST_PTS_DTS 0 @@ -186,6 +188,9 @@ static int merge_with_avs(avs_context_p video_context, case AUDIO_L2: prog_type[1] = MPEG2_AUDIO_STREAM_TYPE; break; + case AUDIO_AC3: + prog_type[1] = ATSC_DOLBY_AUDIO_STREAM_TYPE; + break; default: // what else can we do? prog_type[1] = ADTS_AUDIO_STREAM_TYPE; break; @@ -419,6 +424,9 @@ static int merge_with_h264(access_unit_context_p video_context, case AUDIO_L2: prog_type[1] = MPEG2_AUDIO_STREAM_TYPE; break; + case AUDIO_AC3: + prog_type[1] = ATSC_DOLBY_AUDIO_STREAM_TYPE; + break; default: // what else can we do? prog_type[1] = ADTS_AUDIO_STREAM_TYPE; break; @@ -610,6 +618,7 @@ static void print_usage() " -l2 The audio stream is MPEG layer 2 audio\n" " -mp2adts The audio stream is MPEG-2 style ADTS regardless of ID bit\n" " -mp4adts The audio stream is MPEG-4 style ADTS regardless of ID bit\n" + " -ac3 The audio stream is Dolby AC-3 in ATSC\n" "\n" " -patpmtfreq PAT and PMT will be inserted every video frames. \n" " by default, f = 0 and PAT/PMT are inserted only at \n" @@ -618,8 +627,8 @@ static void print_usage() "Limitations\n" "===========\n" "For the moment, the video input must be H.264 or AVS, and the audio input\n" - "ADTS or MPEG layer 2. Also, the audio is assumed to have a constant\n" - "number of samples per frame.\n" + "ADTS, AC-3 ATSC or MPEG layer 2. Also, the audio is assumed to have a\n" + "constant number of samples per frame.\n" ); } @@ -712,6 +721,10 @@ int main(int argc, char **argv) { audio_type = AUDIO_L2; } + else if (!strcmp("-ac3", argv[ii])) + { + audio_type = AUDIO_AC3; + } else if (!strcmp("-h264",argv[ii])) { video_type = VIDEO_H264; @@ -851,6 +864,9 @@ int main(int argc, char **argv) case AUDIO_L2: audio_samples_per_frame = L2_SAMPLES_PER_FRAME; break; + case AUDIO_AC3: + audio_samples_per_frame = AC3_SAMPLES_PER_FRAME; + break; default: // hmm - or we could give up... audio_samples_per_frame = ADTS_SAMPLES_PER_FRAME; break;