anchor.diff:  (defgeneric decode-media-stream (record fsize input-stream))
   
   (defmethod decode-media-stream ((rec stream-record) fsize input-stream)
  -  (read-sequence (frame (car (wcursor rec))) input-stream :end fsize))
  -
  -(defmethod decode-media-stream ((rec audio-stream-record) fsize input-stream)
  -  (let* ((chunk (pop (wcursor rec)))
  -	 (cur-lock (vacancy-lock chunk))
  -	 (new-chunk (car (wcursor rec))))
  -    (bt:acquire-lock (vacancy-lock new-chunk))
  -    (read-sequence (frame chunk) input-stream :end fsize)
  -    (bt:release-lock cur-lock)))
  -
  -(defmethod decode-media-stream ((rec mjpeg-stream-record) fsize input-stream)
  -  (let* ((chunk (pop (wcursor rec)))
  -	 (cur-lock (vacancy-lock chunk))
  -	 (new-chunk (car (wcursor rec))))
  -    (bt:acquire-lock (vacancy-lock new-chunk))
  -    (read-sequence (jpeg:descriptor-source-cache (jpeg-descriptor rec)) input-stream :end fsize)
  -    (jpeg:decode-stream nil :buffer (frame chunk)
  -			:descriptor (jpeg-descriptor rec)
  -			:cached-source-p t)
  -    (bt:release-lock cur-lock)))
  -
  -(defmethod initialize-instance :after ((s avi-mjpeg-stream) &key &allow-other-keys)
  -  (setf (chunk-decoder s) #'(lambda (stream id size)
  -			      (if (member (subseq id 2) '("dc" "wb") :test #'string-equal)
  -				  (progn (decode-media-stream (elt (stream-records s) (parse-integer (subseq id 0 2))) size stream)
  -					 (when (plusp (padding s)) (loop repeat (rem size (padding s)) do (read-byte s))))
  -				  (read-sequence (make-array size :element-type '(unsigned-byte 8)) stream)))))
  +  (read-sequence (frame (ar (wcursor rec))) input-stream :end fsize))
   
   (defgeneric decode (stream)
     (:documentation "Decodes the video stream"))
   
  -(defmethod read-avi-stream-info ((avi avi-mjpeg-stream) stream)
  -  (loop for chunk = (riff:read-riff-chunk stream)
  -     with rec = (make-instance 'stream-record :avi avi)
  -     when (string-equal (riff:riff-chunk-id chunk) "strh") do
  -       (flexi-streams:with-input-from-sequence (is (riff:riff-chunk-data chunk))
  -	 (setf (fcc-type rec) (riff::read-fourcc is)
  -	       (fcc-handler rec) (riff::read-fourcc is)
  -	       (flags rec) (riff:read-u4 is)
  -	       (priority rec) (riff:read-u2 is)
  -	       (language rec) (riff:read-u2 is)
  -	       (initial-frames rec) (riff:read-u4 is)
  -	       (scale rec) (riff:read-u4 is)
  -	       (rate rec) (riff:read-u4 is)
  -	       (start rec) (riff:read-u4 is)
  -	       (stream-length rec) (riff:read-u4 is)
  -	       (suggested-buffer-size rec) (riff:read-u4 is)
  -	       (quality rec) (riff:read-u4 is)
  -	       (sample-size rec) (riff:read-u4 is)
  -	       (frame rec) (list (riff:read-u2 is) (riff:read-u2 is) (riff:read-u2 is) (riff:read-u2 is))))
  -       (when (and (string-equal (fcc-type rec) "vids") (not (member (fcc-handler rec) '("mjpg") :test #'string-equal)))
  -	 (error 'unsupported-avi-file-format))
  -       (cond ((and (string-equal (fcc-type rec) "vids") (string-equal (fcc-handler rec) "mjpg"))
  -	      (change-class rec 'mjpeg-stream-record))
  -	     ((string-equal (fcc-type rec) "auds") (change-class rec 'audio-stream-record) (read-audio-stream-header rec stream)))
  -       (return-from read-avi-stream-info rec))
  -  (error 'malformed-avi-file-format))
  -
  -(defmethod read-avi-header ((avi avi-mjpeg-stream) stream)
  -  (loop for chunk = (riff:read-riff-chunk stream)
  -     when (string-equal (riff:riff-chunk-id chunk) "avih") do
  -       (flexi-streams:with-input-from-sequence (is (riff:riff-chunk-data chunk))
  -	 (riff:read-u4 is)   ;;dwMicroSecPerFrame
  -	 (riff:read-u4 is)   ;;dwMaxBytesPerSec
  -	 (setf (padding avi) (riff:read-u4 is)
  -	       (flags avi) (riff:read-u4 is))
  -	 (unless (zerop (logand (flags avi) +avif-must-use-index+))
  -	   (debug-log (format nil "CL-VIDEO WARNING: must use index flag is set, frame order is possibly incorrect~%")))
  -	 (riff:read-u4 is)   ;;dwTotalFrames
  -	 (riff:read-u4 is)   ;;dwInitialFrames
  -	 (setf (nstreams avi) (riff:read-u4 is))
  -	 (riff:read-u4 is) ;;dwSuggestedBufferSize
  -	 (setf (width avi) (riff:read-u4 is)
  -	       (height avi) (riff:read-u4 is))
  -	 (riff:read-u4 is) (riff:read-u4 is) (riff:read-u4 is) (riff:read-u4 is))
  -       (setf (stream-records avi)
  -	     (loop repeat (nstreams avi) collecting (read-avi-stream-info avi stream)))
  -       (return)))
  -
  -(defmethod find-mjpeg-stream-record ((avi avi-mjpeg-stream))
  -  (find-if #'(lambda (x) (eql (type-of x) 'mjpeg-stream-record)) (stream-records avi)))
  -
  -(defmethod find-pcm-stream-record ((avi avi-mjpeg-stream))
  -  (find-if #'(lambda (x) (and (eql (type-of x) 'audio-stream-record)
  -			      (eql (compression-code x) +pcmi-uncompressed+))) (stream-records avi)))
  -
  -(defmethod prime-all-streams ((avi avi-mjpeg-stream))
  +(defmethod prime-all-streams ((c av-container))
     ;; the playback shouldn't start before 1st frame is decoded
  -  (loop for rec in (stream-records avi) do
  +  (loop for rec in (stream-records c) do
          (bt:acquire-lock (vacancy-lock (car (wcursor rec))))))
   
  -
  -(defmethod decode ((avi avi-mjpeg-stream))
  -  (with-open-file (stream (filename avi) :direction :input :element-type '(unsigned-byte 8))
  -    ;; read AVI header first
  -    (let* ((chunk (riff:read-riff-chunk stream))
  -	   (id (getf chunk :chunk-id))
  -	   (fourcc (getf chunk :file-type)))
  -      (unless (string-equal id "riff")
  -	(error 'unrecognized-file-format))
  -      (cond ((string-equal fourcc "avi ") (read-avi-header avi stream))
  -	    (t (error 'unsupported-avi-file-format))))
  -    (when (player-callback avi)
  -      (funcall (player-callback avi) avi))
  -    (loop for chunk = (riff:read-riff-chunk stream :chunk-data-reader (chunk-decoder avi))
  -       while (and chunk (not (finish avi))))
  -    (loop for rec in (stream-records avi) do 
  -	 (setf (final rec) (car (wcursor rec)))
  -	 (bt:release-lock (vacancy-lock (car (wcursor rec)))))))
  -
  -(defun decode-file (pathname &key player-callback)
  -  (let ((avi-stream (make-instance 'avi-mjpeg-stream :filename pathname :player-callback player-callback)))
  -    (decode avi-stream)))
  -
  -(defun show-file-chunks (pathname)
  -  (with-open-file (stream pathname :direction :input :element-type '(unsigned-byte 8))
  -    (loop for chunk = (riff:read-riff-chunk stream)
  -	 while chunk do (format t "~A size ~D~%" (riff:riff-chunk-id chunk) (riff:riff-chunk-data-size chunk)))))
  +(defmethod find-video-stream-record ((c av-container))
  +  (find-if #'(lambda (x) (typep x 'video-stream-record)) (stream-records c)))
  
positive.code: (in-package #:cl-video)
  
  (setf *print-circle* t)
  
  (define-constant +avif-must-use-index+ #x20) 
  
  (define-constant  +pcmi-uncompressed+ 1)
  
  (define-constant +avi-dht+
      #(#x01 #xA2 
        #x00 #x00 #x01 #x05 #x01 #x01 #x01 #x01 #x01 #x01 #x00 #x00 #x00 #x00 #x00 
        #x00 #x00 #x00 #x01 #x02 #x03 #x04 #x05 #x06 #x07 #x08 #x09 #x0A #x0B #x01 
        #x00 #x03 #x01 #x01 #x01 #x01 #x01 #x01 #x01 #x01 #x01 #x00 #x00 #x00 #x00 
   
        #x00 #x00 #x01 #x02 #x03 #x04 #x05 #x06 #x07 #x08 #x09 #x0A #x0B #x10 #x00 
        #x02 #x01 #x03 #x03 #x02 #x04 #x03 #x05 #x05 #x04 #x04 #x00 #x00 #x01 #x7D 
        #x01 #x02 #x03 #x00 #x04 #x11 #x05 #x12 #x21 #x31 #x41 #x06 #x13 #x51 #x61 
        #x07 #x22 #x71 #x14 #x32 #x81 #x91 #xA1 #x08 #x23 #x42 #xB1 #xC1 #x15 #x52 
        #xD1 #xF0 #x24 #x33 #x62 #x72 #x82 #x09 #x0A #x16 #x17 #x18 #x19 #x1A #x25 
        #x26 #x27 #x28 #x29 #x2A #x34 #x35 #x36 #x37 #x38 #x39 #x3A #x43 #x44 #x45 
        #x46 #x47 #x48 #x49 #x4A #x53 #x54 #x55 #x56 #x57 #x58 #x59 #x5A #x63 #x64 
   
        #x65 #x66 #x67 #x68 #x69 #x6A #x73 #x74 #x75 #x76 #x77 #x78 #x79 #x7A #x83 
        #x84 #x85 #x86 #x87 #x88 #x89 #x8A #x92 #x93 #x94 #x95 #x96 #x97 #x98 #x99 
        #x9A #xA2 #xA3 #xA4 #xA5 #xA6 #xA7 #xA8 #xA9 #xAA #xB2 #xB3 #xB4 #xB5 #xB6 
        #xB7 #xB8 #xB9 #xBA #xC2 #xC3 #xC4 #xC5 #xC6 #xC7 #xC8 #xC9 #xCA #xD2 #xD3 
        #xD4 #xD5 #xD6 #xD7 #xD8 #xD9 #xDA #xE1 #xE2 #xE3 #xE4 #xE5 #xE6 #xE7 #xE8 
        #xE9 #xEA #xF1 #xF2 #xF3 #xF4 #xF5 #xF6 #xF7 #xF8 #xF9 #xFA #x11 #x00 #x02 
        #x01 #x02 #x04 #x04 #x03 #x04 #x07 #x05 #x04 #x04 #x00 #x01 #x02 #x77 #x00 
   
        #x01 #x02 #x03 #x11 #x04 #x05 #x21 #x31 #x06 #x12 #x41 #x51 #x07 #x61 #x71 
        #x13 #x22 #x32 #x81 #x08 #x14 #x42 #x91 #xA1 #xB1 #xC1 #x09 #x23 #x33 #x52 
        #xF0 #x15 #x62 #x72 #xD1 #x0A #x16 #x24 #x34 #xE1 #x25 #xF1 #x17 #x18 #x19 
        #x1A #x26 #x27 #x28 #x29 #x2A #x35 #x36 #x37 #x38 #x39 #x3A #x43 #x44 #x45 
        #x46 #x47 #x48 #x49 #x4A #x53 #x54 #x55 #x56 #x57 #x58 #x59 #x5A #x63 #x64 
        #x65 #x66 #x67 #x68 #x69 #x6A #x73 #x74 #x75 #x76 #x77 #x78 #x79 #x7A #x82 
        #x83 #x84 #x85 #x86 #x87 #x88 #x89 #x8A #x92 #x93 #x94 #x95 #x96 #x97 #x98 
   
        #x99 #x9A #xA2 #xA3 #xA4 #xA5 #xA6 #xA7 #xA8 #xA9 #xAA #xB2 #xB3 #xB4 #xB5 
        #xB6 #xB7 #xB8 #xB9 #xBA #xC2 #xC3 #xC4 #xC5 #xC6 #xC7 #xC8 #xC9 #xCA #xD2 
        #xD3 #xD4 #xD5 #xD6 #xD7 #xD8 #xD9 #xDA #xE2 #xE3 #xE4 #xE5 #xE6 #xE7 #xE8 
        #xE9 #xEA #xF2 #xF3 #xF4 #xF5 #xF6 #xF7 #xF8 #xF9 #xFA)
    :test #'equalp)
  
  (defvar *debug* nil)
  
  
negative.code:   ()
    (:report (lambda (condition stream)
  	     (declare (ignorable condition))
  	     (format stream "Unrecognized file format"))))
  
  (defclass chunk ()
    ((lock :reader vacancy-lock :initform (bt:make-lock "vacancy"))
     (frame :accessor frame :initarg :frame)))
  
  (defclass stream-record ()
    ((chunk-queue :accessor chunk-queue)
     (rcursor :accessor rcursor)
     (wcursor :accessor wcursor)
     (final :accessor final :initform nil)
     (buffer :accessor buffer :type '(unsigned-byte 8))
     (container :accessor container :initarg :container)))
  
  (defmethod initialize-ring ((rec stream-record) ring-length frame-size element-type)
    (setf (chunk-queue rec) (make-list ring-length))
  