M2TS.pm 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. #------------------------------------------------------------------------------
  2. # File: M2TS.pm
  3. #
  4. # Description: Read M2TS (AVCHD) meta information
  5. #
  6. # Revisions: 2009/07/03 - P. Harvey Created
  7. #
  8. # References: 1) http://neuron2.net/library/mpeg2/iso13818-1.pdf
  9. # 2) http://www.blu-raydisc.com/Assets/Downloadablefile/BD-RE_Part3_V2.1_WhitePaper_080406-15271.pdf
  10. # 3) http://www.videohelp.com/forum/archive/reading-avchd-playlist-files-bdmv-playlist-mpl-t358888.html
  11. # 4) http://en.wikipedia.org/wiki/MPEG_transport_stream
  12. # 5) http://www.dunod.com/documents/9782100493463/49346_DVB.pdf
  13. # 6) http://trac.handbrake.fr/browser/trunk/libhb/stream.c
  14. # 7) http://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=04560141
  15. # 8) http://www.w6rz.net/xport.zip
  16. #
  17. # Notes: Variable names containing underlines are the same as in ref 1.
  18. #
  19. # Glossary: PES = Packetized Elementary Stream
  20. # PAT = Program Association Table
  21. # PMT = Program Map Table
  22. # PCR = Program Clock Reference
  23. # PID = Packet Identifier
  24. #
  25. # To Do: - parse PCR to obtain average bitrates?
  26. #------------------------------------------------------------------------------
  27. package Image::ExifTool::M2TS;
  28. use strict;
  29. use vars qw($VERSION);
  30. use Image::ExifTool qw(:DataAccess :Utils);
  31. $VERSION = '1.11';
  32. # program map table "stream_type" lookup (ref 6/1)
  33. my %streamType = (
  34. 0x00 => 'Reserved',
  35. 0x01 => 'MPEG-1 Video',
  36. 0x02 => 'MPEG-2 Video',
  37. 0x03 => 'MPEG-1 Audio',
  38. 0x04 => 'MPEG-2 Audio',
  39. 0x05 => 'ISO 13818-1 private sections',
  40. 0x06 => 'ISO 13818-1 PES private data',
  41. 0x07 => 'ISO 13522 MHEG',
  42. 0x08 => 'ISO 13818-1 DSM-CC',
  43. 0x09 => 'ISO 13818-1 auxiliary',
  44. 0x0A => 'ISO 13818-6 multi-protocol encap',
  45. 0x0B => 'ISO 13818-6 DSM-CC U-N msgs',
  46. 0x0C => 'ISO 13818-6 stream descriptors',
  47. 0x0D => 'ISO 13818-6 sections',
  48. 0x0E => 'ISO 13818-1 auxiliary',
  49. 0x0F => 'MPEG-2 AAC Audio',
  50. 0x10 => 'MPEG-4 Video',
  51. 0x11 => 'MPEG-4 LATM AAC Audio',
  52. 0x12 => 'MPEG-4 generic',
  53. 0x13 => 'ISO 14496-1 SL-packetized',
  54. 0x14 => 'ISO 13818-6 Synchronized Download Protocol',
  55. # 0x15-0x7F => 'ISO 13818-1 Reserved',
  56. 0x1b => 'H.264 Video',
  57. 0x80 => 'DigiCipher II Video',
  58. 0x81 => 'A52/AC-3 Audio',
  59. 0x82 => 'HDMV DTS Audio',
  60. 0x83 => 'LPCM Audio',
  61. 0x84 => 'SDDS Audio',
  62. 0x85 => 'ATSC Program ID',
  63. 0x86 => 'DTS-HD Audio',
  64. 0x87 => 'E-AC-3 Audio',
  65. 0x8a => 'DTS Audio',
  66. 0x91 => 'A52b/AC-3 Audio',
  67. 0x92 => 'DVD_SPU vls Subtitle',
  68. 0x94 => 'SDDS Audio',
  69. 0xa0 => 'MSCODEC Video',
  70. 0xea => 'Private ES (VC-1)',
  71. # 0x80-0xFF => 'User Private',
  72. );
  73. # "table_id" values (ref 5)
  74. my %tableID = (
  75. 0x00 => 'Program Association',
  76. 0x01 => 'Conditional Access',
  77. 0x02 => 'Program Map',
  78. 0x03 => 'Transport Stream Description',
  79. 0x40 => 'Actual Network Information',
  80. 0x41 => 'Other Network Information',
  81. 0x42 => 'Actual Service Description',
  82. 0x46 => 'Other Service Description',
  83. 0x4a => 'Bouquet Association',
  84. 0x4e => 'Actual Event Information - Present/Following',
  85. 0x4f => 'Other Event Information - Present/Following',
  86. 0x50 => 'Actual Event Information - Schedule', #(also 0x51-0x5f)
  87. 0x60 => 'Other Event Information - Schedule', # (also 0x61-0x6f)
  88. 0x70 => 'Time/Date',
  89. 0x71 => 'Running Status',
  90. 0x72 => 'Stuffing',
  91. 0x73 => 'Time Offset',
  92. 0x7e => 'Discontinuity Information',
  93. 0x7f => 'Selection Information',
  94. # 0x80-0xfe => 'User Defined',
  95. );
  96. # PES stream ID's for which a syntax field does not exist
  97. my %noSyntax = (
  98. 0xbc => 1, # program_stream_map
  99. 0xbe => 1, # padding_stream
  100. 0xbf => 1, # private_stream_2
  101. 0xf0 => 1, # ECM_stream
  102. 0xf1 => 1, # EMM_stream
  103. 0xf2 => 1, # DSMCC_stream
  104. 0xf8 => 1, # ITU-T Rec. H.222.1 type E stream
  105. 0xff => 1, # program_stream_directory
  106. );
  107. # information extracted from the MPEG-2 transport stream
  108. %Image::ExifTool::M2TS::Main = (
  109. GROUPS => { 2 => 'Video' },
  110. VARS => { NO_ID => 1 },
  111. NOTES => q{
  112. The MPEG-2 transport stream is used as a container for many different
  113. audio/video formats (including AVCHD). This table lists information
  114. extracted from M2TS files.
  115. },
  116. VideoStreamType => {
  117. PrintHex => 1,
  118. PrintConv => \%streamType,
  119. SeparateTable => 'StreamType',
  120. },
  121. AudioStreamType => {
  122. PrintHex => 1,
  123. PrintConv => \%streamType,
  124. SeparateTable => 'StreamType',
  125. },
  126. Duration => {
  127. Notes => q{
  128. the -fast option may be used to avoid scanning to the end of file to
  129. calculate the Duration
  130. },
  131. ValueConv => '$val / 27000000', # (clock is 27MHz)
  132. PrintConv => 'ConvertDuration($val)',
  133. },
  134. # the following tags are for documentation purposes only
  135. _AC3 => { SubDirectory => { TagTable => 'Image::ExifTool::M2TS::AC3' } },
  136. _H264 => { SubDirectory => { TagTable => 'Image::ExifTool::H264::Main' } },
  137. );
  138. # information extracted from AC-3 audio streams
  139. %Image::ExifTool::M2TS::AC3 = (
  140. GROUPS => { 1 => 'AC3', 2 => 'Audio' },
  141. VARS => { NO_ID => 1 },
  142. NOTES => 'Tags extracted from AC-3 audio streams.',
  143. AudioSampleRate => {
  144. PrintConv => {
  145. 0 => '48000',
  146. 1 => '44100',
  147. 2 => '32000',
  148. },
  149. },
  150. AudioBitrate => {
  151. PrintConvColumns => 2,
  152. ValueConv => {
  153. 0 => 32000,
  154. 1 => 40000,
  155. 2 => 48000,
  156. 3 => 56000,
  157. 4 => 64000,
  158. 5 => 80000,
  159. 6 => 96000,
  160. 7 => 112000,
  161. 8 => 128000,
  162. 9 => 160000,
  163. 10 => 192000,
  164. 11 => 224000,
  165. 12 => 256000,
  166. 13 => 320000,
  167. 14 => 384000,
  168. 15 => 448000,
  169. 16 => 512000,
  170. 17 => 576000,
  171. 18 => 640000,
  172. 32 => '32000 max',
  173. 33 => '40000 max',
  174. 34 => '48000 max',
  175. 35 => '56000 max',
  176. 36 => '64000 max',
  177. 37 => '80000 max',
  178. 38 => '96000 max',
  179. 39 => '112000 max',
  180. 40 => '128000 max',
  181. 41 => '160000 max',
  182. 42 => '192000 max',
  183. 43 => '224000 max',
  184. 44 => '256000 max',
  185. 45 => '320000 max',
  186. 46 => '384000 max',
  187. 47 => '448000 max',
  188. 48 => '512000 max',
  189. 49 => '576000 max',
  190. 50 => '640000 max',
  191. },
  192. PrintConv => 'ConvertBitrate($val)',
  193. },
  194. SurroundMode => {
  195. PrintConv => {
  196. 0 => 'Not indicated',
  197. 1 => 'Not Dolby surround',
  198. 2 => 'Dolby surround',
  199. },
  200. },
  201. AudioChannels => {
  202. PrintConvColumns => 2,
  203. PrintConv => {
  204. 0 => '1 + 1',
  205. 1 => 1,
  206. 2 => 2,
  207. 3 => 3,
  208. 4 => '2/1',
  209. 5 => '3/1',
  210. 6 => '2/2',
  211. 7 => '3/2',
  212. 8 => 1,
  213. 9 => '2 max',
  214. 10 => '3 max',
  215. 11 => '4 max',
  216. 12 => '5 max',
  217. 13 => '6 max',
  218. },
  219. },
  220. );
  221. #------------------------------------------------------------------------------
  222. # Extract information from AC-3 audio stream
  223. # Inputs: 0) ExifTool ref, 1) data ref
  224. # Reference: http://www.atsc.org/standards/a_52b.pdf
  225. sub ParseAC3Audio($$)
  226. {
  227. my ($et, $dataPt) = @_;
  228. if ($$dataPt =~ /\x0b\x77..(.)/sg) {
  229. my $sampleRate = ord($1) >> 6;
  230. my $tagTablePtr = GetTagTable('Image::ExifTool::M2TS::AC3');
  231. $et->HandleTag($tagTablePtr, AudioSampleRate => $sampleRate);
  232. }
  233. }
  234. #------------------------------------------------------------------------------
  235. # Extract information from AC-3 stream descriptor
  236. # Inputs: 0) ExifTool ref, 1) data ref
  237. # Reference: http://www.atsc.org/standards/a_52b.pdf
  238. # Note: This information is duplicated in the Audio stream, but it
  239. # is somewhat easier to extract it from the descriptor instead
  240. sub ParseAC3Descriptor($$)
  241. {
  242. my ($et, $dataPt) = @_;
  243. return if length $$dataPt < 3;
  244. my @v = unpack('C3', $$dataPt);
  245. my $tagTablePtr = GetTagTable('Image::ExifTool::M2TS::AC3');
  246. # $et->HandleTag($tagTablePtr, 'AudioSampleRate', $v[0] >> 5);
  247. $et->HandleTag($tagTablePtr, 'AudioBitrate', $v[1] >> 2);
  248. $et->HandleTag($tagTablePtr, 'SurroundMode', $v[1] & 0x03);
  249. $et->HandleTag($tagTablePtr, 'AudioChannels', ($v[2] >> 1) & 0x0f);
  250. # don't (yet) decode any more (language codes, etc)
  251. }
  252. #------------------------------------------------------------------------------
  253. # Parse PID stream data
  254. # Inputs: 0) Exiftool ref, 1) PID number, 2) PID type, 3) PID name, 4) data ref
  255. # Returns: 0=stream parsed OK,
  256. # 1=stream parsed but we want to parse more of these,
  257. # -1=can't parse yet because we don't know the type
  258. sub ParsePID($$$$$)
  259. {
  260. my ($et, $pid, $type, $pidName, $dataPt) = @_;
  261. # can't parse until we know the type (Program Map Table may be later in the stream)
  262. return -1 unless defined $type;
  263. my $verbose = $et->Options('Verbose');
  264. if ($verbose > 1) {
  265. my $out = $et->Options('TextOut');
  266. printf $out "Parsing stream 0x%.4x (%s)\n", $pid, $pidName;
  267. my %parms = ( Out => $out );
  268. $parms{MaxLen} = 96 if $verbose < 4;
  269. HexDump($dataPt, undef, %parms) if $verbose > 2;
  270. }
  271. my $more = 0;
  272. if ($type == 0x01 or $type == 0x02) {
  273. # MPEG-1/MPEG-2 Video
  274. require Image::ExifTool::MPEG;
  275. Image::ExifTool::MPEG::ParseMPEGAudioVideo($et, $dataPt);
  276. } elsif ($type == 0x03 or $type == 0x04) {
  277. # MPEG-1/MPEG-2 Audio
  278. require Image::ExifTool::MPEG;
  279. Image::ExifTool::MPEG::ParseMPEGAudio($et, $dataPt);
  280. } elsif ($type == 0x1b) {
  281. # H.264 Video
  282. require Image::ExifTool::H264;
  283. $more = Image::ExifTool::H264::ParseH264Video($et, $dataPt);
  284. # force parsing additional H264 frames with ExtractEmbedded option
  285. $more = 1 if $et->Options('ExtractEmbedded');
  286. } elsif ($type == 0x81 or $type == 0x87 or $type == 0x91) {
  287. # AC-3 audio
  288. ParseAC3Audio($et, $dataPt);
  289. }
  290. return $more;
  291. }
  292. #------------------------------------------------------------------------------
  293. # Extract information from a M2TS file
  294. # Inputs: 0) ExifTool object reference, 1) DirInfo reference
  295. # Returns: 1 on success, 0 if this wasn't a valid M2TS file
  296. sub ProcessM2TS($$)
  297. {
  298. my ($et, $dirInfo) = @_;
  299. my $raf = $$dirInfo{RAF};
  300. my ($buff, $pLen, $upkPrefix, $j, $fileType, $eof);
  301. my (%pmt, %pidType, %data, %sectLen);
  302. my ($startTime, $endTime, $backScan, $maxBack);
  303. my $verbose = $et->Options('Verbose');
  304. my $out = $et->Options('TextOut');
  305. # read first packet
  306. return 0 unless $raf->Read($buff, 8) == 8;
  307. # test for magic number (sync byte is the only thing we can safely check)
  308. return 0 unless $buff =~ /^(....)?\x47/s;
  309. unless ($1) {
  310. $pLen = 188; # no timecode
  311. $fileType = 'M2T'; # (just as a way to tell there is no timecode)
  312. $upkPrefix = 'N';
  313. } else {
  314. $pLen = 192; # 188-byte transport packet + leading 4-byte timecode (ref 4)
  315. $upkPrefix = 'x4N';
  316. }
  317. $et->SetFileType($fileType);
  318. SetByteOrder('MM');
  319. $raf->Seek(0,0); # rewind to start
  320. my $tagTablePtr = GetTagTable('Image::ExifTool::M2TS::Main');
  321. # PID lookup strings (will add to this with entries from program map table)
  322. my %pidName = (
  323. 0 => 'Program Association Table',
  324. 1 => 'Conditional Access Table',
  325. 2 => 'Transport Stream Description Table',
  326. 0x1fff => 'Null Packet',
  327. );
  328. my %didPID = ( 1 => 0, 2 => 0, 0x1fff => 0 );
  329. my %needPID = ( 0 => 1 ); # lookup for stream PID's that we still need to parse
  330. my $prePos = $pLen - 188; # byte position of packet prefix
  331. my $readSize = 64 * $pLen; # read 64 packets at once
  332. my $pEnd = 0;
  333. my $i = 0;
  334. $buff = '';
  335. # parse packets from MPEG-2 Transport Stream
  336. for (;;) {
  337. unless (%needPID) {
  338. last unless defined $startTime;
  339. # seek backwards to find last PCR
  340. if (defined $backScan) {
  341. last if defined $endTime;
  342. $backScan -= $pLen;
  343. last if $backScan < $maxBack;
  344. } else {
  345. undef $endTime;
  346. last if $et->Options('FastScan');
  347. $verbose and print "[Starting backscan for last PCR]\n";
  348. # calculate position of last complete packet
  349. my $fwdPos = $raf->Tell();
  350. $raf->Seek(0, 2) or last;
  351. my $fsize = $raf->Tell();
  352. my $nPack = int($fsize / $pLen);
  353. $backScan = ($nPack - 1) * $pLen - $fsize;
  354. # set limit on how far back we will go
  355. $maxBack = $fwdPos - $fsize;
  356. $maxBack = -256000 if $maxBack < -256000;
  357. }
  358. $raf->Seek($backScan, 2) or last;
  359. }
  360. my $pos = $pEnd;
  361. # read more if necessary
  362. if ($pos + $pLen > length $buff) {
  363. $raf->Read($buff, $readSize) >= $pLen or $eof = 1, last;
  364. $pos = $pEnd = 0;
  365. }
  366. $pEnd += $pLen;
  367. # decode the packet prefix
  368. $pos += $prePos;
  369. my $prefix = unpack("x${pos}N", $buff); # (use unpack instead of Get32u for speed)
  370. # validate sync byte
  371. unless (($prefix & 0xff000000) == 0x47000000) {
  372. $et->Warn('Synchronization error') unless defined $backScan;
  373. last;
  374. }
  375. # my $transport_error_indicator = $prefix & 0x00800000;
  376. my $payload_unit_start_indicator = $prefix & 0x00400000;
  377. # my $transport_priority = $prefix & 0x00200000;
  378. my $pid =($prefix & 0x001fff00) >> 8; # packet ID
  379. # my $transport_scrambling_control = $prefix & 0x000000c0;
  380. my $adaptation_field_exists = $prefix & 0x00000020;
  381. my $payload_data_exists = $prefix & 0x00000010;
  382. # my $continuity_counter = $prefix & 0x0000000f;
  383. if ($verbose > 1) {
  384. print $out "Transport packet $i:\n";
  385. ++$i;
  386. HexDump(\$buff, $pLen, Addr => $i * $pLen, Out => $out,
  387. Start => $pos - $prePos) if $verbose > 2;
  388. my $str = $pidName{$pid} ? " ($pidName{$pid})" : '';
  389. printf $out " Timecode: 0x%.4x\n", Get32u(\$buff, 0) if $pLen == 192;
  390. printf $out " Packet ID: 0x%.4x$str\n", $pid;
  391. printf $out " Start Flag: %s\n", $payload_unit_start_indicator ? 'Yes' : 'No';
  392. }
  393. $pos += 4;
  394. # handle adaptation field
  395. if ($adaptation_field_exists) {
  396. my $len = Get8u(\$buff, $pos++);
  397. $pos + $len > $pEnd and $et->Warn('Invalid adaptation field length'), last;
  398. # read PCR value for calculation of Duration
  399. if ($len > 6) {
  400. my $flags = Get8u(\$buff, $pos);
  401. if ($flags & 0x10) { # PCR_flag
  402. # combine 33-bit program_clock_reference_base and 9-bit extension
  403. my $pcrBase = Get32u(\$buff, $pos + 1);
  404. my $pcrExt = Get16u(\$buff, $pos + 5);
  405. # ignore separate programs (PID's) and store just the
  406. # first and last timestamps found in the file (is this OK?)
  407. $endTime = 300 * (2 * $pcrBase + ($pcrExt >> 15)) + ($pcrExt & 0x01ff);
  408. $startTime = $endTime unless defined $startTime;
  409. }
  410. }
  411. $pos += $len;
  412. }
  413. # all done with this packet unless it carries a payload
  414. # or if we are just looking for the last timestamp
  415. next unless $payload_data_exists and not defined $backScan;
  416. # decode payload data
  417. if ($pid == 0 or # program association table
  418. defined $pmt{$pid}) # program map table(s)
  419. {
  420. # must interpret pointer field if payload_unit_start_indicator is set
  421. my $buf2;
  422. if ($payload_unit_start_indicator) {
  423. # skip to start of section
  424. my $pointer_field = Get8u(\$buff, $pos);
  425. $pos += 1 + $pointer_field;
  426. $pos >= $pEnd and $et->Warn('Bad pointer field'), last;
  427. $buf2 = substr($buff, $pEnd-$pLen, $pLen);
  428. $pos -= $pEnd - $pLen;
  429. } else {
  430. # not the start of a section
  431. next unless $sectLen{$pid};
  432. my $more = $sectLen{$pid} - length($data{$pid});
  433. my $size = $pLen - $pos;
  434. $size = $more if $size > $more;
  435. $data{$pid} .= substr($buff, $pos, $size);
  436. next unless $size == $more;
  437. # we have the complete section now, so put into $buf2 for parsing
  438. $buf2 = $data{$pid};
  439. $pos = 0;
  440. delete $data{$pid};
  441. delete $sectLen{$pid};
  442. }
  443. my $slen = length($buf2); # section length
  444. $pos + 8 > $slen and $et->Warn("Truncated payload"), last;
  445. # validate table ID
  446. my $table_id = Get8u(\$buf2, $pos);
  447. my $name = ($tableID{$table_id} || sprintf('Unknown (0x%x)',$table_id)) . ' Table';
  448. my $expectedID = $pid ? 0x02 : 0x00;
  449. unless ($table_id == $expectedID) {
  450. $verbose > 1 and print $out " (skipping $name)\n";
  451. delete $needPID{$pid};
  452. $didPID{$pid} = 1;
  453. next;
  454. }
  455. # validate section syntax indicator for parsed tables (PAT, PMT)
  456. my $section_syntax_indicator = Get8u(\$buf2, $pos + 1) & 0xc0;
  457. $section_syntax_indicator == 0x80 or $et->Warn("Bad $name"), last;
  458. my $section_length = Get16u(\$buf2, $pos + 1) & 0x0fff;
  459. $section_length > 1021 and $et->Warn("Invalid $name length"), last;
  460. if ($slen < $section_length + 3) { # (3 bytes for table_id + section_length)
  461. # must wait until we have the full section
  462. $data{$pid} = substr($buf2, $pos);
  463. $sectLen{$pid} = $section_length + 3;
  464. next;
  465. }
  466. my $program_number = Get16u(\$buf2, $pos + 3);
  467. my $section_number = Get8u(\$buf2, $pos + 6);
  468. my $last_section_number = Get8u(\$buf2, $pos + 7);
  469. if ($verbose > 1) {
  470. print $out " $name length: $section_length\n";
  471. print $out " Program No: $program_number\n" if $pid;
  472. printf $out " Stream ID: 0x%x\n", $program_number if not $pid;
  473. print $out " Section No: $section_number\n";
  474. print $out " Last Sect.: $last_section_number\n";
  475. }
  476. my $end = $pos + $section_length + 3 - 4; # (don't read 4-byte CRC)
  477. $pos += 8;
  478. if ($pid == 0) {
  479. # decode PAT (Program Association Table)
  480. while ($pos <= $end - 4) {
  481. my $program_number = Get16u(\$buf2, $pos);
  482. my $program_map_PID = Get16u(\$buf2, $pos + 2) & 0x1fff;
  483. $pmt{$program_map_PID} = $program_number; # save our PMT PID's
  484. my $str = "Program $program_number Map";
  485. $pidName{$program_map_PID} = $str;
  486. $needPID{$program_map_PID} = 1 unless $didPID{$program_map_PID};
  487. $verbose and printf $out " PID(0x%.4x) --> $str\n", $program_map_PID;
  488. $pos += 4;
  489. }
  490. } else {
  491. # decode PMT (Program Map Table)
  492. $pos + 4 > $slen and $et->Warn('Truncated PMT'), last;
  493. my $pcr_pid = Get16u(\$buf2, $pos) & 0x1fff;
  494. my $program_info_length = Get16u(\$buf2, $pos + 2) & 0x0fff;
  495. my $str = "Program $program_number Clock Reference";
  496. $pidName{$pcr_pid} = $str;
  497. $verbose and printf $out " PID(0x%.4x) --> $str\n", $pcr_pid;
  498. $pos += 4;
  499. $pos + $program_info_length > $slen and $et->Warn('Truncated program info'), last;
  500. # dump program information descriptors if verbose
  501. if ($verbose > 1) { for ($j=0; $j<$program_info_length-2; ) {
  502. my $descriptor_tag = Get8u(\$buf2, $pos + $j);
  503. my $descriptor_length = Get8u(\$buf2, $pos + $j + 1);
  504. $j += 2;
  505. last if $j + $descriptor_length > $program_info_length;
  506. my $desc = substr($buf2, $pos+$j, $descriptor_length);
  507. $j += $descriptor_length;
  508. $desc =~ s/([\x00-\x1f\x80-\xff])/sprintf("\\x%.2x",ord $1)/eg;
  509. printf $out " Program Descriptor: Type=0x%.2x \"$desc\"\n", $descriptor_tag;
  510. }}
  511. $pos += $program_info_length; # skip descriptors (for now)
  512. while ($pos <= $end - 5) {
  513. my $stream_type = Get8u(\$buf2, $pos);
  514. my $elementary_pid = Get16u(\$buf2, $pos + 1) & 0x1fff;
  515. my $es_info_length = Get16u(\$buf2, $pos + 3) & 0x0fff;
  516. my $str = $streamType{$stream_type};
  517. $str or $str = ($stream_type < 0x7f ? 'Reserved' : 'Private');
  518. $str = sprintf('%s (0x%.2x)', $str, $stream_type);
  519. $str = "Program $program_number $str";
  520. $verbose and printf $out " PID(0x%.4x) --> $str\n", $elementary_pid;
  521. if ($str =~ /(Audio|Video)/) {
  522. unless ($pidName{$elementary_pid}) {
  523. $et->HandleTag($tagTablePtr, $1 . 'StreamType', $stream_type)
  524. }
  525. # we want to parse all Audio and Video streams
  526. $needPID{$elementary_pid} = 1 unless $didPID{$elementary_pid};
  527. }
  528. # save PID type and name string
  529. $pidName{$elementary_pid} = $str;
  530. $pidType{$elementary_pid} = $stream_type;
  531. $pos += 5;
  532. $pos + $es_info_length > $slen and $et->Warn('Trunacted ES info'), $pos = $end, last;
  533. # parse elementary stream descriptors
  534. for ($j=0; $j<$es_info_length-2; ) {
  535. my $descriptor_tag = Get8u(\$buf2, $pos + $j);
  536. my $descriptor_length = Get8u(\$buf2, $pos + $j + 1);
  537. $j += 2;
  538. last if $j + $descriptor_length > $es_info_length;
  539. my $desc = substr($buf2, $pos+$j, $descriptor_length);
  540. $j += $descriptor_length;
  541. if ($verbose > 1) {
  542. my $dstr = $desc;
  543. $dstr =~ s/([\x00-\x1f\x80-\xff])/sprintf("\\x%.2x",ord $1)/eg;
  544. printf $out " ES Descriptor: Type=0x%.2x \"$dstr\"\n", $descriptor_tag;
  545. }
  546. # parse type-specific descriptor information (once)
  547. unless ($didPID{$pid}) {
  548. if ($descriptor_tag == 0x81) { # AC-3
  549. ParseAC3Descriptor($et, \$desc);
  550. }
  551. }
  552. }
  553. $pos += $es_info_length;
  554. }
  555. }
  556. # $pos = $end + 4; # skip CRC
  557. } elsif (not defined $didPID{$pid}) {
  558. # save data from the start of each elementary stream
  559. if ($payload_unit_start_indicator) {
  560. if (defined $data{$pid}) {
  561. # we must have a whole section, so parse now
  562. my $more = ParsePID($et, $pid, $pidType{$pid}, $pidName{$pid}, \$data{$pid});
  563. # start fresh even if we couldn't process this PID yet
  564. delete $data{$pid};
  565. unless ($more) {
  566. delete $needPID{$pid};
  567. $didPID{$pid} = 1;
  568. next;
  569. }
  570. # set flag indicating we found this PID but we still want more
  571. $needPID{$pid} = -1;
  572. }
  573. # check for a PES header
  574. next if $pos + 6 > $pEnd;
  575. my $start_code = Get32u(\$buff, $pos);
  576. next unless ($start_code & 0xffffff00) == 0x00000100;
  577. my $stream_id = $start_code & 0xff;
  578. if ($verbose > 1) {
  579. my $pes_packet_length = Get16u(\$buff, $pos + 4);
  580. printf $out " Stream ID: 0x%.2x\n", $stream_id;
  581. print $out " Packet Len: $pes_packet_length\n";
  582. }
  583. $pos += 6;
  584. unless ($noSyntax{$stream_id}) {
  585. next if $pos + 3 > $pEnd;
  586. # validate PES syntax
  587. my $syntax = Get8u(\$buff, $pos) & 0xc0;
  588. $syntax == 0x80 or $et->Warn('Bad PES syntax'), next;
  589. # skip PES header
  590. my $pes_header_data_length = Get8u(\$buff, $pos + 2);
  591. $pos += 3 + $pes_header_data_length;
  592. next if $pos >= $pEnd;
  593. }
  594. $data{$pid} = substr($buff, $pos, $pEnd-$pos);
  595. } else {
  596. next unless defined $data{$pid};
  597. # accumulate data for each elementary stream
  598. $data{$pid} .= substr($buff, $pos, $pEnd-$pos);
  599. }
  600. # save only the first 256 bytes of most streams, except for
  601. # unknown or H.264 streams where we save 1 kB
  602. my $saveLen = (not $pidType{$pid} or $pidType{$pid} == 0x1b) ? 1024 : 256;
  603. if (length($data{$pid}) >= $saveLen) {
  604. my $more = ParsePID($et, $pid, $pidType{$pid}, $pidName{$pid}, \$data{$pid});
  605. next if $more < 0; # wait for program map table (hopefully not too long)
  606. delete $data{$pid};
  607. $more and $needPID{$pid} = -1, next; # parse more of these
  608. delete $needPID{$pid};
  609. $didPID{$pid} = 1;
  610. }
  611. next;
  612. }
  613. if ($needPID{$pid}) {
  614. # we found and parsed a section with this PID, so
  615. # delete from the lookup of PID's we still need to parse
  616. delete $needPID{$pid};
  617. $didPID{$pid} = 1;
  618. }
  619. }
  620. # calculate Duration if available
  621. if (defined $startTime and defined $endTime and $startTime != $endTime) {
  622. $endTime += 0x80000000 * 1200 if $startTime > $endTime; # handle 33-bit wrap
  623. $et->HandleTag($tagTablePtr, 'Duration', $endTime - $startTime);
  624. }
  625. if ($verbose) {
  626. my @need;
  627. foreach (keys %needPID) {
  628. push @need, sprintf('0x%.2x',$_) if $needPID{$_} > 0;
  629. }
  630. if (@need) {
  631. @need = sort @need;
  632. print $out "End of file. Missing PID(s): @need\n";
  633. } else {
  634. my $what = $eof ? 'of file' : 'scan';
  635. print $out "End $what. All PID's parsed.\n";
  636. }
  637. }
  638. # parse any remaining partial PID streams
  639. my $pid;
  640. foreach $pid (sort keys %data) {
  641. ParsePID($et, $pid, $pidType{$pid}, $pidName{$pid}, \$data{$pid});
  642. delete $data{$pid};
  643. }
  644. return 1;
  645. }
  646. 1; # end
  647. __END__
  648. =head1 NAME
  649. Image::ExifTool::M2TS - Read M2TS (AVCHD) meta information
  650. =head1 SYNOPSIS
  651. This module is used by Image::ExifTool
  652. =head1 DESCRIPTION
  653. This module contains routines required by Image::ExifTool to extract
  654. information from MPEG-2 transport streams, such as those used by AVCHD
  655. video.
  656. =head1 AUTHOR
  657. Copyright 2003-2016, Phil Harvey (phil at owl.phy.queensu.ca)
  658. This library is free software; you can redistribute it and/or modify it
  659. under the same terms as Perl itself.
  660. =head1 REFERENCES
  661. =over 4
  662. =item L<http://neuron2.net/library/mpeg2/iso13818-1.pdf>
  663. =item L<http://www.blu-raydisc.com/Assets/Downloadablefile/BD-RE_Part3_V2.1_WhitePaper_080406-15271.pdf>
  664. =item L<http://www.videohelp.com/forum/archive/reading-avchd-playlist-files-bdmv-playlist-mpl-t358888.html>
  665. =item L<http://en.wikipedia.org/wiki/MPEG_transport_stream>
  666. =item L<http://www.dunod.com/documents/9782100493463/49346_DVB.pdf>
  667. =item L<http://trac.handbrake.fr/browser/trunk/libhb/stream.c>
  668. =item L<http://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=04560141>
  669. =item L<http://www.w6rz.net/xport.zip>
  670. =back
  671. =head1 SEE ALSO
  672. L<Image::ExifTool::TagNames/M2TS Tags>,
  673. L<Image::ExifTool(3pm)|Image::ExifTool>
  674. =cut