mpeg.lisp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. ;;; -*- Mode: Lisp; show-trailing-whitespace: t; Base: 10; indent-tabs: nil; Syntax: ANSI-Common-Lisp; Package: MPEG; -*-
  2. ;;; Copyright (c) 2013, Mark VandenBrink. All rights reserved.
  3. ;;; Parsing MPEG audio frames. See http://www.datavoyage.com/mpgscript/mpeghdr.htm for format of a frame.
  4. (in-package #:mpeg)
  5. (log5:defcategory cat-log-mpeg-frame)
  6. (defmacro log-mpeg-frame (&rest log-stuff) `(log5:log-for (cat-log-mpeg-frame) ,@log-stuff))
  7. (define-condition mpeg-condition ()
  8. ((location :initarg :location :reader location :initform nil)
  9. (object :initarg :object :reader object :initform nil)
  10. (messsage :initarg :message :reader message :initform "Undefined Condition"))
  11. (:report (lambda (condition stream)
  12. (format stream "MP3 condition at location <~a> with object <~a>: message<~a>"
  13. (location condition) (object condition) (message condition)))))
  14. (define-condition mpeg-bad-header (mpeg-condition) ())
  15. (defconstant +sync-word+ #x7ff "NB: this is 11 bits so as to be able to recognize V2.5")
  16. ;;; the versions
  17. (defconstant +mpeg-2.5+ 0)
  18. (defconstant +v-reserved+ 1)
  19. (defconstant +mpeg-2+ 2)
  20. (defconstant +mpeg-1+ 3)
  21. (defun valid-version (version)
  22. (declare #.utils:*standard-optimize-settings*)
  23. (or ;; can't deal with 2.5's yet (= (the fixnum +mpeg-2.5+) (the fixnum version))
  24. (= (the fixnum +mpeg-2+) (the fixnum version))
  25. (= (the fixnum +mpeg-1+) (the fixnum version))))
  26. (defun get-mpeg-version-string (version)
  27. (declare #.utils:*standard-optimize-settings*)
  28. (nth version '("MPEG 2.5" "Reserved" "MPEG 2" "MPEG 1")))
  29. ;;; the layers
  30. (defconstant +layer-reserved+ 0)
  31. (defconstant +layer-3+ 1)
  32. (defconstant +layer-2+ 2)
  33. (defconstant +layer-1+ 3)
  34. (defun valid-layer (layer)
  35. (declare #.utils:*standard-optimize-settings*)
  36. (or (= (the fixnum +layer-3+) (the fixnum layer))
  37. (= (the fixnum +layer-2+) (the fixnum layer))
  38. (= (the fixnum +layer-1+) (the fixnum layer))))
  39. (defun get-layer-string (layer)
  40. (declare #.utils:*standard-optimize-settings*)
  41. (nth layer '("Reserved" "Layer III" "Layer II" "Layer I")))
  42. ;;; the modes
  43. (defconstant +channel-mode-stereo+ 0)
  44. (defconstant +channel-mode-joint+ 1)
  45. (defconstant +channel-mode-dual+ 2)
  46. (defconstant +channel-mode-mono+ 3)
  47. (defun get-channel-mode-string (mode)
  48. (declare #.utils:*standard-optimize-settings*)
  49. (nth mode '("Stereo" "Joint" "Dual" "Mono")))
  50. ;;; the emphases
  51. (defconstant +emphasis-none+ 0)
  52. (defconstant +emphasis-50-15+ 1)
  53. (defconstant +emphasis-reserved+ 2)
  54. (defconstant +emphasis-ccit+ 3)
  55. (defun get-emphasis-string (e)
  56. (declare #.utils:*standard-optimize-settings*)
  57. (nth e '("None" "50/15 ms" "Reserved" "CCIT J.17")))
  58. (defun valid-emphasis (e)
  59. (declare #.utils:*standard-optimize-settings*)
  60. (or (= (the fixnum e) (the fixnum +emphasis-none+))
  61. (= (the fixnum e) (the fixnum +emphasis-50-15+))
  62. (= (the fixnum e) (the fixnum +emphasis-ccit+))))
  63. ;;; the modes
  64. (defconstant +mode-extension-0+ 0)
  65. (defconstant +mode-extension-1+ 1)
  66. (defconstant +mode-extension-2+ 2)
  67. (defconstant +mode-extension-3+ 3)
  68. (defun get-mode-extension-string (channel-mode layer mode-extension)
  69. (declare #.utils:*standard-optimize-settings*)
  70. (if (not (= channel-mode +channel-mode-joint+))
  71. ""
  72. (if (or (= layer +layer-1+)
  73. (= layer +layer-2+))
  74. (format nil "Bands ~[4~;8~;12~;16~] to 31" mode-extension)
  75. (format nil "Intensity Stereo: ~[off~;on~], MS Stereo: ~[off~;on~]" (ash mode-extension -1) (logand mode-extension 1)))))
  76. (defun get-samples-per-frame (version layer)
  77. (declare #.utils:*standard-optimize-settings*)
  78. (cond ((= (the fixnum layer) (the fixnum +layer-1+)) 384)
  79. ((= (the fixnum layer) (the fixnum +layer-2+)) 1152)
  80. ((= (the fixnum layer) (the fixnum +layer-3+))
  81. (cond ((= (the fixnum version) +mpeg-1+) 1152)
  82. ((or (= (the fixnum version) (the fixnum +mpeg-2+))
  83. (= (the fixnum version) (the fixnum +mpeg-2.5+))) 576)))))
  84. (defclass frame ()
  85. ((pos :accessor pos :initarg :pos)
  86. (hdr-u32 :accessor hdr-u32 :initarg :hdr-u32)
  87. (samples :accessor samples :initarg :samples)
  88. (sync :accessor sync :initarg :sync)
  89. (version :accessor version :initarg :version)
  90. (layer :accessor layer :initarg :layer)
  91. (protection :accessor protection :initarg :protection)
  92. (bit-rate :accessor bit-rate :initarg :bit-rate)
  93. (sample-rate :accessor sample-rate :initarg :sample-rate)
  94. (padded :accessor padded :initarg :padded)
  95. (private :accessor private :initarg :private)
  96. (channel-mode :accessor channel-mode :initarg :channel-mode)
  97. (mode-extension :accessor mode-extension :initarg :mode-extension)
  98. (copyright :accessor copyright :initarg :copyright)
  99. (original :accessor original :initarg :original)
  100. (emphasis :accessor emphasis :initarg :emphasis)
  101. (size :accessor size :initarg :size)
  102. (vbr :accessor vbr :initarg :vbr)
  103. (payload :accessor payload :initarg :payload))
  104. (:documentation "Data in and associated with an MPEG audio frame.")
  105. (:default-initargs :pos nil :hdr-u32 nil :samples 0 :sync 0 :version 0 :layer 0 :protection 0 :bit-rate 0
  106. :sample-rate 0 :padded 0 :private 0 :channel-mode 0 :mode-extension 0
  107. :copyright 0 :original 0 :emphasis 0 :size nil :vbr nil :payload nil))
  108. (defmacro with-frame-slots ((instance) &body body)
  109. `(with-slots (pos hdr-u32 samples sync version layer protection bit-rate sample-rate
  110. padded private channel-mode mode-extension copyright
  111. original emphasis size vbr payload) ,instance
  112. ,@body))
  113. (let ((bit-array-table
  114. (make-array '(14 5) :initial-contents
  115. '((32 32 32 32 8)
  116. (64 48 40 48 16)
  117. (96 56 48 56 24)
  118. (128 64 56 64 32)
  119. (160 80 64 80 40)
  120. (192 96 80 96 48)
  121. (224 112 96 112 56)
  122. (256 128 112 128 64)
  123. (288 160 128 144 80)
  124. (320 192 160 160 96)
  125. (352 224 192 176 112)
  126. (384 256 224 192 128)
  127. (416 320 256 224 144)
  128. (448 384 320 256 160)))))
  129. (defun valid-bit-rate-index (br-index)
  130. (declare #.utils:*standard-optimize-settings*)
  131. (and (> (the fixnum br-index) 0) (< (the fixnum br-index) 15)))
  132. (defun get-bit-rate (version layer bit-rate-index)
  133. (declare #.utils:*standard-optimize-settings*)
  134. (log5:with-context "get-bit-rate"
  135. (log-mpeg-frame "version = ~d, layer = ~d, bit-rate-index = ~d" version layer bit-rate-index)
  136. (let ((row (1- bit-rate-index))
  137. (col (cond ((= (the fixnum version) (the fixnum +mpeg-1+))
  138. (cond ((= (the fixnum layer) (the fixnum +layer-1+)) 0)
  139. ((= (the fixnum layer) (the fixnum +layer-2+)) 1)
  140. ((= (the fixnum layer) (the fixnum +layer-3+)) 2)
  141. (t nil)))
  142. ((= (the fixnum version) (the fixnum +mpeg-2+))
  143. (cond ((= (the fixnum layer) (the fixnum +layer-1+)) 3)
  144. ((= (the fixnum layer) (the fixnum +layer-2+)) 4)
  145. ((= (the fixnum layer) (the fixnum +layer-3+)) 4)
  146. (t nil)))
  147. (t (error "don't support MPEG 2.5 yet")))))
  148. (log-mpeg-frame "version = ~d, row = ~d, col = ~d" version row col)
  149. (if (or (null col) (< row 0) (> row 14))
  150. nil
  151. (let ((ret (* 1000 (aref bit-array-table row col))))
  152. (log-mpeg-frame "returning ~:d" ret)
  153. ret))))))
  154. (defun valid-sample-rate-index (sr-index)
  155. (declare #.utils:*standard-optimize-settings*)
  156. (and (>= (the fixnum sr-index) 0)
  157. (< (the fixnum sr-index) 3)))
  158. (defun get-sample-rate (version sr-index)
  159. (declare #.utils:*standard-optimize-settings*)
  160. (cond ((= (the fixnum version) (the fixnum +mpeg-1+))
  161. (case (the fixnum sr-index) (0 44100) (1 48000) (2 32000)))
  162. ((= (the fixnum version) (the fixnum +mpeg-2+))
  163. (case (the fixnum sr-index) (0 22050) (1 24000) (2 16000)))
  164. (t nil)))
  165. (defun get-frame-size (version layer bit-rate sample-rate padded)
  166. (declare #.utils:*standard-optimize-settings*)
  167. (truncate (float (cond ((= (the fixnum layer) (the fixnum +layer-1+))
  168. (* 4 (+ (/ (* 12 bit-rate) sample-rate) padded)))
  169. ((= (the fixnum layer) (the fixnum +layer-2+))
  170. (+ (* 144 (/ bit-rate sample-rate)) padded))
  171. ((= (the fixnum layer) (the fixnum +layer-3+))
  172. (if (= (the fixnum version) (the fixnum +mpeg-1+))
  173. (+ (* 144 (/ bit-rate sample-rate)) padded)
  174. (+ (* 72 (/ bit-rate sample-rate)) padded)))))))
  175. (defmethod load-frame ((me frame) &key instream (read-payload nil))
  176. "Load an MPEG frame from current file position. If READ-PAYLOAD is set, read in frame's content."
  177. (declare #.utils:*standard-optimize-settings*)
  178. (declare #.utils:*standard-optimize-settings*)
  179. (log5:with-context "load-frame"
  180. (handler-case
  181. (with-frame-slots (me)
  182. (log-mpeg-frame "loading frame from pos ~:d" (stream-seek instream))
  183. (when (null hdr-u32) ; has header already been read in?
  184. (log-mpeg-frame "reading in header")
  185. (setf pos (stream-seek instream))
  186. (setf hdr-u32 (stream-read-u32 instream))
  187. (when (null hdr-u32)
  188. (log-mpeg-frame "hit EOF")
  189. (return-from load-frame nil)))
  190. (if (parse-header me)
  191. (progn
  192. (log-mpeg-frame "header parsed ok")
  193. (setf size (get-frame-size version layer bit-rate sample-rate padded))
  194. (when read-payload
  195. (setf payload (stream-read-sequence instream (- size 4))))
  196. t)
  197. (progn
  198. (log-mpeg-frame "header didn't parse!")
  199. nil)))
  200. (end-of-file (c)
  201. (declare (ignore c))
  202. (log-mpeg-frame "Hit EOF")
  203. nil))))
  204. (defmethod parse-header ((me frame))
  205. "Given a frame, verify that is a valid MPEG audio frame by examining the header.
  206. A header looks like this:
  207. Bits 31-21 (11 bits): the sync word. Must be #xffe (NB version 2.5 standard)
  208. Bits 20-19 (2 bits): the version
  209. Bits 18-17 (2 bits): the layer
  210. Bit 16 (1 bit ): the protection bit
  211. Bits 15-12 (4 bits): the bit-rate index
  212. Bits 11-10 (2 bits): the sample-rate index
  213. Bit 9 (1 bit ): the padding bit
  214. Bit 8 (1 bit ): the private bit
  215. Bits 7-6 (2 bits): the channel mode
  216. Bits 5-4 (2 bits): the mode extension
  217. Bit 3 (1 bit ): the copyright bit
  218. Bit 2 (1 bit ): the original bit
  219. Bits 1-0 (2 bits): the emphasis"
  220. (declare #.utils:*standard-optimize-settings*)
  221. (log5:with-context "parse-header"
  222. (with-frame-slots (me)
  223. ;; check sync word
  224. (setf sync (get-bitfield hdr-u32 31 11))
  225. ;(setf (ldb (byte 8 8) sync) (ldb (byte 8 24) hdr-u32))
  226. ;(setf (ldb (byte 3 5) sync) (ldb (byte 3 5) (ldb (byte 8 16) hdr-u32)))
  227. (when (not (= sync +sync-word+))
  228. (log-mpeg-frame "bad sync ~x/~x" sync hdr-u32)
  229. (return-from parse-header nil))
  230. ;; check version
  231. ;(setf version (ldb (byte 2 3) (ldb (byte 8 16) hdr-u32)))
  232. (setf version (get-bitfield hdr-u32 20 2))
  233. (when (not (valid-version version))
  234. (log-mpeg-frame "bad version ~d" version)
  235. (return-from parse-header nil))
  236. ;; check layer
  237. ;(setf layer (ldb (byte 2 1) (ldb (byte 8 16) hdr-u32)))
  238. (setf layer (get-bitfield hdr-u32 18 2))
  239. (when (not (valid-layer layer))
  240. (log-mpeg-frame "bad layer ~d" layer)
  241. (return-from parse-header nil))
  242. ;(setf protection (ldb (byte 1 0) (ldb (byte 8 16) hdr-u32)))
  243. (setf protection (get-bitfield hdr-u32 16 1))
  244. (setf samples (get-samples-per-frame version layer))
  245. ;; check bit-rate
  246. ;(let ((br-index (the fixnum (ldb (byte 4 4) (ldb (byte 8 8) hdr-u32)))))
  247. (let ((br-index (get-bitfield hdr-u32 15 4)))
  248. (when (not (valid-bit-rate-index br-index))
  249. (log-mpeg-frame "bad bit-rate index ~d" br-index)
  250. (return-from parse-header nil))
  251. (setf bit-rate (get-bit-rate version layer br-index)))
  252. ;; check sample rate
  253. ;(let ((sr-index (the fixnum (ldb (byte 2 2) (ldb (byte 8 8) hdr-u32)))))
  254. (let ((sr-index (get-bitfield hdr-u32 11 2)))
  255. (when (not (valid-sample-rate-index sr-index))
  256. (log-mpeg-frame "bad sample-rate index ~d" sr-index)
  257. (return-from parse-header nil))
  258. (setf sample-rate (get-sample-rate version sr-index)))
  259. ;(setf padded (ldb (byte 1 1) (ldb (byte 8 8) hdr-u32)))
  260. (setf padded (get-bitfield hdr-u32 9 1))
  261. ;(setf private (ldb (byte 1 0) (ldb (byte 8 8) hdr-u32)))
  262. (setf private (get-bitfield hdr-u32 8 1))
  263. ;(setf channel-mode (ldb (byte 2 6) (ldb (byte 8 0) hdr-u32)))
  264. (setf channel-mode (get-bitfield hdr-u32 7 2))
  265. ;(setf mode-extension (ldb (byte 2 4) (ldb (byte 8 0) hdr-u32)))
  266. (setf mode-extension (get-bitfield hdr-u32 5 2))
  267. ;(setf copyright (ldb (byte 1 3) (ldb (byte 8 0) hdr-u32)))
  268. (setf copyright (get-bitfield hdr-u32 3 1))
  269. ;(setf original (ldb (byte 1 2) (ldb (byte 8 0) hdr-u32)))
  270. (setf original (get-bitfield hdr-u32 2 1))
  271. ;(setf emphasis (ldb (byte 2 0) (ldb (byte 8 0) hdr-u32)))
  272. (setf emphasis (get-bitfield hdr-u32 1 2))
  273. ;; check emphasis
  274. (when (not (valid-emphasis emphasis))
  275. (log-mpeg-frame "bad emphasis ~d" emphasis)
  276. (return-from parse-header nil))
  277. (log-mpeg-frame "good parse: ~a" me)
  278. t)))
  279. (defmethod vpprint ((me frame) stream)
  280. (format stream "~a"
  281. (with-output-to-string (s)
  282. (with-frame-slots (me)
  283. (format s "MPEG Frame: position in file = ~:d, header in (hex) bytes = ~x, size = ~d, sync word = ~x, " pos hdr-u32 size sync)
  284. (when vbr
  285. (format s "~&vbr-info: ~a~%" vbr))
  286. (format s "version = ~a, layer = ~a, crc protected? = ~[yes~;no~], bit-rate = ~:d bps, sampling rate = ~:d bps, padded? = ~[no~;yes~], private bit set? = ~[no~;yes~], channel mode = ~a, "
  287. (get-mpeg-version-string version) (get-layer-string layer)
  288. protection bit-rate sample-rate padded private (get-channel-mode-string channel-mode))
  289. (format s "mode extension = ~a, copyrighted? = ~[no~;yes~], original? = ~[no~;yes~], emphasis = ~a"
  290. (get-mode-extension-string channel-mode layer mode-extension) copyright original (get-emphasis-string emphasis))
  291. (when payload
  292. (format s "~%frame payload[~:d] = ~a~%" (length payload) (utils:printable-array payload)))))))
  293. (defclass vbr-info ()
  294. ((tag :accessor tag :initarg :tag)
  295. (flags :accessor flags :initarg :flags)
  296. (frames :accessor frames :initarg :frames)
  297. (bytes :accessor bytes :initarg :bytes)
  298. (tocs :accessor tocs :initarg :tocs)
  299. (scale :accessor scale :initarg :scale))
  300. (:default-initargs :tag nil :flags 0 :frames nil :bytes nil :tocs nil :scale nil))
  301. (defmacro with-vbr-info-slots ((instance) &body body)
  302. `(with-slots (tag flags frames bytes tocs scale) ,instance
  303. ,@body))
  304. (defconstant +vbr-frames+ 1)
  305. (defconstant +vbr-bytes+ 2)
  306. (defconstant +vbr-tocs+ 4)
  307. (defconstant +vbr-scale+ 8)
  308. (defun get-side-info-size (version channel-mode)
  309. (declare #.utils:*standard-optimize-settings*)
  310. (cond ((= (the fixnum version) (the fixnum +mpeg-1+))
  311. (cond ((= (the fixnum channel-mode) (the fixnum +channel-mode-mono+)) 17)
  312. (t 32)))
  313. (t (cond ((= (the fixnum channel-mode) (the fixnum +channel-mode-mono+)) 9)
  314. (t 17)))))
  315. (defmethod check-vbr ((me frame) fn)
  316. (declare #.utils:*standard-optimize-settings*)
  317. (log5::with-context "check-vbr"
  318. (with-frame-slots (me)
  319. (let ((i (get-side-info-size version channel-mode)))
  320. (log-mpeg-frame "array index = ~d, payload size = ~d" i (length payload))
  321. (when (>= i (length payload))
  322. (return-from check-vbr nil))
  323. (when (or (and (= (aref payload (+ i 0)) (char-code #\X))
  324. (= (aref payload (+ i 1)) (char-code #\i))
  325. (= (aref payload (+ i 2)) (char-code #\n))
  326. (= (aref payload (+ i 3)) (char-code #\g)))
  327. (and (= (aref payload (+ i 0)) (char-code #\I))
  328. (= (aref payload (+ i 1)) (char-code #\n))
  329. (= (aref payload (+ i 2)) (char-code #\f))
  330. (= (aref payload (+ i 3)) (char-code #\o))))
  331. (log-mpeg-frame "found xing/info: ~c ~c ~c ~c"
  332. (code-char (aref payload (+ i 0)))
  333. (code-char (aref payload (+ i 1)))
  334. (code-char (aref payload (+ i 2)))
  335. (code-char (aref payload (+ i 3))))
  336. (setf vbr (make-instance 'vbr-info))
  337. (let ((v (make-mem-stream (payload me))))
  338. (stream-seek v i :start) ; seek to Xing/Info offset
  339. (setf (tag vbr) (stream-read-iso-string-with-len v 4))
  340. (setf (flags vbr) (stream-read-u32 v))
  341. (when (logand (flags vbr) +vbr-frames+)
  342. (setf (frames vbr) (stream-read-u32 v))
  343. (log-mpeg-frame "Xing frames set: read ~d" (frames vbr))
  344. (when (zerop (frames vbr))
  345. (warn-user "warning file ~a Xing/Info header flags has FRAMES set, but field is zero." fn)))
  346. (when (logand (flags vbr) +vbr-bytes+)
  347. (setf (bytes vbr) (stream-read-u32 v))
  348. (log-mpeg-frame "Xing bytes set: read ~d" (bytes vbr)))
  349. (when (logand (flags vbr) +vbr-tocs+)
  350. (setf (tocs vbr) (stream-read-sequence v 100))
  351. (log-mpeg-frame "Xing tocs set: read ~a" (tocs vbr)))
  352. (when (logand (flags vbr) +vbr-scale+)
  353. (setf (scale vbr) (stream-read-u32 v))
  354. (log-mpeg-frame "Xing scale set: read ~d" (scale vbr)))
  355. (log-mpeg-frame "vbr-info = ~a" (vpprint vbr nil))))))))
  356. (defmethod vpprint ((me vbr-info) stream)
  357. (with-vbr-info-slots (me)
  358. (format stream "tag = ~a, flags = 0x~x, frame~p = ~:d, bytes = ~:d, tocs = ~d, scale = ~d, "
  359. tag flags frames frames bytes tocs scale)))
  360. (defun find-first-sync (in)
  361. (declare #.utils:*standard-optimize-settings*)
  362. (log5:with-context "find-first-sync"
  363. (log-mpeg-frame "Looking for first sync, begining at file position ~:d" (stream-seek in))
  364. (let ((hdr-u32)
  365. (count 0)
  366. (pos))
  367. (handler-case
  368. (loop
  369. (setf pos (stream-seek in))
  370. (setf hdr-u32 (stream-read-u32 in))
  371. (when (null hdr-u32)
  372. (return-from find-first-sync nil))
  373. (incf count)
  374. (when (= (logand hdr-u32 #xffe00000) #xffe00000) ; magic number is potential sync frame header
  375. (log-mpeg-frame "Potential sync bytes at ~:d: <~x>" pos hdr-u32)
  376. (let ((hdr (make-instance 'frame :hdr-u32 hdr-u32 :pos pos)))
  377. (if (load-frame hdr :instream in :read-payload t)
  378. (progn
  379. (check-vbr hdr (stream-filename in))
  380. (log-mpeg-frame "Valid header being returned: ~a, searched ~:d times" hdr count)
  381. (return-from find-first-sync hdr))
  382. (progn
  383. (log-mpeg-frame "hdr wasn't valid: ~a" hdr))))))
  384. (condition (c) (progn
  385. (warn-user "Condtion <~a> signaled while looking for first sync" c)
  386. (log-mpeg-frame "got a condition while looking for first sync: ~a" c)
  387. (error c)))) ; XXX should I propogate this, or just return nil
  388. nil)))
  389. (defmethod next-frame ((me frame) &key instream read-payload)
  390. "Get next frame. If READ-PAYLOAD is true, read in contents for frame, else, seek to next frame header."
  391. (declare #.utils:*standard-optimize-settings*)
  392. (log5:with-context "next-frame"
  393. (let ((nxt-frame (make-instance 'frame)))
  394. (when (not (payload me))
  395. (log-mpeg-frame "no payload load required in current frame, skipping from ~:d forward ~:d bytes"
  396. (stream-seek instream)
  397. (- (size me) 4) :current)
  398. (stream-seek instream (- (size me) 4) :current))
  399. (log-mpeg-frame "at pos ~:d, read-payload is ~a" (stream-seek instream) read-payload)
  400. (if (load-frame nxt-frame :instream instream :read-payload read-payload)
  401. nxt-frame
  402. nil))))
  403. (defparameter *max-frames-to-read* most-positive-fixnum "when trying to determine bit-rate, etc, read at most this many frames")
  404. (defun map-frames (in func &key (start-pos nil) (read-payload nil) (max nil))
  405. "Loop through the MPEG audio frames in a file. If *MAX-FRAMES-TO-READ* is set, return after reading that many frames."
  406. (declare #.utils:*standard-optimize-settings*)
  407. (log5:with-context "next-frame"
  408. (log-mpeg-frame "mapping frames, start pos ~:d" start-pos)
  409. (when start-pos
  410. (stream-seek in start-pos :start))
  411. (loop
  412. for max-frames = (if max max *max-frames-to-read*)
  413. for count = 0 then (incf count)
  414. for frame = (find-first-sync in) then (next-frame frame :instream in :read-payload read-payload)
  415. while (and frame (< count max-frames)) do
  416. (log-mpeg-frame "map-frames: at pos ~:d, dispatching function" (pos frame))
  417. (funcall func frame))))
  418. (defclass mpeg-audio-info ()
  419. ((is-vbr :accessor is-vbr :initarg :is-vbr :initform nil)
  420. (n-frames :accessor n-frames :initarg :n-frames :initform 0)
  421. (bit-rate :accessor bit-rate :initarg :bit-rate :initform nil)
  422. (sample-rate :accessor sample-rate :initarg :sample-rate :initform nil)
  423. (len :accessor len :initarg :len :initform nil)
  424. (version :accessor version :initarg :version :initform nil)
  425. (layer :accessor layer :initarg :layer :initform nil)))
  426. (defmethod vpprint ((me mpeg-audio-info) stream)
  427. (with-slots (is-vbr sample-rate bit-rate len version layer n-frames) me
  428. (format stream "~:d frame~p read, ~a, ~a, ~:[CBR,~;VBR,~] sample rate: ~:d Hz, bit rate: ~:d Kbps, duration: ~:d:~2,'0d"
  429. n-frames n-frames
  430. (get-mpeg-version-string version)
  431. (get-layer-string layer)
  432. is-vbr
  433. sample-rate
  434. (round (/ bit-rate 1000))
  435. (floor (/ len 60)) (round (mod len 60)))))
  436. (defun calc-bit-rate-exhaustive (in start info)
  437. "Map every MPEG frame in IN and calculate the bit-rate"
  438. (declare #.utils:*standard-optimize-settings*)
  439. (log5:with-context "calc-bit-rate-exhaustive"
  440. (let ((total-len 0)
  441. (last-bit-rate nil)
  442. (bit-rate-total 0)
  443. (vbr nil))
  444. (log-mpeg-frame "broken Xing/Info header found, reading all frames")
  445. (with-slots (is-vbr sample-rate bit-rate len version layer n-frames) info
  446. (map-frames in (lambda (f)
  447. (incf n-frames)
  448. (incf total-len (float (/ (samples f) (sample-rate f))))
  449. (incf bit-rate-total (bit-rate f))
  450. (if (null last-bit-rate)
  451. (setf last-bit-rate (bit-rate f))
  452. (progn
  453. (when (not (= last-bit-rate (bit-rate f)))
  454. (setf vbr t))
  455. (setf last-bit-rate (bit-rate f)))))
  456. :read-payload nil :start-pos start)
  457. (log-mpeg-frame "finished mapping. read ~:d frames" n-frames)
  458. (when (or (< n-frames 10) (zerop bit-rate-total))
  459. (log-mpeg-frame "couldn't get audio-info: only got ~d frames" n-frames)
  460. (return-from calc-bit-rate-exhaustive))
  461. (setf is-vbr t)
  462. (setf len total-len)
  463. (setf bit-rate (float (/ bit-rate-total n-frames)))
  464. (log-mpeg-frame "len = ~:d, bit-rate = ~f" len bit-rate)))))
  465. (defun get-mpeg-audio-info (in &key) ;; (max-frames *max-frames-to-read*))
  466. "Get MPEG Layer 3 audio information.
  467. If the first MPEG frame we find is a Xing/Info header, return that as info.
  468. Else, we assume CBR and calculate the duration, etc."
  469. (declare #.utils:*standard-optimize-settings*)
  470. (log5:with-context "get-mpeg-audio-info"
  471. (let ((first-frame (find-first-sync in))
  472. (info (make-instance 'mpeg-audio-info)))
  473. (log-mpeg-frame "search for first frame yielded ~a" (vpprint first-frame nil))
  474. (when (null first-frame)
  475. (return-from get-mpeg-audio-info nil))
  476. (with-slots (is-vbr sample-rate bit-rate len version layer n-frames) info
  477. (setf version (version first-frame))
  478. (setf layer (layer first-frame))
  479. (setf sample-rate (sample-rate first-frame))
  480. (if (vbr first-frame)
  481. ;; found a Xing header, now check to see if it is correct
  482. (if (zerop (frames (vbr first-frame)))
  483. (calc-bit-rate-exhaustive in (pos first-frame) info) ; Xing header broken, read all frames to calc
  484. ;; Good Xing header, use info in VBR to calc
  485. (progn
  486. (setf n-frames 1)
  487. (setf is-vbr t)
  488. (setf len (float (* (frames (vbr first-frame)) (/ (samples first-frame) (sample-rate first-frame)))))
  489. (setf bit-rate (float (/ (* 8 (bytes (vbr first-frame))) len)))))
  490. ;; No Xing header found. Assume CBR and calculate based on first frame
  491. (let* ((first (pos first-frame))
  492. (last (- (audio-streams:stream-size in) (if (id3-frame::v21-tag-header (id3-header in)) 128 0)))
  493. (n-fr (round (/ (float (- last first)) (float (size first-frame)))))
  494. (n-sec (round (/ (float (* (size first-frame) n-fr)) (float (* 125 (float (/ (bit-rate first-frame) 1000))))))))
  495. (setf is-vbr nil)
  496. (setf n-frames 1)
  497. (setf len n-sec)
  498. (setf bit-rate (float (bit-rate first-frame))))))
  499. info)))