H264.pm 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113
  1. #------------------------------------------------------------------------------
  2. # File: H264.pm
  3. #
  4. # Description: Read meta information from H.264 video
  5. #
  6. # Revisions: 2010/01/31 - P. Harvey Created
  7. #
  8. # References: 1) http://www.itu.int/rec/T-REC-H.264/e (T-REC-H.264-200305-S!!PDF-E.pdf)
  9. # 2) http://miffteevee.co.uk/documentation/development/H264Parser_8cpp-source.html
  10. # 3) http://ffmpeg.org/
  11. # 4) US Patent 2009/0052875 A1
  12. # 5) European Patent (EP2 051 528A1) application no. 07792522.0 filed 08.08.2007
  13. # 6) Dave Nicholson private communication
  14. # 7) http://www.freepatentsonline.com/20050076039.pdf
  15. # 8) Michael Reitinger private communication (RX100)
  16. #
  17. # Glossary: RBSP = Raw Byte Sequence Payload
  18. #------------------------------------------------------------------------------
  19. package Image::ExifTool::H264;
  20. use strict;
  21. use vars qw($VERSION %convMake);
  22. use Image::ExifTool qw(:DataAccess :Utils);
  23. use Image::ExifTool::Exif;
  24. $VERSION = '1.13';
  25. sub ProcessSEI($$);
  26. my $parsePictureTiming; # flag to enable parsing of picture timing information (test only)
  27. # lookup for camera manufacturer name
  28. %convMake = (
  29. 0x0103 => 'Panasonic',
  30. 0x0108 => 'Sony',
  31. 0x1011 => 'Canon',
  32. 0x1104 => 'JVC', #Rob Lewis
  33. );
  34. # information extracted from H.264 video streams
  35. %Image::ExifTool::H264::Main = (
  36. GROUPS => { 2 => 'Video' },
  37. VARS => { NO_ID => 1 },
  38. NOTES => q{
  39. Tags extracted from H.264 video streams. The metadata for AVCHD videos is
  40. stored in this stream.
  41. },
  42. ImageWidth => { },
  43. ImageHeight => { },
  44. MDPM => { SubDirectory => { TagTable => 'Image::ExifTool::H264::MDPM' } },
  45. );
  46. # H.264 Supplemental Enhancement Information User Data (ref PH/4)
  47. %Image::ExifTool::H264::MDPM = (
  48. GROUPS => { 2 => 'Camera' },
  49. PROCESS_PROC => \&ProcessSEI,
  50. TAG_PREFIX => 'MDPM',
  51. NOTES => q{
  52. The following tags are decoded from the Modified Digital Video Pack Metadata
  53. (MDPM) of the unregistered user data with UUID
  54. 17ee8c60f84d11d98cd60800200c9a66 in the H.264 Supplemental Enhancement
  55. Information (SEI). I<[Yes, this description is confusing, but nothing
  56. compared to the challenge of actually decoding the data!]> This information
  57. may exist at regular intervals through the entire video, but only the first
  58. occurrence is extracted unless the ExtractEmbedded (-ee) option is used (in
  59. which case subsequent occurrences are extracted as sub-documents).
  60. },
  61. # (Note: all these are explained in IEC 61834-4, but it costs money so it is useless to me)
  62. # 0x00 - ControlCassetteID (ref 7)
  63. # 0x01 - ControlTapeLength (ref 7)
  64. # 0x02 - ControlTimerActDate (ref 7)
  65. # 0x03 - ControlTimerACS_S_S (ref 7)
  66. # 0x04-0x05 - ControlPR_StartPoint (ref 7)
  67. # 0x06 - ControlTagIDNoGenre (ref 7)
  68. # 0x07 - ControlTopicPageHeader (ref 7)
  69. # 0x08 - ControlTextHeader (ref 7)
  70. # 0x09 - ControlText (ref 7)
  71. # 0x0a-0x0b - ControlTag (ref 7)
  72. # 0x0c - ControlTeletextInfo (ref 7)
  73. # 0x0d - ControlKey (ref 7)
  74. # 0x0e-0x0f - ControlZoneEnd (ref 7)
  75. # 0x10 - TitleTotalTime (ref 7)
  76. # 0x11 - TitleRemainTime (ref 7)
  77. # 0x12 - TitleChapterTotalNo (ref 7)
  78. 0x13 => {
  79. Name => 'TimeCode',
  80. Notes => 'hours:minutes:seconds:frames',
  81. ValueConv => 'sprintf("%.2x:%.2x:%.2x:%.2x",reverse unpack("C*",$val))',
  82. },
  83. # 0x14 - TitleBinaryGroup
  84. # 0x15 - TitleCassetteNo (ref 7)
  85. # 0x16-0x17 - TitleSoftID (ref 7)
  86. # (0x18,0x19 listed as TitleTextHeader/TitleText by ref 7)
  87. 0x18 => {
  88. Name => 'DateTimeOriginal',
  89. Description => 'Date/Time Original',
  90. Groups => { 2 => 'Time' },
  91. Notes => 'combined with tag 0x19',
  92. Combine => 1, # the next tag (0x19) contains the rest of the date
  93. # first byte is timezone information:
  94. # 0x80 - unused
  95. # 0x40 - DST flag
  96. # 0x20 - TimeZoneSign
  97. # 0x1e - TimeZoneValue
  98. # 0x01 - half-hour flag
  99. ValueConv => q{
  100. my ($tz, @a) = unpack('C*',$val);
  101. return sprintf('%.2x%.2x:%.2x:%.2x %.2x:%.2x:%.2x%s%.2d:%s%s', @a,
  102. $tz & 0x20 ? '-' : '+', ($tz >> 1) & 0x0f,
  103. $tz & 0x01 ? '30' : '00',
  104. $tz & 0x40 ? ' DST' : '');
  105. },
  106. PrintConv => '$self->ConvertDateTime($val)',
  107. },
  108. # 0x1a-0x1b - TitleStart (ref 7)
  109. # 0x1c-0x1d - TitleReelID (ref 7)
  110. # 0x1e-0x1f - TitleEnd (ref 7)
  111. # 0x20 - ChapterTotalTime (ref 7)
  112. # 0x42 - ProgramRecDTime (ref 7)
  113. # 0x50/0x60 - (AAUX/VAUX)Source (ref 7)
  114. # 0x51/0x61 - (AAUX/VAUX)SourceControl (ref 7)
  115. # 0x52/0x62 - (AAUX/VAUX)RecDate (ref 7)
  116. # 0x53/0x63 - (AAUX/VAUX)RecTime (ref 7)
  117. # 0x54/0x64 - (AAUX/VAUX)BinaryGroup (ref 7)
  118. # 0x55/0x65 - (AAUX/VAUX)ClosedCaption (ref 7)
  119. # 0x56/0x66 - (AAUX/VAUX)TR (ref 7)
  120. 0x70 => { # ConsumerCamera1
  121. Name => 'Camera1',
  122. SubDirectory => { TagTable => 'Image::ExifTool::H264::Camera1' },
  123. },
  124. 0x71 => { # ConsumerCamera2
  125. Name => 'Camera2',
  126. SubDirectory => { TagTable => 'Image::ExifTool::H264::Camera2' },
  127. },
  128. # 0x73 Lens - val: 0x75ffffd3,0x0effffd3,0x59ffffd3,0x79ffffd3,0xffffffd3...
  129. # 0x74 Gain
  130. # 0x75 Pedestal
  131. # 0x76 Gamma
  132. # 0x77 Detail
  133. # 0x7b CameraPreset
  134. # 0x7c Flare
  135. # 0x7d Shading
  136. # 0x7e Knee
  137. 0x7f => { # Shutter
  138. Name => 'Shutter',
  139. SubDirectory => {
  140. TagTable => 'Image::ExifTool::H264::Shutter',
  141. ByteOrder => 'LittleEndian', # weird
  142. },
  143. },
  144. 0xa0 => {
  145. Name => 'ExposureTime',
  146. Format => 'rational32u',
  147. Groups => { 2 => 'Image' },
  148. PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
  149. },
  150. 0xa1 => {
  151. Name => 'FNumber',
  152. Format => 'rational32u',
  153. Groups => { 2 => 'Image' },
  154. },
  155. 0xa2 => {
  156. Name => 'ExposureProgram',
  157. Format => 'int32u', # (guess)
  158. PrintConv => {
  159. 0 => 'Not Defined',
  160. 1 => 'Manual',
  161. 2 => 'Program AE',
  162. 3 => 'Aperture-priority AE',
  163. 4 => 'Shutter speed priority AE',
  164. 5 => 'Creative (Slow speed)',
  165. 6 => 'Action (High speed)',
  166. 7 => 'Portrait',
  167. 8 => 'Landscape',
  168. },
  169. },
  170. 0xa3 => {
  171. Name => 'BrightnessValue',
  172. Format => 'rational32s',
  173. Groups => { 2 => 'Image' },
  174. },
  175. 0xa4 => {
  176. Name => 'ExposureCompensation',
  177. Format => 'rational32s',
  178. Groups => { 2 => 'Image' },
  179. PrintConv => 'Image::ExifTool::Exif::PrintFraction($val)',
  180. },
  181. 0xa5 => {
  182. Name => 'MaxApertureValue',
  183. Format => 'rational32u',
  184. ValueConv => '2 ** ($val / 2)',
  185. PrintConv => 'sprintf("%.1f",$val)',
  186. },
  187. 0xa6 => {
  188. Name => 'Flash',
  189. Format => 'int32u', # (guess)
  190. Flags => 'PrintHex',
  191. SeparateTable => 'EXIF Flash',
  192. PrintConv => \%Image::ExifTool::Exif::flash,
  193. },
  194. 0xa7 => {
  195. Name => 'CustomRendered',
  196. Format => 'int32u', # (guess)
  197. Groups => { 2 => 'Image' },
  198. PrintConv => {
  199. 0 => 'Normal',
  200. 1 => 'Custom',
  201. },
  202. },
  203. 0xa8 => {
  204. Name => 'WhiteBalance',
  205. Format => 'int32u', # (guess)
  206. Priority => 0,
  207. PrintConv => {
  208. 0 => 'Auto',
  209. 1 => 'Manual',
  210. },
  211. },
  212. 0xa9 => {
  213. Name => 'FocalLengthIn35mmFormat',
  214. Format => 'rational32u',
  215. PrintConv => '"$val mm"',
  216. },
  217. 0xaa => {
  218. Name => 'SceneCaptureType',
  219. Format => 'int32u', # (guess)
  220. PrintConv => {
  221. 0 => 'Standard',
  222. 1 => 'Landscape',
  223. 2 => 'Portrait',
  224. 3 => 'Night',
  225. },
  226. },
  227. # 0xab-0xaf ExifOption
  228. 0xb0 => {
  229. Name => 'GPSVersionID',
  230. Format => 'int8u',
  231. Count => 4,
  232. Groups => { 1 => 'GPS', 2 => 'Location' },
  233. PrintConv => '$val =~ tr/ /./; $val',
  234. },
  235. 0xb1 => {
  236. Name => 'GPSLatitudeRef',
  237. Format => 'string',
  238. Groups => { 1 => 'GPS', 2 => 'Location' },
  239. PrintConv => {
  240. N => 'North',
  241. S => 'South',
  242. },
  243. },
  244. 0xb2 => {
  245. Name => 'GPSLatitude',
  246. Format => 'rational32u',
  247. Groups => { 1 => 'GPS', 2 => 'Location' },
  248. Notes => 'combined with tags 0xb3 and 0xb4',
  249. Combine => 2, # combine the next 2 tags (0xb2=deg, 0xb3=min, 0xb4=sec)
  250. ValueConv => 'Image::ExifTool::GPS::ToDegrees($val)',
  251. PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1)',
  252. },
  253. 0xb5 => {
  254. Name => 'GPSLongitudeRef',
  255. Format => 'string',
  256. Groups => { 1 => 'GPS', 2 => 'Location' },
  257. PrintConv => {
  258. E => 'East',
  259. W => 'West',
  260. },
  261. },
  262. 0xb6 => {
  263. Name => 'GPSLongitude',
  264. Format => 'rational32u',
  265. Groups => { 1 => 'GPS', 2 => 'Location' },
  266. Combine => 2, # combine the next 2 tags (0xb6=deg, 0xb7=min, 0xb8=sec)
  267. Notes => 'combined with tags 0xb7 and 0xb8',
  268. ValueConv => 'Image::ExifTool::GPS::ToDegrees($val)',
  269. PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1)',
  270. },
  271. 0xb9 => {
  272. Name => 'GPSAltitudeRef',
  273. Format => 'int32u', # (guess)
  274. Groups => { 1 => 'GPS', 2 => 'Location' },
  275. ValueConv => '$val ? 1 : 0', # because I'm not sure about the Format
  276. PrintConv => {
  277. 0 => 'Above Sea Level',
  278. 1 => 'Below Sea Level',
  279. },
  280. },
  281. 0xba => {
  282. Name => 'GPSAltitude',
  283. Format => 'rational32u',
  284. Groups => { 1 => 'GPS', 2 => 'Location' },
  285. },
  286. 0xbb => {
  287. Name => 'GPSTimeStamp',
  288. Format => 'rational32u',
  289. Groups => { 1 => 'GPS', 2 => 'Time' },
  290. Combine => 2, # the next tags (0xbc/0xbd) contain the minutes/seconds
  291. Notes => 'combined with tags 0xbc and 0xbd',
  292. ValueConv => 'Image::ExifTool::GPS::ConvertTimeStamp($val)',
  293. PrintConv => 'Image::ExifTool::GPS::PrintTimeStamp($val)',
  294. },
  295. 0xbe => {
  296. Name => 'GPSStatus',
  297. Format => 'string',
  298. Groups => { 1 => 'GPS', 2 => 'Location' },
  299. PrintConv => {
  300. A => 'Measurement Active',
  301. V => 'Measurement Void',
  302. },
  303. },
  304. 0xbf => {
  305. Name => 'GPSMeasureMode',
  306. Format => 'string',
  307. Groups => { 1 => 'GPS', 2 => 'Location' },
  308. PrintConv => {
  309. 2 => '2-Dimensional Measurement',
  310. 3 => '3-Dimensional Measurement',
  311. },
  312. },
  313. 0xc0 => {
  314. Name => 'GPSDOP',
  315. Description => 'GPS Dilution Of Precision',
  316. Format => 'rational32u',
  317. Groups => { 1 => 'GPS', 2 => 'Location' },
  318. },
  319. 0xc1 => {
  320. Name => 'GPSSpeedRef',
  321. Format => 'string',
  322. Groups => { 1 => 'GPS', 2 => 'Location' },
  323. PrintConv => {
  324. K => 'km/h',
  325. M => 'mph',
  326. N => 'knots',
  327. },
  328. },
  329. 0xc2 => {
  330. Name => 'GPSSpeed',
  331. Format => 'rational32u',
  332. Groups => { 1 => 'GPS', 2 => 'Location' },
  333. },
  334. 0xc3 => {
  335. Name => 'GPSTrackRef',
  336. Format => 'string',
  337. Groups => { 1 => 'GPS', 2 => 'Location' },
  338. PrintConv => {
  339. M => 'Magnetic North',
  340. T => 'True North',
  341. },
  342. },
  343. 0xc4 => {
  344. Name => 'GPSTrack',
  345. Format => 'rational32u',
  346. Groups => { 1 => 'GPS', 2 => 'Location' },
  347. },
  348. 0xc5 => {
  349. Name => 'GPSImgDirectionRef',
  350. Format => 'string',
  351. Groups => { 1 => 'GPS', 2 => 'Location' },
  352. PrintConv => {
  353. M => 'Magnetic North',
  354. T => 'True North',
  355. },
  356. },
  357. 0xc6 => {
  358. Name => 'GPSImgDirection',
  359. Format => 'rational32u',
  360. Groups => { 1 => 'GPS', 2 => 'Location' },
  361. },
  362. 0xc7 => {
  363. Name => 'GPSMapDatum',
  364. Format => 'string',
  365. Groups => { 1 => 'GPS', 2 => 'Location' },
  366. Combine => 1, # the next tag (0xc8) contains the rest of the string
  367. Notes => 'combined with tag 0xc8',
  368. },
  369. # 0xc9-0xcf - GPSOption
  370. 0xe0 => {
  371. Name => 'MakeModel',
  372. SubDirectory => { TagTable => 'Image::ExifTool::H264::MakeModel' },
  373. },
  374. # 0xe1-0xef - MakerOption
  375. # 0xe1 - val: 0x01000670,0x01000678,0x06ffffff,0x01ffffff,0x01000020,0x01000400...
  376. # 0xe2-0xe8 - val: 0x00000000 in many samples
  377. 0xe1 => { #6
  378. Name => 'RecInfo',
  379. Condition => '$$self{Make} eq "Canon"',
  380. Notes => 'Canon only',
  381. SubDirectory => { TagTable => 'Image::ExifTool::H264::RecInfo' },
  382. },
  383. 0xe4 => { #PH
  384. Name => 'Model',
  385. Condition => '$$self{Make} eq "Sony"',
  386. Description => 'Camera Model Name',
  387. Notes => 'Sony cameras only, combined with tags 0xe5 and 0xe6',
  388. Format => 'string',
  389. Combine => 2, # (not sure about 0xe6, but include it just in case)
  390. RawConv => '$val eq "" ? undef : $val',
  391. },
  392. 0xee => { #6 (HFS200)
  393. Name => 'FrameInfo',
  394. Condition => '$$self{Make} eq "Canon"',
  395. Notes => 'Canon only',
  396. SubDirectory => { TagTable => 'Image::ExifTool::H264::FrameInfo' },
  397. },
  398. );
  399. # ConsumerCamera1 information (ref PH)
  400. %Image::ExifTool::H264::Camera1 = (
  401. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  402. GROUPS => { 2 => 'Camera' },
  403. TAG_PREFIX => 'Camera1',
  404. PRINT_CONV => 'sprintf("0x%.2x",$val)',
  405. FIRST_ENTRY => 0,
  406. 0 => {
  407. Name => 'ApertureSetting',
  408. PrintHex => 1,
  409. PrintConv => {
  410. 0xff => 'Auto',
  411. 0xfe => 'Closed',
  412. OTHER => sub { sprintf('%.1f', 2 ** (($_[0] & 0x3f) / 8)) },
  413. },
  414. },
  415. 1 => {
  416. Name => 'Gain',
  417. Mask => 0x0f,
  418. # (0x0f would translate to 42 dB, but this value is used by the Sony
  419. # HXR-NX5U for any out-of-range value such as -6 dB or "hyper gain" - PH)
  420. ValueConv => '($val - 1) * 3',
  421. PrintConv => '$val==42 ? "Out of range" : "$val dB"',
  422. },
  423. 1.1 => {
  424. Name => 'ExposureProgram',
  425. Mask => 0xf0,
  426. ValueConv => '$val == 0xf0 ? undef : $val',
  427. PrintConv => {
  428. 0x00 => 'Program AE',
  429. 0x10 => 'Gain', #?
  430. 0x20 => 'Shutter speed priority AE',
  431. 0x30 => 'Aperture-priority AE',
  432. 0x40 => 'Manual',
  433. },
  434. },
  435. 2.1 => {
  436. Name => 'WhiteBalance',
  437. Mask => 0xe0,
  438. ValueConv => '$val == 0xe0 ? undef : $val',
  439. PrintConv => {
  440. 0x00 => 'Auto',
  441. 0x20 => 'Hold',
  442. 0x40 => '1-Push',
  443. 0x60 => 'Daylight',
  444. },
  445. },
  446. 3 => {
  447. Name => 'Focus',
  448. ValueConv => '$val == 0xff ? undef : $val',
  449. PrintConv => q{
  450. my $foc = ($val & 0x7e) / (($val & 0x01) ? 40 : 400);
  451. return ($val & 0x80 ? 'Manual' : 'Auto') . " ($foc)";
  452. },
  453. },
  454. );
  455. # ConsumerCamera2 information (ref PH)
  456. %Image::ExifTool::H264::Camera2 = (
  457. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  458. GROUPS => { 2 => 'Camera' },
  459. TAG_PREFIX => 'Camera2',
  460. PRINT_CONV => 'sprintf("0x%.2x",$val)',
  461. FIRST_ENTRY => 0,
  462. 1 => {
  463. Name => 'ImageStabilization',
  464. PrintHex => 1,
  465. PrintConv => {
  466. 0 => 'Off',
  467. 0x3f => 'On (0x3f)', #8
  468. 0xbf => 'Off (0xbf)', #8
  469. 0xff => 'n/a',
  470. OTHER => sub {
  471. my $val = shift;
  472. sprintf("%s (0x%.2x)", $val & 0x10 ? "On" : "Off", $val);
  473. },
  474. },
  475. },
  476. );
  477. # camera info 0x7f (ref PH)
  478. %Image::ExifTool::H264::Shutter = (
  479. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  480. GROUPS => { 2 => 'Image' },
  481. TAG_PREFIX => 'Shutter',
  482. PRINT_CONV => 'sprintf("0x%.2x",$val)',
  483. FIRST_ENTRY => 0,
  484. FORMAT => 'int16u',
  485. 1.1 => { #6
  486. Name => 'ExposureTime',
  487. Mask => 0x7fff, # (what is bit 0x8000 for?)
  488. RawConv => '$val == 0x7fff ? undef : $val', #7
  489. ValueConv => '$val / 28125', #PH (Vixia HF G30, ref forum5588) (was $val/33640 until 9.49)
  490. PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
  491. },
  492. );
  493. # camera info 0xe0 (ref PH)
  494. %Image::ExifTool::H264::MakeModel = (
  495. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  496. GROUPS => { 2 => 'Camera' },
  497. FORMAT => 'int16u',
  498. FIRST_ENTRY => 0,
  499. 0 => {
  500. Name => 'Make',
  501. PrintHex => 1,
  502. RawConv => '$$self{Make} = ($Image::ExifTool::H264::convMake{$val} || "Unknown"); $val',
  503. PrintConv => \%convMake,
  504. },
  505. # 1 => ModelIDCode according to ref 4/5 (I think not - PH)
  506. # 1 => { Name => 'ModelIDCode', PrintConv => 'sprintf("%.4x",$val)' },
  507. # vals: 0x0313 - various Pansonic HDC models
  508. # 0x0345 - Panasonic HC-V7272
  509. # 0x0414 - Panasonic AG-AF100
  510. # 0x0591 - various Panasonic DMC models
  511. # 0x3001 - various Sony DSC, HDR, NEX and SLT models
  512. # 0x3003 - various Sony DSC models
  513. # 0x3100 - various Sony DSC, ILCE, NEX and SLT models
  514. # 0x1000 - Sony HDR-UX1
  515. # 0x2000 - Canon HF100 (60i)
  516. # 0x3000 - Canon HF100 (30p)
  517. # 0x3101 - Canon HFM300 (PH, all qualities and frame rates)
  518. # 0x3102 - Canon HFS200
  519. # 0x4300 - Canon HFG30
  520. );
  521. # camera info 0xe1 (ref 6)
  522. %Image::ExifTool::H264::RecInfo = (
  523. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  524. GROUPS => { 2 => 'Camera' },
  525. FORMAT => 'int8u',
  526. NOTES => 'Recording information stored by some Canon video cameras.',
  527. FIRST_ENTRY => 0,
  528. 0 => {
  529. Name => 'RecordingMode',
  530. PrintConv => {
  531. 0x02 => 'XP+', # High Quality 12 Mbps
  532. 0x04 => 'SP', # Standard Play 7 Mbps
  533. 0x05 => 'LP', # Long Play 5 Mbps
  534. 0x06 => 'FXP', # High Quality 17 Mbps
  535. 0x07 => 'MXP', # High Quality 24 Mbps
  536. },
  537. },
  538. );
  539. # camera info 0xee (ref 6)
  540. %Image::ExifTool::H264::FrameInfo = (
  541. PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  542. GROUPS => { 2 => 'Video' },
  543. FORMAT => 'int8u',
  544. NOTES => 'Frame rate information stored by some Canon video cameras.',
  545. FIRST_ENTRY => 0,
  546. 0 => 'CaptureFrameRate',
  547. 1 => 'VideoFrameRate',
  548. # 2 - 8=60i, 10=PF30, 74=PF24 (PH, HFM300)
  549. );
  550. #==============================================================================
  551. # Bitstream functions (used for H264 video)
  552. #
  553. # Member variables:
  554. # Mask = mask for next bit to read (0 when all data has been read)
  555. # Pos = byte offset of next word to read
  556. # Word = current data word
  557. # Len = total data length in bytes
  558. # DataPt = data pointer
  559. #..............................................................................
  560. #------------------------------------------------------------------------------
  561. # Read next word from bitstream
  562. # Inputs: 0) BitStream ref
  563. # Returns: true if there is more data (and updates
  564. # Mask, Pos and Word for first bit in next word)
  565. sub ReadNextWord($)
  566. {
  567. my $bstr = shift;
  568. my $pos = $$bstr{Pos};
  569. if ($pos + 4 <= $$bstr{Len}) {
  570. $$bstr{Word} = unpack("x$pos N", ${$$bstr{DataPt}});
  571. $$bstr{Mask} = 0x80000000;
  572. $$bstr{Pos} += 4;
  573. } elsif ($pos < $$bstr{Len}) {
  574. my @bytes = unpack("x$pos C*", ${$$bstr{DataPt}});
  575. my ($word, $mask) = (shift(@bytes), 0x80);
  576. while (@bytes) {
  577. $word = ($word << 8) | shift(@bytes);
  578. $mask <<= 8;
  579. }
  580. $$bstr{Word} = $word;
  581. $$bstr{Mask} = $mask;
  582. $$bstr{Pos} = $$bstr{Len};
  583. } else {
  584. return 0;
  585. }
  586. return 1;
  587. }
  588. #------------------------------------------------------------------------------
  589. # Create a new BitStream object
  590. # Inputs: 0) data ref
  591. # Returns: BitStream ref, or null if data is empty
  592. sub NewBitStream($)
  593. {
  594. my $dataPt = shift;
  595. my $bstr = {
  596. DataPt => $dataPt,
  597. Len => length($$dataPt),
  598. Pos => 0,
  599. Mask => 0,
  600. };
  601. ReadNextWord($bstr) or undef $bstr;
  602. return $bstr;
  603. }
  604. #------------------------------------------------------------------------------
  605. # Get number of bits remaining in bit stream
  606. # Inputs: 0) BitStream ref
  607. # Returns: number of bits remaining
  608. sub BitsLeft($)
  609. {
  610. my $bstr = shift;
  611. my $bits = 0;
  612. my $mask = $$bstr{Mask};
  613. while ($mask) {
  614. ++$bits;
  615. $mask >>= 1;
  616. }
  617. return $bits + 8 * ($$bstr{Len} - $$bstr{Pos});
  618. }
  619. #------------------------------------------------------------------------------
  620. # Get integer from bitstream
  621. # Inputs: 0) BitStream ref, 1) number of bits
  622. # Returns: integer (and increments position in bitstream)
  623. sub GetIntN($$)
  624. {
  625. my ($bstr, $bits) = @_;
  626. my $val = 0;
  627. while ($bits--) {
  628. $val <<= 1;
  629. ++$val if $$bstr{Mask} & $$bstr{Word};
  630. $$bstr{Mask} >>= 1 and next;
  631. ReadNextWord($bstr) or last;
  632. }
  633. return $val;
  634. }
  635. #------------------------------------------------------------------------------
  636. # Get Exp-Golomb integer from bitstream
  637. # Inputs: 0) BitStream ref
  638. # Returns: integer (and increments position in bitstream)
  639. sub GetGolomb($)
  640. {
  641. my $bstr = shift;
  642. # first, count the number of zero bits to get the integer bit width
  643. my $count = 0;
  644. until ($$bstr{Mask} & $$bstr{Word}) {
  645. ++$count;
  646. $$bstr{Mask} >>= 1 and next;
  647. ReadNextWord($bstr) or last;
  648. }
  649. # then return the adjusted integer
  650. return GetIntN($bstr, $count + 1) - 1;
  651. }
  652. #------------------------------------------------------------------------------
  653. # Get signed Exp-Golomb integer from bitstream
  654. # Inputs: 0) BitStream ref
  655. # Returns: integer (and increments position in bitstream)
  656. sub GetGolombS($)
  657. {
  658. my $bstr = shift;
  659. my $val = GetGolomb($bstr) + 1;
  660. return ($val & 1) ? -($val >> 1) : ($val >> 1);
  661. }
  662. # end bitstream functions
  663. #==============================================================================
  664. #------------------------------------------------------------------------------
  665. # Decode H.264 scaling matrices
  666. # Inputs: 0) BitStream ref
  667. # Reference: http://ffmpeg.org/
  668. sub DecodeScalingMatrices($)
  669. {
  670. my $bstr = shift;
  671. if (GetIntN($bstr, 1)) {
  672. my ($i, $j);
  673. for ($i=0; $i<8; ++$i) {
  674. my $size = $i<6 ? 16 : 64;
  675. next unless GetIntN($bstr, 1);
  676. my ($last, $next) = (8, 8);
  677. for ($j=0; $j<$size; ++$j) {
  678. $next = ($last + GetGolombS($bstr)) & 0xff if $next;
  679. last unless $j or $next;
  680. }
  681. }
  682. }
  683. }
  684. #------------------------------------------------------------------------------
  685. # Parse H.264 sequence parameter set RBSP (ref 1)
  686. # Inputs) 0) ExifTool ref, 1) tag table ref, 2) data ref
  687. sub ParseSeqParamSet($$$)
  688. {
  689. my ($et, $tagTablePtr, $dataPt) = @_;
  690. # initialize our bitstream object
  691. my $bstr = NewBitStream($dataPt) or return;
  692. my ($t, $i, $j, $n);
  693. # the messy nature of H.264 encoding makes it difficult to use
  694. # data-driven structure parsing, so I code it explicitly (yuck!)
  695. $t = GetIntN($bstr, 8); # profile_idc
  696. GetIntN($bstr, 16); # constraints and level_idc
  697. GetGolomb($bstr); # seq_parameter_set_id
  698. if ($t >= 100) { # (ref b)
  699. $t = GetGolomb($bstr); # chroma_format_idc
  700. if ($t == 3) {
  701. GetIntN($bstr, 1); # separate_colour_plane_flag
  702. $n = 12;
  703. } else {
  704. $n = 8;
  705. }
  706. GetGolomb($bstr); # bit_depth_luma_minus8
  707. GetGolomb($bstr); # bit_depth_chroma_minus8
  708. GetIntN($bstr, 1); # qpprime_y_zero_transform_bypass_flag
  709. DecodeScalingMatrices($bstr);
  710. }
  711. GetGolomb($bstr); # log2_max_frame_num_minus4
  712. $t = GetGolomb($bstr); # pic_order_cnt_type
  713. if ($t == 0) {
  714. GetGolomb($bstr); # log2_max_pic_order_cnt_lsb_minus4
  715. } elsif ($t == 1) {
  716. GetIntN($bstr, 1); # delta_pic_order_always_zero_flag
  717. GetGolomb($bstr); # offset_for_non_ref_pic
  718. GetGolomb($bstr); # offset_for_top_to_bottom_field
  719. $n = GetGolomb($bstr); # num_ref_frames_in_pic_order_cnt_cycle
  720. for ($i=0; $i<$n; ++$i) {
  721. GetGolomb($bstr); # offset_for_ref_frame[i]
  722. }
  723. }
  724. GetGolomb($bstr); # num_ref_frames
  725. GetIntN($bstr, 1); # gaps_in_frame_num_value_allowed_flag
  726. my $w = GetGolomb($bstr); # pic_width_in_mbs_minus1
  727. my $h = GetGolomb($bstr); # pic_height_in_map_units_minus1
  728. my $f = GetIntN($bstr, 1); # frame_mbs_only_flag
  729. $f or GetIntN($bstr, 1); # mb_adaptive_frame_field_flag
  730. GetIntN($bstr, 1); # direct_8x8_inference_flag
  731. # convert image size to pixels
  732. $w = ($w + 1) * 16;
  733. $h = (2 - $f) * ($h + 1) * 16;
  734. # account for cropping (if any)
  735. $t = GetIntN($bstr, 1); # frame_cropping_flag
  736. if ($t) {
  737. my $m = 4 - $f * 2;
  738. $w -= 4 * GetGolomb($bstr);# frame_crop_left_offset
  739. $w -= 4 * GetGolomb($bstr);# frame_crop_right_offset
  740. $h -= $m * GetGolomb($bstr);# frame_crop_top_offset
  741. $h -= $m * GetGolomb($bstr);# frame_crop_bottom_offset
  742. }
  743. # quick validity checks (just in case)
  744. return unless $$bstr{Mask};
  745. if ($w>=160 and $w<=4096 and $h>=120 and $h<=3072) {
  746. $et->HandleTag($tagTablePtr, ImageWidth => $w);
  747. $et->HandleTag($tagTablePtr, ImageHeight => $h);
  748. # (whew! -- so much work just to get ImageSize!!)
  749. }
  750. # return now unless interested in picture timing information
  751. return unless $parsePictureTiming;
  752. # parse vui parameters if they exist
  753. GetIntN($bstr, 1) or return; # vui_parameters_present_flag
  754. $t = GetIntN($bstr, 1); # aspect_ratio_info_present_flag
  755. if ($t) {
  756. $t = GetIntN($bstr, 8); # aspect_ratio_idc
  757. if ($t == 255) { # Extended_SAR ?
  758. GetIntN($bstr, 32); # sar_width/sar_height
  759. }
  760. }
  761. $t = GetIntN($bstr, 1); # overscan_info_present_flag
  762. GetIntN($bstr, 1) if $t; # overscan_appropriate_flag
  763. $t = GetIntN($bstr, 1); # video_signal_type_present_flag
  764. if ($t) {
  765. GetIntN($bstr, 4); # video_format/video_full_range_flag
  766. $t = GetIntN($bstr, 1); # colour_description_present_flag
  767. GetIntN($bstr, 24) if $t; # colour_primaries/transfer_characteristics/matrix_coefficients
  768. }
  769. $t = GetIntN($bstr, 1); # chroma_loc_info_present_flag
  770. if ($t) {
  771. GetGolomb($bstr); # chroma_sample_loc_type_top_field
  772. GetGolomb($bstr); # chroma_sample_loc_type_bottom_field
  773. }
  774. $t = GetIntN($bstr, 1); # timing_info_present_flag
  775. if ($t) {
  776. return if BitsLeft($bstr) < 65;
  777. $$et{VUI_units} = GetIntN($bstr, 32); # num_units_in_tick
  778. $$et{VUI_scale} = GetIntN($bstr, 32); # time_scale
  779. GetIntN($bstr, 1); # fixed_frame_rate_flag
  780. }
  781. my $hard;
  782. for ($j=0; $j<2; ++$j) {
  783. $t = GetIntN($bstr, 1); # nal_/vcl_hrd_parameters_present_flag
  784. if ($t) {
  785. $$et{VUI_hard} = 1;
  786. $hard = 1;
  787. $n = GetGolomb($bstr); # cpb_cnt_minus1
  788. GetIntN($bstr, 8); # bit_rate_scale/cpb_size_scale
  789. for ($i=0; $i<=$n; ++$i) {
  790. GetGolomb($bstr); # bit_rate_value_minus1[SchedSelIdx]
  791. GetGolomb($bstr); # cpb_size_value_minus1[SchedSelIdx]
  792. GetIntN($bstr, 1); # cbr_flag[SchedSelIdx]
  793. }
  794. GetIntN($bstr, 5); # initial_cpb_removal_delay_length_minus1
  795. $$et{VUI_clen} = GetIntN($bstr, 5); # cpb_removal_delay_length_minus1
  796. $$et{VUI_dlen} = GetIntN($bstr, 5); # dpb_output_delay_length_minus1
  797. $$et{VUI_toff} = GetIntN($bstr, 5); # time_offset_length
  798. }
  799. }
  800. GetIntN($bstr, 1) if $hard; # low_delay_hrd_flag
  801. $$et{VUI_pic} = GetIntN($bstr, 1); # pic_struct_present_flag
  802. # (don't yet decode the rest of the vui data)
  803. }
  804. #------------------------------------------------------------------------------
  805. # Parse H.264 picture timing SEI message (payload type 1) (ref 1)
  806. # Inputs) 0) ExifTool ref, 1) data ref
  807. sub ParsePictureTiming($$)
  808. {
  809. my ($et, $dataPt) = @_;
  810. my $bstr = NewBitStream($dataPt) or return;
  811. my ($i, $t, $n);
  812. # the specification is very odd on this point: the following delays
  813. # exist if the VUI hardware parameters are present, or if
  814. # "determined by the application, by some means not specified" -- WTF??
  815. if ($$et{VUI_hard}) {
  816. GetIntN($bstr, $$et{VUI_clen} + 1); # cpb_removal_delay
  817. GetIntN($bstr, $$et{VUI_dlen} + 1); # dpb_output_delay
  818. }
  819. if ($$et{VUI_pic}) {
  820. $t = GetIntN($bstr, 4); # pic_struct
  821. # determine NumClockTS ($n)
  822. $n = { 0=>1, 1=>1, 2=>1, 3=>2, 4=>2, 5=>3, 6=>3, 7=>2, 8=>3 }->{$t};
  823. $n or return;
  824. for ($i=0; $i<$n; ++$i) {
  825. $t = GetIntN($bstr, 1); # clock_timestamp_flag[i]
  826. next unless $t;
  827. my ($nu, $s, $m, $h, $o);
  828. GetIntN($bstr, 2); # ct_type
  829. $nu = GetIntN($bstr, 1);# nuit_field_based_flag
  830. GetIntN($bstr, 5); # counting_type
  831. $t = GetIntN($bstr, 1); # full_timestamp_flag
  832. GetIntN($bstr, 1); # discontinuity_flag
  833. GetIntN($bstr, 1); # cnt_dropped_flag
  834. GetIntN($bstr, 8); # n_frames
  835. if ($t) {
  836. $s = GetIntN($bstr, 6); # seconds_value
  837. $m = GetIntN($bstr, 6); # minutes_value
  838. $h = GetIntN($bstr, 5); # hours_value
  839. } else {
  840. $t = GetIntN($bstr, 1); # seconds_flag
  841. if ($t) {
  842. $s = GetIntN($bstr, 6); # seconds_value
  843. $t = GetIntN($bstr, 1); # minutes_flag
  844. if ($t) {
  845. $m = GetIntN($bstr, 6); # minutes_value
  846. $t = GetIntN($bstr, 1); # hours_flag
  847. $h = GetIntN($bstr, 5) if $t; # hours_value
  848. }
  849. }
  850. }
  851. if ($$et{VUI_toff}) {
  852. $o = GetIntN($bstr, $$et{VUI_toff}); # time_offset
  853. }
  854. last; # only parse the first clock timestamp found
  855. }
  856. }
  857. }
  858. #------------------------------------------------------------------------------
  859. # Process H.264 Supplementary Enhancement Information (ref 1/PH)
  860. # Inputs: 0) Exiftool ref, 1) dirInfo ref, 2) tag table ref
  861. # Returns: 1 if we processed payload type 5
  862. sub ProcessSEI($$)
  863. {
  864. my ($et, $dirInfo) = @_;
  865. my $dataPt = $$dirInfo{DataPt};
  866. my $end = length($$dataPt);
  867. my $pos = 0;
  868. my ($type, $size, $index, $t);
  869. # scan through SEI payload for type 5 (the unregistered user data)
  870. for (;;) {
  871. $type = 0;
  872. for (;;) {
  873. return 0 if $pos >= $end;
  874. $t = Get8u($dataPt, $pos++); # payload type
  875. $type += $t;
  876. last unless $t == 255;
  877. }
  878. return 0 if $type == 0x80; # terminator (ref PH - maybe byte alignment bits?)
  879. $size = 0;
  880. for (;;) {
  881. return 0 if $pos >= $end;
  882. $t = Get8u($dataPt, $pos++); # payload data length
  883. $size += $t;
  884. last unless $t == 255;
  885. }
  886. return 0 if $pos + $size > $end;
  887. if ($type == 1) { # picture timing information
  888. if ($parsePictureTiming) {
  889. my $buff = substr($$dataPt, $pos, $size);
  890. ParsePictureTiming($et, $dataPt);
  891. }
  892. } elsif ($type == 5) { # unregistered user data
  893. last; # exit loop to process user data now
  894. }
  895. $pos += $size;
  896. }
  897. # look for our 16-byte UUID
  898. # - plus "MDPM" for "ModifiedDVPackMeta"
  899. # - plus "GA94" for closed-caption data (currently not decoded)
  900. return 0 unless $size > 20 and substr($$dataPt, $pos, 20) eq
  901. "\x17\xee\x8c\x60\xf8\x4d\x11\xd9\x8c\xd6\x08\0\x20\x0c\x9a\x66MDPM";
  902. # load the GPS module because it contains conversion routines and
  903. # Composite tags needed for a number of tags we may be extracting
  904. require Image::ExifTool::GPS;
  905. #
  906. # parse the MDPM records in the UUID 17ee8c60f84d11d98cd60800200c9a66
  907. # unregistered user data payload (ref PH)
  908. #
  909. my $tagTablePtr = GetTagTable('Image::ExifTool::H264::MDPM');
  910. my $oldIndent = $$et{INDENT};
  911. $$et{INDENT} .= '| ';
  912. $end = $pos + $size; # end of payload
  913. $pos += 20; # skip UUID + "MDPM"
  914. my $num = Get8u($dataPt, $pos++); # get entry count
  915. my $lastTag = 0;
  916. $et->VerboseDir('MDPM', $num) if $et->Options('Verbose');
  917. # walk through entries in the MDPM payload
  918. for ($index=0; $index<$num and $pos<$end; ++$index) {
  919. my $tag = Get8u($dataPt, $pos);
  920. if ($tag <= $lastTag) { # should be in numerical order (PH)
  921. $et->Warn('Entries in MDPM directory are out of sequence');
  922. last;
  923. }
  924. $lastTag = $tag;
  925. my $buff = substr($$dataPt, $pos + 1, 4);
  926. my $from;
  927. my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
  928. if ($tagInfo) {
  929. # use our own print conversion for Unknown tags
  930. if ($$tagInfo{Unknown} and not $$tagInfo{SetPrintConv}) {
  931. $$tagInfo{PrintConv} = 'sprintf("0x%.8x", unpack("N", $val))';
  932. $$tagInfo{SetPrintConv} = 1;
  933. }
  934. # combine with next value(s) if necessary
  935. my $combine = $$tagTablePtr{$tag}{Combine};
  936. while ($combine) {
  937. last if $pos + 5 >= $end;
  938. my $t = Get8u($dataPt, $pos + 5);
  939. last if $t != $lastTag + 1; # must be consecutive tag ID's
  940. $pos += 5;
  941. $buff .= substr($$dataPt, $pos + 1, 4);
  942. $from = $index unless defined $from;
  943. ++$index;
  944. ++$lastTag;
  945. --$combine;
  946. }
  947. $et->HandleTag($tagTablePtr, $tag, undef,
  948. TagInfo => $tagInfo,
  949. DataPt => \$buff,
  950. Size => length($buff),
  951. Index => defined $from ? "$from-$index" : $index,
  952. );
  953. }
  954. $pos += 5;
  955. }
  956. $$et{INDENT} = $oldIndent;
  957. return 1;
  958. }
  959. #------------------------------------------------------------------------------
  960. # Extract information from H.264 video stream
  961. # Inputs: 0) ExifTool ref, 1) data ref
  962. # Returns: 0 = done parsing, 1 = we want to parse more of these
  963. sub ParseH264Video($$)
  964. {
  965. my ($et, $dataPt) = @_;
  966. my $verbose = $et->Options('Verbose');
  967. my $out = $et->Options('TextOut');
  968. my $tagTablePtr = GetTagTable('Image::ExifTool::H264::Main');
  969. my %parseNalUnit = ( 0x06 => 1, 0x07 => 1 ); # NAL unit types to parse
  970. my $foundUserData;
  971. my $len = length $$dataPt;
  972. my $pos = 0;
  973. while ($pos < $len) {
  974. my ($nextPos, $end);
  975. # find start of next NAL unit
  976. if ($$dataPt =~ /(\0{2,3}\x01)/g) {
  977. $nextPos = pos $$dataPt;
  978. $end = $nextPos - length $1;
  979. $pos or $pos = $nextPos, next;
  980. } else {
  981. last unless $pos;
  982. $nextPos = $end = $len;
  983. }
  984. last if $pos >= $len;
  985. # parse NAL unit from $pos to $end
  986. my $nal_unit_type = Get8u($dataPt, $pos);
  987. ++$pos;
  988. # check forbidden_zero_bit
  989. $nal_unit_type & 0x80 and $et->Warn('H264 forbidden bit error'), last;
  990. $nal_unit_type &= 0x1f;
  991. # ignore this NAL unit unless we will parse it
  992. $parseNalUnit{$nal_unit_type} or $verbose or $pos = $nextPos, next;
  993. # read NAL unit (and convert all 0x000003's to 0x0000 as per spec.)
  994. my $buff = '';
  995. pos($$dataPt) = $pos + 1;
  996. while ($$dataPt =~ /\0\0\x03/g) {
  997. last if pos $$dataPt > $end;
  998. $buff .= substr($$dataPt, $pos, pos($$dataPt)-1-$pos);
  999. $pos = pos $$dataPt;
  1000. }
  1001. $buff .= substr($$dataPt, $pos, $end - $pos);
  1002. if ($verbose > 1) {
  1003. printf $out " NAL Unit Type: 0x%x (%d bytes)\n",$nal_unit_type, length $buff;
  1004. my %parms = ( Out => $out );
  1005. $parms{MaxLen} = 96 if $verbose < 4;
  1006. HexDump(\$buff, undef, %parms) if $verbose > 2;
  1007. }
  1008. pos($$dataPt) = $pos = $nextPos;
  1009. if ($nal_unit_type == 0x06) { # sei_rbsp (supplemental enhancement info)
  1010. if ($$et{GotNAL06}) {
  1011. # process only the first SEI unless ExtractEmbedded is set
  1012. next unless $et->Options('ExtractEmbedded');
  1013. $$et{DOC_NUM} = $$et{GotNAL06};
  1014. }
  1015. $foundUserData = ProcessSEI($et, { DataPt => \$buff } );
  1016. delete $$et{DOC_NUM};
  1017. # keep parsing SEI's until we find the user data
  1018. next unless $foundUserData;
  1019. $$et{GotNAL06} = ($$et{GotNAL06} || 0) + 1;
  1020. } elsif ($nal_unit_type == 0x07) { # sequence_parameter_set_rbsp
  1021. # process this NAL unit type only once
  1022. next if $$et{GotNAL07};
  1023. $$et{GotNAL07} = 1;
  1024. ParseSeqParamSet($et, $tagTablePtr, \$buff);
  1025. }
  1026. # we were successful, so don't parse this NAL unit type again
  1027. delete $parseNalUnit{$nal_unit_type};
  1028. }
  1029. # parse one extra H264 frame if we didn't find the user data in this one
  1030. # (Panasonic cameras don't put the SEI in the first frame)
  1031. return 0 if $foundUserData or $$et{ParsedH264};
  1032. $$et{ParsedH264} = 1;
  1033. return 1;
  1034. }
  1035. 1; # end
  1036. __END__
  1037. =head1 NAME
  1038. Image::ExifTool::H264 - Read meta information from H.264 video
  1039. =head1 SYNOPSIS
  1040. This module is used by Image::ExifTool
  1041. =head1 DESCRIPTION
  1042. This module contains routines required by Image::ExifTool to extract
  1043. information from H.264 video streams.
  1044. =head1 AUTHOR
  1045. Copyright 2003-2016, Phil Harvey (phil at owl.phy.queensu.ca)
  1046. This library is free software; you can redistribute it and/or modify it
  1047. under the same terms as Perl itself.
  1048. =head1 REFERENCES
  1049. =over 4
  1050. =item L<http://www.itu.int/rec/T-REC-H.264/e>
  1051. =item L<http://miffteevee.co.uk/documentation/development/H264Parser_8cpp-source.html>
  1052. =item L<http://ffmpeg.org/>
  1053. =back
  1054. =head1 SEE ALSO
  1055. L<Image::ExifTool::TagNames/H264 Tags>,
  1056. L<Image::ExifTool(3pm)|Image::ExifTool>
  1057. =cut