;;//////////////////////////////////////////////////////////////////////////
;;
;;        IMPORTANT NOTICE: This sample code makes NO attempts to align 
;;          DWORD writes on DWORD boundaries.  It is HIGHLY recommended 
;;          that you modify this code to do so.  Alternatively, you may 
;;          set the DCI_DWORDALIGN flag in your DCI provider, but this 
;;          may result in window behavior which is distracting to the 
;;          end user.
;;//////////////////////////////////////////////////////////////////////////

memS   EQU   1
?PLM   EQU   0
?WIN   EQU   1

.xlist
include cmacros.new
include windows.inc
.list



sBegin  Data
;keeping locals in data area not on stack
;using ebp as a register during loops
    dstPtrUpdate            DD      ?
    srcPtrUpdate            DD      ?
    dwStripCount            DD      ?
    endOfRow                DD      ?
    dwWidthCopy             DD      ?
    dwVOffset               DD      ?
    dwUOffset               DD      ?
sEnd    Data     




.386

ifndef SEGNAME
    SEGNAME equ <_DCISAMP32>
endif

;createSeg %SEGNAME, CodeSeg, word, PUBLIC, use32, CODE
%SEGNAME    SEGMENT WORD PUBLIC USE32 'CODE'

;sBegin CodeSeg
ASSUME  CS : _DCISAMP32
assumes ds,Data
assumes es,Data
assumes fs,nothing

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;      IF09TO422 -- procedure to convert from Indeo(tm) intermediate format
;;      to 4:2:2 YUYV (Fourcc 'YUY2').  Inner loop operates on a 4x4 block of
;;      pixels, written two at a time in DWORDs, in the following order:
;;
;;                            _______________________________
;;                           |___1___|___1___|___0___|___0___| 
;;                           |___3___|___3___|___2___|___2___|
;;                           |___5___|___5___|___4___|___4___|
;;                           |___7___|___7___|___6___|___6___|
;;
;;      Source and destination indices progress along row one of each 4-line
;;      'strip'.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

PUBLIC          _IF09TO422
_IF09TO422   PROC    FAR

    ;set up stack: save 4 registers, set up bp.
    push    ebp
    push    edi
    push    esi
    push    ds
    movzx   ebp, sp
    add     ebp, 20
    
    ;set up equates - params are after ret addr, saved regs
    wSrcSel     EQU     WORD  PTR   [ebp+0]     ;selector of src. buffer
    dwSrcOffset EQU     DWORD PTR   [ebp+2]     ;offset of src. buffer
    wDstSel     EQU     WORD  PTR   [ebp+6]     ;selector of dst. buffer
    dwDstOffset EQU     DWORD PTR   [ebp+8]     ;offset of dst. buffer
    dwWidth     EQU     DWORD PTR   [ebp+12]    ;width in pixels of src.
    dwHeight    EQU     DWORD PTR   [ebp+16]    ;height in pixels of src.
    dwStride    EQU     DWORD PTR   [ebp+20]    ;pitch (stride) of frame buffer.
    
    ;move params. into registers, set up for loop.
    mov     eax, dwStride           ;copy pitch into eax for later use.
    mov     cx, ds                  ;get a copy of data seg.
    mov     ebx, dwWidth            ;copy width into ebx for later use.
    mov     fs, cx                  ;fs<--copy of "real" ds
    mov     edx, ebx                ;keep this for offsets in inner loop
    mov     ecx, eax                ; "     "   "     "     "   "     "
    shl     eax, 2                  
    shl     ebx, 1                  
    sub     eax, ebx                ;eax<--outer loop pointer update amt.
    mov     fs:dwWidthCopy, edx     ;copy of width for detecting end of row
    shr     ebx, 1
    mov     fs:dstPtrUpdate, eax    ;amount to add to dst pointer per strip
    mov     esi, dwSrcOffset        ;es:[esi] will be src. pointer
    mov     eax, ebx                
    mov     edi, dwDstOffset        ;ds:[edi] will be dst. pointer
    shl     eax, 2
    mov     ds, wSrcSel             
    sub     eax, ebx
    mov     es, wDstSel
    mov     fs:srcPtrUpdate, eax    ;amount to add to src pointer per strip
    add     esi, dwWidth
    mov     eax, dwHeight
    sub     esi, fs:srcPtrUpdate
    shr     eax, 2
    sub     esi, 4
    add     edi, dwStride           ;point to second line of image
    mov     fs:dwStripCount, eax    ;counter for outer loop
    sub     edi, fs:dstPtrUpdate    ;will add these in 1st time around
    mov     eax, dwHeight
    sub     edi, 8
    mul     edx
    mov     fs:dwVOffset, eax       ;offset to V plane
    mov     ebx, eax
    mov     edx, dwWidth
    shl     eax, 3
    inc     fs:dwStripCount
    add     eax, ebx
    shr     eax, 3
    mov     ebp, eax                ;ebp = offset to skip indices
    mov     eax, ebx
    dec     ebp
    shl     eax, 4
    add     eax, ebx
    shr     eax, 4
    mov     fs:dwUOffset, eax       ;offset to U plane

NextRow:
    mov     ebx, fs:dwStripCount
    dec     ebx
    jz      Done
    mov     fs:dwStripCount, ebx
    add     esi, fs:srcPtrUpdate    ;src += 3 * width
    add     edi, fs:dstPtrUpdate    ;dst += (4 * stride) - width
    mov     eax, esi
    add     eax, fs:dwWidthCopy
    mov     fs:endOfRow, eax        ;calculate end of next row

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;  This conversion routine does IF09 to YUV 4:2:2 in YUYV order.  Swapping
;;  the bytes is trivial, and is thus left as an exercise for the reader.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

NextBlock:
    cmp     esi, fs:endOfRow        ;check for row done
    je      NextRow
    add     esi, 4                  ;point src. to next 4x4
    inc     ebp                     ;point to next skip index
    add     edi, 8                  ;point dst. to next 4x4
    inc     fs:dwVOffset            ;point to next u,v pair
    inc     fs:dwUOffset
    mov     al, BYTE PTR ds:[ebp]
    cmp     al, 0fh                 ;check for skipped 4x4 block
    je      NextBlock               ;loop if block is skipped


    ;fetch u,v pair for this 4x4 block
    mov     ebx, fs:dwVOffset
    neg     ecx                     ;ecx points back one row in dest. buf.
    mov     ah, [ebx]               ;ah = v value for this block
    neg     edx                     ;edx points back one in src.
    mov     ebx, fs:dwUOffset
    shl     eax, 16
    mov     ah, [ebx]               ;ah = u value for this block
    mov     ebx, eax                ;copy eax into ebx to copy u, v pair

    ;now fetch y values and write out
    mov     bl, [esi+edx+2]
    mov     al, [esi+edx]           ;al = y00
    rol     ebx, 16
    rol     eax, 16
    mov     bl, [esi+edx+3]
    mov     al, [esi+edx+1]         ;interleave Ys. al = y01
    rol     ebx, 16
    rol     eax, 16
    mov     es:[edi+ecx+4], ebx     ;store y02-u-y03-v
    mov     es:[edi+ecx], eax       ;store y00-u-y01-v

    neg     ecx                     ;ecx = +stride
    neg     edx                     ;edx = +width

    mov     bl, [esi+2]
    mov     al, [esi]
    rol     ebx, 16
    rol     eax, 16
    mov     bl, [esi+3]
    mov     al, [esi+1]
    rol     ebx, 16
    rol     eax, 16
    mov     es:[edi+4], ebx         ;store y12-u-y13-v
    mov     es:[edi], eax           ;store y10-u-y11-v

    mov     bl, [esi+edx+2]
    mov     al, [esi+edx]
    rol     ebx, 16
    rol     eax, 16
    mov     bl, [esi+edx+3]
    mov     al, [esi+edx+1]
    rol     ebx, 16
    rol     eax, 16
    mov     es:[edi+ecx+4], ebx     ;store y22-u-y23-v
    mov     es:[edi+ecx], eax       ;store y20-u-y21-v

    mov     bl, [esi+edx*2+2]
    mov     al, [esi+edx*2]
    rol     ebx, 16
    rol     eax, 16
    mov     bl, [esi+edx*2+3]
    mov     al, [esi+edx*2+1]
    rol     ebx, 16
    rol     eax, 16
    mov     es:[edi+ecx*2+4], ebx   ;store y32-u-y33-v
    mov     es:[edi+ecx*2], eax     ;store y30-u-y31-v

    jmp     NextBlock

Done:
    ;all done - pop saved registers
    pop     ds
    pop     esi
    pop     edi
    pop     ebp
    db      66h
    retf

_IF09TO422  ENDP



%SEGNAME ENDS
;sEnd    CodeSeg
end
