<div dir="ltr">---<br> modules/codec/jpeg.c | 1263 +++++++++++++++++++++++++++++++++++++++++++++++++-<br> 1 file changed, 1257 insertions(+), 6 deletions(-)<br><br>diff --git a/modules/codec/jpeg.c b/modules/codec/jpeg.c<br>index cc7a58b..77233a7 100644<br>--- a/modules/codec/jpeg.c<br>+++ b/modules/codec/jpeg.c<br>@@ -1,9 +1,10 @@<br> /*****************************************************************************<br>  * jpeg.c: jpeg decoder module making use of libjpeg.<br>  *****************************************************************************<br>- * Copyright (C) 2013-2014 VLC authors and VideoLAN<br>+ * Copyright (C) 2013-2014,2016 VLC authors and VideoLAN<br>  *<br>  * Authors: Maxim Bublis <<a href="mailto:b@codemonkey.ru">b@codemonkey.ru</a>><br>+ *          Wayne McDougall <<a href="mailto:waynemcdougall@gmail.com">waynemcdougall@gmail.com</a>><br>  *<br>  * This program is free software; you can redistribute it and/or modify it<br>  * under the terms of the GNU Lesser General Public License as published by<br>@@ -27,6 +28,11 @@<br> #include <vlc_common.h><br> #include <vlc_plugin.h><br> #include <vlc_codec.h><br>+<br>+/* Although this file really shouldn't have access to the library internals,<br>+ * it's helpful to let it call jround_up() and jcopy_block_row().<br>+ */<br>+#define JPEG_INTERNALS<br> #include <jpeglib.h><br> #include <setjmp.h><br> <br>@@ -50,6 +56,27 @@<br> #define ENC_QUALITY_LONGTEXT N_( "Quality level " \<br>                                  "for encoding (this can enlarge or reduce output image size)." )<br> <br>+#define DEC_CFG_PREFIX "jpeg-"<br>+#define DEC_AUTOORIENT_TEXT N_( "Automatic Orientation" )<br>+#define DEC_AUTOORIENT_LONGTEXT N_( "Automatic rotation based on EXIF orientation flag. " \<br>+                                    "Lossless, but will crop if JPEG has unusual dimensions. Uses more RAM." )<br>+<br>+const char leth[] = {<br>+    0x49, 0x49, 0x2a, 0x00<br>+};                                              /* Little endian TIFF header */<br>+const char beth[] = {<br>+    0x4d, 0x4d, 0x00, 0x2a<br>+};                                              /* Big endian TIFF header */<br>+const char types[] = {<br>+    0x00, 0x01, 0x01, 0x02, 0x04, 0x08, 0x00,<br>+    0x08, 0x00, 0x04, 0x08<br>+};                                              /* size in bytes for EXIF types */<br>+<br>+#define G_LITTLE_ENDIAN     1234<br>+#define G_BIG_ENDIAN        4321<br>+<br>+#define EXIF_JPEG_MARKER    0xE1<br>+#define EXIF_IDENT_STRING   "Exif\000\000"<br> <br> /*<br>  * jpeg common descriptor<br>@@ -86,6 +113,33 @@ struct encoder_sys_t {<br>     int i_quality;<br> };<br> <br>+/*<br>+ * Codes for supported types of image transformations.<br>+ */<br>+<br>+typedef enum {<br>+    JXFORM_FLIP_H,              /* horizontal flip */<br>+    JXFORM_FLIP_V,              /* vertical flip */<br>+    JXFORM_TRANSPOSE,           /* transpose across UL-to-LR axis */<br>+    JXFORM_TRANSVERSE,          /* transpose across UR-to-LL axis */<br>+    JXFORM_ROT_90,              /* 90-degree clockwise rotation */<br>+    JXFORM_ROT_180,             /* 180-degree rotation */<br>+    JXFORM_ROT_270,             /* 270-degree clockwise (or 90 ccw) */<br>+} JXFORM_CODE;<br>+<br>+typedef struct {<br>+    /* Options: set by caller */<br>+    JXFORM_CODE transform;      /* image transform operator */<br>+<br>+    /* Internal workspace: caller should not touch these */<br>+    int num_components;         /* # of components in workspace */<br>+    jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */<br>+    JDIMENSION output_width;    /* cropped destination dimensions */<br>+    JDIMENSION output_height;<br>+    int iMCU_sample_width;      /* destination iMCU size */<br>+    int iMCU_sample_height;<br>+} jpeg_transform_info;<br>+<br> static const char * const ppsz_enc_options[] = {<br>     "quality",<br>     NULL<br>@@ -107,6 +161,8 @@ set_description( N_( "JPEG image decoder" ) )<br> set_capability( "decoder", 1000 )<br> set_callbacks( OpenDecoder, CloseDecoder )<br> add_shortcut( "jpeg" )<br>+add_bool( DEC_CFG_PREFIX "autoorient", true,<br>+          DEC_AUTOORIENT_TEXT, DEC_AUTOORIENT_LONGTEXT, true )<br> <br> /* encoder submodule */<br> add_submodule()<br>@@ -178,6 +234,1120 @@ static int OpenDecoder ( vlc_object_t * p_this )<br>     return VLC_SUCCESS;<br> }<br> <br>+/* Start of code used to Auto Orient JPEG */<br>+<br>+LOCAL( unsigned short )<br>+de_get16( void * ptr, uint endian ) {<br>+    unsigned short val;<br>+<br>+    memcpy( &val, ptr, sizeof( val ) );<br>+    if ( endian == G_BIG_ENDIAN )<br>+    {<br>+        #ifndef WORDS_BIGENDIAN<br>+        val = bswap16( val );<br>+        #endif<br>+    }<br>+    else<br>+    {<br>+        #ifdef WORDS_BIGENDIAN<br>+        val = bswap16( val );<br>+        #endif<br>+    }<br>+    return val;<br>+}<br>+<br>+LOCAL( unsigned int )<br>+de_get32( void * ptr, uint endian ) {<br>+    unsigned int val;<br>+<br>+    memcpy( &val, ptr, sizeof( val ) );<br>+    if ( endian == G_BIG_ENDIAN )<br>+    {<br>+        #ifndef WORDS_BIGENDIAN<br>+        val = bswap32( val );<br>+        #endif<br>+    }<br>+    else<br>+    {<br>+        #ifdef WORDS_BIGENDIAN<br>+        val = bswap32( val );<br>+        #endif<br>+    }<br>+    return val;<br>+}<br>+<br>+/* jpeg_GetOrientation function based on code from GdkPixbuf library - JPEG image loader<br>+ * <a href="http://src.gnu-darwin.org/ports/x11-toolkits/gtk20/work/gtk+-2.12.3/gdk-pixbuf/io-jpeg.c">http://src.gnu-darwin.org/ports/x11-toolkits/gtk20/work/gtk+-2.12.3/gdk-pixbuf/io-jpeg.c</a><br>+ *<br>+ * Copyright (C) 1999 Michael Zucchi<br>+ * Copyright (C) 1999 The Free Software Foundation<br>+ */<br>+<br>+LOCAL( int )<br>+jpeg_GetOrientation( j_decompress_ptr cinfo ) {<br>+    /* This function looks through the meta data in the libjpeg decompress structure to<br>+       determine if an EXIF Orientation tag is present and if so return its value (1-8).<br>+       If no EXIF Orientation tag is found 0 (zero) is returned. */<br>+<br>+    uint i;                    /* index into working buffer */<br>+    ushort tag_type;           /* endianed tag type extracted from tiff header */<br>+    uint ret;                  /* Return value */<br>+    uint offset;               /* de-endianed offset in various situations */<br>+    uint tags;                 /* number of tags in current ifd */<br>+    uint type;                 /* de-endianed type of tag used as index into types[] */<br>+    uint count;                /* de-endianed count of elements in a tag */<br>+    uint tiff = 0;             /* offset to active tiff header */<br>+    uint endian = 0;           /* detected endian of data */<br>+<br>+    jpeg_saved_marker_ptr exif_marker;      /* Location of the Exif APP1 marker */<br>+    jpeg_saved_marker_ptr cmarker;          /* Location to check for Exif APP1 marker */<br>+<br>+    /* check for Exif marker (also called the APP1 marker) */<br>+    exif_marker = NULL;<br>+    cmarker = cinfo->marker_list;<br>+<br>+<br>+<br>+    while ( cmarker )<br>+    {<br>+        if ( cmarker->marker == EXIF_JPEG_MARKER )<br>+        {<br>+            /* The Exif APP1 marker should contain a unique<br>+               identification string ("Exif\0\0"). Check for it. */<br>+            if ( !memcmp( cmarker->data, EXIF_IDENT_STRING, 6 ) )<br>+            {<br>+                exif_marker = cmarker;<br>+            }<br>+        }<br>+        cmarker = cmarker->next;<br>+    }<br>+<br>+    /* Did we find the Exif APP1 marker? */<br>+    if ( exif_marker == NULL )<br>+        return 0;<br>+<br>+    /* Do we have enough data? */<br>+    if ( exif_marker->data_length < 32 )<br>+        return 0;<br>+<br>+    /* Check for TIFF header and catch endianess */<br>+    i = 0;<br>+<br>+    /* Just skip data until TIFF header - it should be within 16 bytes from marker start.<br>+       Normal structure relative to APP1 marker -<br>+            0x0000: APP1 marker entry = 2 bytes<br>+            0x0002: APP1 length entry = 2 bytes<br>+            0x0004: Exif Identifier entry = 6 bytes<br>+            0x000A: Start of TIFF header (Byte order entry) - 4 bytes<br>+                    - This is what we look for, to determine endianess.<br>+            0x000E: 0th IFD offset pointer - 4 bytes<br>+<br>+            exif_marker->data points to the first data after the APP1 marker<br>+            and length entries, which is the exif identification string.<br>+            The TIFF header should thus normally be found at i=6, below,<br>+            and the pointer to IFD0 will be at 6+4 = 10.<br>+    */<br>+<br>+    while ( i < 16 )<br>+    {<br>+        /* Little endian TIFF header */<br>+        if ( memcmp( &exif_marker->data[i], leth, 4 ) == 0 )<br>+        {<br>+            endian = G_LITTLE_ENDIAN;<br>+        }<br>+        /* Big endian TIFF header */<br>+        else<br>+        if ( memcmp( &exif_marker->data[i], beth, 4 ) == 0 )<br>+        {<br>+            endian = G_BIG_ENDIAN;<br>+        }<br>+        /* Keep looking through buffer */<br>+        else<br>+        {<br>+            i++;<br>+            continue;<br>+        }<br>+        /* We have found either big or little endian TIFF header */<br>+        tiff = i;<br>+        break;<br>+    }<br>+<br>+    /* So did we find a TIFF header or did we just hit end of buffer? */<br>+    if ( tiff == 0 )<br>+        return 0;<br>+<br>+    /* Read out the offset pointer to IFD0 */<br>+    offset = de_get32( &exif_marker->data[i] + 4, endian );<br>+    i = i + offset;<br>+<br>+    /* Check that we still are within the buffer and can read the tag count */<br>+<br>+    if ( ( i + 2 ) > exif_marker->data_length )<br>+        return 0;<br>+<br>+    /* Find out how many tags we have in IFD0. As per the TIFF spec, the first<br>+       two bytes of the IFD contain a count of the number of tags. */<br>+    tags = de_get16( &exif_marker->data[i], endian );<br>+    i = i + 2;<br>+<br>+    /* Check that we still have enough data for all tags to check. The tags<br>+       are listed in consecutive 12-byte blocks. The tag ID, type, size, and<br>+       a pointer to the actual value, are packed into these 12 byte entries. */<br>+    if ( ( i + tags * 12 ) > exif_marker->data_length )<br>+        return 0;<br>+<br>+    /* Check through IFD0 for tags of interest */<br>+    while ( tags-- )<br>+    {<br>+        tag_type = de_get16( &exif_marker->data[i], endian );<br>+        /* Is this the orientation tag? */<br>+        if ( tag_type == 0x112 )<br>+        {<br>+            type = de_get16( &exif_marker->data[i + 2], endian );<br>+            count = de_get32( &exif_marker->data[i + 4], endian );<br>+<br>+            /* Check that type and count fields are OK. The orientation field<br>+               will consist of a single (count=1) 2-byte integer (type=3). */<br>+            if ( type != 3 || count != 1 )<br>+                return 0;<br>+<br>+            /* Return the orientation value. Within the 12-byte block, the<br>+               pointer to the actual data is at offset 8. */<br>+            ret = de_get16( &exif_marker->data[i + 8], endian );<br>+            return ret <= 8 ? ret : 0;<br>+        }<br>+        /* move the pointer to the next 12-byte tag field. */<br>+        i = i + 12;<br>+    }<br>+<br>+    return 0;     /* No EXIF Orientation tag found */<br>+}<br>+<br>+/* Following Auto Orient code heavily based on code from transupp.c by the IJG */<br>+<br>+/* Trim off any partial iMCUs on the indicated destination edge */<br>+<br>+LOCAL( void )<br>+trim_right_edge( jpeg_transform_info * info, JDIMENSION full_width ) {<br>+    JDIMENSION MCU_cols;<br>+<br>+    MCU_cols = info->output_width / info->iMCU_sample_width;<br>+    if ( MCU_cols > 0 && MCU_cols ==<br>+         full_width / info->iMCU_sample_width )<br>+        info->output_width = MCU_cols * info->iMCU_sample_width;<br>+}<br>+<br>+LOCAL( void )<br>+trim_bottom_edge( jpeg_transform_info * info, JDIMENSION full_height ) {<br>+    JDIMENSION MCU_rows;<br>+<br>+    MCU_rows = info->output_height / info->iMCU_sample_height;<br>+    if ( MCU_rows > 0 && MCU_rows ==<br>+         full_height / info->iMCU_sample_height )<br>+        info->output_height = MCU_rows * info->iMCU_sample_height;<br>+}<br>+<br>+/* Request any required workspace.<br>+ *<br>+ * This routine figures out the size that the output image will be<br>+ * (which implies that all the transform parameters must be set before<br>+ * it is called).<br>+ *<br>+ * We allocate the workspace virtual arrays from the source decompression<br>+ * object, so that all the arrays (both the original data and the workspace)<br>+ * will be taken into account while making memory management decisions.<br>+ * Hence, this routine must be called after jpeg_read_header (which reads<br>+ * the image dimensions) and before jpeg_read_coefficients (which realizes<br>+ * the source's virtual arrays).<br>+ *<br>+ */<br>+<br>+LOCAL( boolean )<br>+jtransform_request_workspace( j_decompress_ptr srcinfo,<br>+                              jpeg_transform_info * info ) {<br>+    jvirt_barray_ptr * coef_arrays;<br>+    boolean need_workspace, transpose_it;<br>+    jpeg_component_info * compptr;<br>+    JDIMENSION width_in_iMCUs, height_in_iMCUs;<br>+    JDIMENSION width_in_blocks, height_in_blocks;<br>+    int ci, h_samp_factor, v_samp_factor;<br>+<br>+    /* Process all the components */<br>+    info->num_components = srcinfo->num_components;<br>+<br>+    /* Compute output image dimensions and related values. */<br>+    jpeg_core_output_dimensions( srcinfo );<br>+<br>+    /* If there is only one output component, force the iMCU size to be 1;<br>+     * else use the source iMCU size.<br>+     */<br>+    switch ( info->transform )<br>+    {<br>+    case JXFORM_TRANSPOSE:<br>+    case JXFORM_TRANSVERSE:<br>+    case JXFORM_ROT_90:<br>+    case JXFORM_ROT_270:<br>+        info->output_width = srcinfo->output_height;<br>+        info->output_height = srcinfo->output_width;<br>+        if ( info->num_components == 1 )<br>+        {<br>+            info->iMCU_sample_width = srcinfo->min_DCT_v_scaled_size;<br>+            info->iMCU_sample_height = srcinfo->min_DCT_h_scaled_size;<br>+        }<br>+        else<br>+        {<br>+            info->iMCU_sample_width =<br>+                srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size;<br>+            info->iMCU_sample_height =<br>+                srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size;<br>+        }<br>+        break;<br>+    default:<br>+        info->output_width = srcinfo->output_width;<br>+        info->output_height = srcinfo->output_height;<br>+        if ( info->num_components == 1 )<br>+        {<br>+            info->iMCU_sample_width = srcinfo->min_DCT_h_scaled_size;<br>+            info->iMCU_sample_height = srcinfo->min_DCT_v_scaled_size;<br>+        }<br>+        else<br>+        {<br>+            info->iMCU_sample_width =<br>+                srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size;<br>+            info->iMCU_sample_height =<br>+                srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size;<br>+        }<br>+        break;<br>+    }<br>+<br>+    /* Figure out whether we need workspace arrays,<br>+     * and if so whether they are transposed relative to the source.<br>+     */<br>+    need_workspace = FALSE;<br>+    transpose_it = FALSE;<br>+    switch ( info->transform )<br>+    {<br>+    case JXFORM_FLIP_H:<br>+        trim_right_edge( info, srcinfo->output_width );<br>+        /* do_flip_h doesn't need a workspace array */<br>+        break;<br>+    case JXFORM_FLIP_V:<br>+        trim_bottom_edge( info, srcinfo->output_height );<br>+        /* Need workspace arrays having same dimensions as source image. */<br>+        need_workspace = TRUE;<br>+        break;<br>+    case JXFORM_TRANSPOSE:<br>+        /* transpose does NOT have to trim anything */<br>+        /* Need workspace arrays having transposed dimensions. */<br>+        need_workspace = TRUE;<br>+        transpose_it = TRUE;<br>+        break;<br>+    case JXFORM_TRANSVERSE:<br>+        trim_right_edge( info, srcinfo->output_height );<br>+        trim_bottom_edge( info, srcinfo->output_width );<br>+        /* Need workspace arrays having transposed dimensions. */<br>+        need_workspace = TRUE;<br>+        transpose_it = TRUE;<br>+        break;<br>+    case JXFORM_ROT_90:<br>+        trim_right_edge( info, srcinfo->output_height );<br>+        /* Need workspace arrays having transposed dimensions. */<br>+        need_workspace = TRUE;<br>+        transpose_it = TRUE;<br>+        break;<br>+    case JXFORM_ROT_180:<br>+        trim_right_edge( info, srcinfo->output_width );<br>+        trim_bottom_edge( info, srcinfo->output_height );<br>+        /* Need workspace arrays having same dimensions as source image. */<br>+        need_workspace = TRUE;<br>+        break;<br>+    case JXFORM_ROT_270:<br>+        trim_bottom_edge( info, srcinfo->output_width );<br>+        /* Need workspace arrays having transposed dimensions. */<br>+        need_workspace = TRUE;<br>+        transpose_it = TRUE;<br>+        break;<br>+    }<br>+<br>+    /* Allocate workspace if needed.<br>+<br>+     * Note that we allocate arrays padded out to the next iMCU boundary,<br>+     * so that transform routines need not worry about missing edge blocks.<br>+     */<br>+    if ( need_workspace )<br>+    {<br>+        coef_arrays = (jvirt_barray_ptr *)<br>+                      ( *srcinfo->mem->alloc_small )( (j_common_ptr)srcinfo, JPOOL_IMAGE,<br>+                                                      sizeof( jvirt_barray_ptr ) * info->num_components );<br>+        width_in_iMCUs = (JDIMENSION)<br>+                         jdiv_round_up( (long)info->output_width,<br>+                                        (long)info->iMCU_sample_width );<br>+        height_in_iMCUs = (JDIMENSION)<br>+                          jdiv_round_up( (long)info->output_height,<br>+                                         (long)info->iMCU_sample_height );<br>+        for ( ci = 0; ci < info->num_components; ci++ )<br>+        {<br>+            compptr = srcinfo->comp_info + ci;<br>+            if ( info->num_components == 1 )<br>+            {<br>+                /* we're going to force samp factors to 1x1 in this case */<br>+                h_samp_factor = v_samp_factor = 1;<br>+            }<br>+            else<br>+            if ( transpose_it )<br>+            {<br>+                h_samp_factor = compptr->v_samp_factor;<br>+                v_samp_factor = compptr->h_samp_factor;<br>+            }<br>+            else<br>+            {<br>+                h_samp_factor = compptr->h_samp_factor;<br>+                v_samp_factor = compptr->v_samp_factor;<br>+            }<br>+            width_in_blocks = width_in_iMCUs * h_samp_factor;<br>+            height_in_blocks = height_in_iMCUs * v_samp_factor;<br>+            coef_arrays[ci] = ( *srcinfo->mem->request_virt_barray )<br>+                                  ( (j_common_ptr)srcinfo, JPOOL_IMAGE, FALSE,<br>+                                  width_in_blocks, height_in_blocks, (JDIMENSION)v_samp_factor );<br>+        }<br>+        info->workspace_coef_arrays = coef_arrays;<br>+    }<br>+    else<br>+        info->workspace_coef_arrays = NULL;<br>+<br>+    return TRUE;<br>+}<br>+<br>+/* Transpose destination image parameters */<br>+<br>+LOCAL( void )<br>+transpose_critical_parameters( j_compress_ptr dstinfo ) {<br>+    int tblno, i, j, ci, itemp;<br>+    jpeg_component_info * compptr;<br>+    JQUANT_TBL * qtblptr;<br>+    JDIMENSION jtemp;<br>+    UINT16 qtemp;<br>+<br>+    /* Transpose image dimensions */<br>+    jtemp = dstinfo->image_width;<br>+    dstinfo->image_width = dstinfo->image_height;<br>+    dstinfo->image_height = jtemp;<br>+    itemp = dstinfo->min_DCT_h_scaled_size;<br>+    dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size;<br>+<br>+    dstinfo->min_DCT_v_scaled_size = itemp;<br>+<br>+    /* Transpose sampling factors */<br>+    for ( ci = 0; ci < dstinfo->num_components; ci++ )<br>+    {<br>+        compptr = dstinfo->comp_info + ci;<br>+        itemp = compptr->h_samp_factor;<br>+        compptr->h_samp_factor = compptr->v_samp_factor;<br>+        compptr->v_samp_factor = itemp;<br>+    }<br>+<br>+    /* Transpose quantization tables */<br>+    for ( tblno = 0; tblno < NUM_QUANT_TBLS; tblno++ )<br>+    {<br>+        qtblptr = dstinfo->quant_tbl_ptrs[tblno];<br>+        if ( qtblptr != NULL )<br>+        {<br>+            for ( i = 0; i < DCTSIZE; i++ )<br>+            {<br>+                for ( j = 0; j < i; j++ )<br>+                {<br>+                    qtemp = qtblptr->quantval[i * DCTSIZE + j];<br>+                    qtblptr->quantval[i * DCTSIZE + j] = qtblptr->quantval[j * DCTSIZE + i];<br>+                    qtblptr->quantval[j * DCTSIZE + i] = qtemp;<br>+                }<br>+            }<br>+        }<br>+    }<br>+}<br>+<br>+/* Adjust output image parameters as needed.<br>+ *<br>+ * This must be called after jpeg_copy_critical_parameters()<br>+ * and before jpeg_write_coefficients().<br>+ *<br>+ * The return value is the set of virtual coefficient arrays to be written<br>+ * (either the ones allocated by jtransform_request_workspace, or the<br>+ * original source data arrays).  The caller will need to pass this value<br>+ * to jpeg_write_coefficients().<br>+ */<br>+<br>+LOCAL( jvirt_barray_ptr * )<br>+jtransform_adjust_parameters( j_compress_ptr dstinfo,<br>+                              jvirt_barray_ptr * src_coef_arrays,<br>+                              jpeg_transform_info * info ) {<br>+    /* Correct the destination's image dimensions as necessary<br>+     * for rotate/flip operations.<br>+     */<br>+    dstinfo->jpeg_width = info->output_width;<br>+    dstinfo->jpeg_height = info->output_height;<br>+<br>+    if ( info->transform == JXFORM_ROT_270 )<br>+    {<br>+        transpose_critical_parameters( dstinfo );<br>+    }<br>+<br>+    /* Return the appropriate output data set */<br>+    if ( info->workspace_coef_arrays != NULL )<br>+        return info->workspace_coef_arrays;<br>+    return src_coef_arrays;<br>+}<br>+<br>+LOCAL( void )<br>+do_flip_h( j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr * src_coef_arrays ) {<br>+/* Horizontal flip; done in-place, so no separate dest array is required.<br>+ */<br>+    JDIMENSION MCU_cols, comp_width, blk_x, blk_y;<br>+    int ci, k, offset_y;<br>+    JBLOCKARRAY buffer;<br>+    JCOEFPTR ptr1, ptr2;<br>+    JCOEF temp1, temp2;<br>+    jpeg_component_info * compptr;<br>+<br>+    /* Horizontal mirroring of DCT blocks is accomplished by swapping<br>+     * pairs of blocks in-place.  Within a DCT block, we perform horizontal<br>+     * mirroring by changing the signs of odd-numbered columns.<br>+     * Partial iMCUs at the right edge are left untouched.<br>+     */<br>+    MCU_cols = srcinfo->output_width /<br>+               ( dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size );<br>+<br>+    for ( ci = 0; ci < dstinfo->num_components; ci++ )<br>+    {<br>+        compptr = dstinfo->comp_info + ci;<br>+        comp_width = MCU_cols * compptr->h_samp_factor;<br>+        for ( blk_y = 0; blk_y < compptr->height_in_blocks;<br>+              blk_y += compptr->v_samp_factor )<br>+        {<br>+            buffer = ( *srcinfo->mem->access_virt_barray )<br>+                         ( (j_common_ptr)srcinfo, src_coef_arrays[ci], blk_y,<br>+                         (JDIMENSION)compptr->v_samp_factor, TRUE );<br>+            for ( offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++ )<br>+            {<br>+                /* Do the mirroring */<br>+                for ( blk_x = 0; blk_x * 2 < comp_width; blk_x++ )<br>+                {<br>+                    ptr1 = buffer[offset_y][blk_x];<br>+                    ptr2 = buffer[offset_y][comp_width - blk_x - 1];<br>+                    /* this unrolled loop doesn't need to know which row it's on... */<br>+                    for ( k = 0; k < DCTSIZE2; k += 2 )<br>+                    {<br>+                        temp1 = *ptr1; /* swap even column */<br>+                        temp2 = *ptr2;<br>+                        *ptr1++ = temp2;<br>+                        *ptr2++ = temp1;<br>+                        temp1 = *ptr1; /* swap odd column with sign change */<br>+                        temp2 = *ptr2;<br>+                        *ptr1++ = -temp2;<br>+                        *ptr2++ = -temp1;<br>+                    }<br>+                }<br>+            }<br>+        }<br>+    }<br>+}<br>+<br>+LOCAL( void )<br>+do_flip_v( j_decompress_ptr srcinfo, j_compress_ptr dstinfo,<br>+           jvirt_barray_ptr * src_coef_arrays,<br>+           jvirt_barray_ptr * dst_coef_arrays ) {<br>+/* Vertical flip */<br>+    JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;<br>+    int ci, i, j, offset_y;<br>+    JBLOCKARRAY src_buffer, dst_buffer;<br>+    JBLOCKROW src_row_ptr, dst_row_ptr;<br>+    JCOEFPTR src_ptr, dst_ptr;<br>+    jpeg_component_info * compptr;<br>+<br>+    /* We output into a separate array because we can't touch different<br>+     * rows of the source virtual array simultaneously.  Otherwise, this<br>+     * is a pretty straightforward analog of horizontal flip.<br>+     * Within a DCT block, vertical mirroring is done by changing the signs<br>+     * of odd-numbered rows.<br>+     * Partial iMCUs at the bottom edge are copied verbatim.<br>+     */<br>+    MCU_rows = srcinfo->output_height /<br>+               ( dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size );<br>+<br>+    for ( ci = 0; ci < dstinfo->num_components; ci++ )<br>+    {<br>+        compptr = dstinfo->comp_info + ci;<br>+        comp_height = MCU_rows * compptr->v_samp_factor;<br>+        for ( dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;<br>+              dst_blk_y += compptr->v_samp_factor )<br>+        {<br>+            dst_buffer = ( *srcinfo->mem->access_virt_barray )<br>+                             ( (j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,<br>+                             (JDIMENSION)compptr->v_samp_factor, TRUE );<br>+            if ( dst_blk_y < comp_height )<br>+            {<br>+                /* Row is within the mirrorable area. */<br>+                src_buffer = ( *srcinfo->mem->access_virt_barray )<br>+                                 ( (j_common_ptr)srcinfo, src_coef_arrays[ci],<br>+                                 comp_height - dst_blk_y -<br>+                                 (JDIMENSION)compptr->v_samp_factor,<br>+                                 (JDIMENSION)compptr->v_samp_factor, FALSE );<br>+            }<br>+            else<br>+            {<br>+                /* Bottom-edge blocks will be copied verbatim. */<br>+                src_buffer = ( *srcinfo->mem->access_virt_barray )<br>+                                 ( (j_common_ptr)srcinfo, src_coef_arrays[ci],<br>+                                 dst_blk_y,<br>+                                 (JDIMENSION)compptr->v_samp_factor, FALSE );<br>+            }<br>+            for ( offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++ )<br>+            {<br>+                if ( dst_blk_y < comp_height )<br>+                {<br>+                    /* Row is within the mirrorable area. */<br>+                    dst_row_ptr = dst_buffer[offset_y];<br>+                    src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];<br>+                    for ( dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;<br>+                          dst_blk_x++ )<br>+                    {<br>+                        dst_ptr = dst_row_ptr[dst_blk_x];<br>+                        src_ptr = src_row_ptr[dst_blk_x];<br>+                        for ( i = 0; i < DCTSIZE; i += 2 )<br>+                        {<br>+                            /* copy even row */<br>+                            for ( j = 0; j < DCTSIZE; j++ )<br>+                                *dst_ptr++ = *src_ptr++;<br>+                            /* copy odd row with sign change */<br>+                            for ( j = 0; j < DCTSIZE; j++ )<br>+                                *dst_ptr++ = -*src_ptr++;<br>+                        }<br>+                    }<br>+                }<br>+                else<br>+                {<br>+                    /* Just copy row verbatim. */<br>+                    jcopy_block_row( src_buffer[offset_y],<br>+                                     dst_buffer[offset_y],<br>+                                     compptr->width_in_blocks );<br>+                }<br>+            }<br>+        }<br>+    }<br>+}<br>+<br>+LOCAL( void )<br>+do_transpose( j_decompress_ptr srcinfo, j_compress_ptr dstinfo,<br>+              jvirt_barray_ptr * src_coef_arrays,<br>+              jvirt_barray_ptr * dst_coef_arrays ) {<br>+/* Transpose source into destination */<br>+    JDIMENSION dst_blk_x, dst_blk_y;<br>+    int ci, i, j, offset_x, offset_y;<br>+    JBLOCKARRAY src_buffer, dst_buffer;<br>+    JCOEFPTR src_ptr, dst_ptr;<br>+    jpeg_component_info * compptr;<br>+<br>+    /* Transposing pixels within a block just requires transposing the<br>+     * DCT coefficients.<br>+     * Partial iMCUs at the edges require no special treatment; we simply<br>+     * process all the available DCT blocks for every component.<br>+     */<br>+    for ( ci = 0; ci < dstinfo->num_components; ci++ )<br>+    {<br>+        compptr = dstinfo->comp_info + ci;<br>+        for ( dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;<br>+              dst_blk_y += compptr->v_samp_factor )<br>+        {<br>+            dst_buffer = ( *srcinfo->mem->access_virt_barray )<br>+                             ( (j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,<br>+                             (JDIMENSION)compptr->v_samp_factor, TRUE );<br>+            for ( offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++ )<br>+            {<br>+                for ( dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;<br>+                      dst_blk_x += compptr->h_samp_factor )<br>+                {<br>+                    src_buffer = ( *srcinfo->mem->access_virt_barray )<br>+                                     ( (j_common_ptr)srcinfo, src_coef_arrays[ci],<br>+                                     dst_blk_x,<br>+                                     (JDIMENSION)compptr->h_samp_factor, FALSE );<br>+                    for ( offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++ )<br>+                    {<br>+                        dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];<br>+                        src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];<br>+                        for ( i = 0; i < DCTSIZE; i++ )<br>+                            for ( j = 0; j < DCTSIZE; j++ )<br>+                                dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];<br>+                    }<br>+                }<br>+            }<br>+        }<br>+    }<br>+}<br>+<br>+LOCAL( void )<br>+do_rot_90( j_decompress_ptr srcinfo, j_compress_ptr dstinfo,<br>+           jvirt_barray_ptr * src_coef_arrays,<br>+           jvirt_barray_ptr * dst_coef_arrays ) {<br>+/* 90 degree rotation is equivalent to<br>+ *   1. Transposing the image;<br>+ *   2. Horizontal mirroring.<br>+ * These two steps are merged into a single processing routine.<br>+ */<br>+    JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;<br>+    int ci, i, j, offset_x, offset_y;<br>+    JBLOCKARRAY src_buffer, dst_buffer;<br>+    JCOEFPTR src_ptr, dst_ptr;<br>+    jpeg_component_info * compptr;<br>+<br>+    /* Because of the horizontal mirror step, we can't process partial iMCUs<br>+     * at the (output) right edge properly.  They just get transposed and<br>+     * not mirrored.<br>+     */<br>+    MCU_cols = srcinfo->output_height /<br>+               ( dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size );<br>+<br>+    for ( ci = 0; ci < dstinfo->num_components; ci++ )<br>+    {<br>+        compptr = dstinfo->comp_info + ci;<br>+        comp_width = MCU_cols * compptr->h_samp_factor;<br>+        for ( dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;<br>+              dst_blk_y += compptr->v_samp_factor )<br>+        {<br>+            dst_buffer = ( *srcinfo->mem->access_virt_barray )<br>+                             ( (j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,<br>+                             (JDIMENSION)compptr->v_samp_factor, TRUE );<br>+            for ( offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++ )<br>+            {<br>+                for ( dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;<br>+                      dst_blk_x += compptr->h_samp_factor )<br>+                {<br>+                    if ( dst_blk_x < comp_width )<br>+                    {<br>+                        /* Block is within the mirrorable area. */<br>+                        src_buffer = ( *srcinfo->mem->access_virt_barray )<br>+                                         ( (j_common_ptr)srcinfo, src_coef_arrays[ci],<br>+                                         comp_width - dst_blk_x -<br>+                                         (JDIMENSION)compptr->h_samp_factor,<br>+                                         (JDIMENSION)compptr->h_samp_factor, FALSE );<br>+                    }<br>+                    else<br>+                    {<br>+                        /* Edge blocks are transposed but not mirrored. */<br>+                        src_buffer = ( *srcinfo->mem->access_virt_barray )<br>+                                         ( (j_common_ptr)srcinfo, src_coef_arrays[ci],<br>+                                         dst_blk_x,<br>+                                         (JDIMENSION)compptr->h_samp_factor, FALSE );<br>+                    }<br>+                    for ( offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++ )<br>+                    {<br>+                        dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];<br>+                        if ( dst_blk_x < comp_width )<br>+                        {<br>+                            /* Block is within the mirrorable area. */<br>+                            src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]<br>+                                      [dst_blk_y + offset_y];<br>+                            for ( i = 0; i < DCTSIZE; i++ )<br>+                            {<br>+                                for ( j = 0; j < DCTSIZE; j++ )<br>+                                    dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];<br>+                                i++;<br>+                                for ( j = 0; j < DCTSIZE; j++ )<br>+                                    dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];<br>+                            }<br>+                        }<br>+                        else<br>+                        {<br>+                            /* Edge blocks are transposed but not mirrored. */<br>+                            src_ptr = src_buffer[offset_x]<br>+                                      [dst_blk_y + offset_y];<br>+                            for ( i = 0; i < DCTSIZE; i++ )<br>+                                for ( j = 0; j < DCTSIZE; j++ )<br>+                                    dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];<br>+                        }<br>+                    }<br>+                }<br>+            }<br>+        }<br>+    }<br>+}<br>+<br>+LOCAL( void )<br>+do_rot_270( j_decompress_ptr srcinfo, j_compress_ptr dstinfo,<br>+            jvirt_barray_ptr * src_coef_arrays,<br>+            jvirt_barray_ptr * dst_coef_arrays ) {<br>+/* 270 degree rotation is equivalent to<br>+ *   1. Horizontal mirroring;<br>+ *   2. Transposing the image.<br>+ * These two steps are merged into a single processing routine.<br>+ */<br>+    JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;<br>+    int ci, i, j, offset_x, offset_y;<br>+    JBLOCKARRAY src_buffer, dst_buffer;<br>+    JCOEFPTR src_ptr, dst_ptr;<br>+    jpeg_component_info * compptr;<br>+<br>+    /* Because of the horizontal mirror step, we can't process partial iMCUs<br>+     * at the (output) bottom edge properly.  They just get transposed and<br>+     * not mirrored.<br>+     */<br>+    MCU_rows = srcinfo->output_width /<br>+               ( dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size );<br>+<br>+    for ( ci = 0; ci < dstinfo->num_components; ci++ )<br>+    {<br>+        compptr = dstinfo->comp_info + ci;<br>+        comp_height = MCU_rows * compptr->v_samp_factor;<br>+        for ( dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;<br>+              dst_blk_y += compptr->v_samp_factor )<br>+        {<br>+            dst_buffer = ( *srcinfo->mem->access_virt_barray )<br>+                             ( (j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,<br>+                             (JDIMENSION)compptr->v_samp_factor, TRUE );<br>+            for ( offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++ )<br>+            {<br>+                for ( dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;<br>+                      dst_blk_x += compptr->h_samp_factor )<br>+                {<br>+                    src_buffer = ( *srcinfo->mem->access_virt_barray )<br>+                                     ( (j_common_ptr)srcinfo, src_coef_arrays[ci],<br>+                                     dst_blk_x,<br>+                                     (JDIMENSION)compptr->h_samp_factor, FALSE );<br>+                    for ( offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++ )<br>+                    {<br>+                        dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];<br>+                        if ( dst_blk_y < comp_height )<br>+                        {<br>+                            /* Block is within the mirrorable area. */<br>+                            src_ptr = src_buffer[offset_x]<br>+                                      [comp_height - dst_blk_y - offset_y - 1];<br>+                            for ( i = 0; i < DCTSIZE; i++ )<br>+                            {<br>+                                for ( j = 0; j < DCTSIZE; j++ )<br>+                                {<br>+                                    dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];<br>+                                    j++;<br>+                                    dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];<br>+                                }<br>+                            }<br>+                        }<br>+                        else<br>+                        {<br>+                            /* Edge blocks are transposed but not mirrored. */<br>+                            src_ptr = src_buffer[offset_x]<br>+                                      [dst_blk_y + offset_y];<br>+                            for ( i = 0; i < DCTSIZE; i++ )<br>+                                for ( j = 0; j < DCTSIZE; j++ )<br>+                                    dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];<br>+                        }<br>+                    }<br>+                }<br>+            }<br>+        }<br>+    }<br>+}<br>+<br>+LOCAL( void )<br>+do_rot_180( j_decompress_ptr srcinfo, j_compress_ptr dstinfo,<br>+            jvirt_barray_ptr * src_coef_arrays,<br>+            jvirt_barray_ptr * dst_coef_arrays ) {<br>+/* 180 degree rotation is equivalent to<br>+ *   1. Vertical mirroring;<br>+ *   2. Horizontal mirroring.<br>+ * These two steps are merged into a single processing routine.<br>+ */<br>+    JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;<br>+    int ci, i, j, offset_y;<br>+    JBLOCKARRAY src_buffer, dst_buffer;<br>+    JBLOCKROW src_row_ptr, dst_row_ptr;<br>+    JCOEFPTR src_ptr, dst_ptr;<br>+    jpeg_component_info * compptr;<br>+<br>+    MCU_cols = srcinfo->output_width /<br>+               ( dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size );<br>+    MCU_rows = srcinfo->output_height /<br>+               ( dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size );<br>+<br>+    for ( ci = 0; ci < dstinfo->num_components; ci++ )<br>+    {<br>+        compptr = dstinfo->comp_info + ci;<br>+        comp_width = MCU_cols * compptr->h_samp_factor;<br>+        comp_height = MCU_rows * compptr->v_samp_factor;<br>+        for ( dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;<br>+              dst_blk_y += compptr->v_samp_factor )<br>+        {<br>+            dst_buffer = ( *srcinfo->mem->access_virt_barray )<br>+                             ( (j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,<br>+                             (JDIMENSION)compptr->v_samp_factor, TRUE );<br>+            if ( dst_blk_y < comp_height )<br>+            {<br>+                /* Row is within the vertically mirrorable area. */<br>+                src_buffer = ( *srcinfo->mem->access_virt_barray )<br>+                                 ( (j_common_ptr)srcinfo, src_coef_arrays[ci],<br>+                                 comp_height - dst_blk_y -<br>+                                 (JDIMENSION)compptr->v_samp_factor,<br>+                                 (JDIMENSION)compptr->v_samp_factor, FALSE );<br>+            }<br>+            else<br>+            {<br>+                /* Bottom-edge rows are only mirrored horizontally. */<br>+                src_buffer = ( *srcinfo->mem->access_virt_barray )<br>+                                 ( (j_common_ptr)srcinfo, src_coef_arrays[ci],<br>+                                 dst_blk_y,<br>+                                 (JDIMENSION)compptr->v_samp_factor, FALSE );<br>+            }<br>+            for ( offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++ )<br>+            {<br>+                dst_row_ptr = dst_buffer[offset_y];<br>+                if ( dst_blk_y < comp_height )<br>+                {<br>+                    /* Row is within the mirrorable area. */<br>+                    src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];<br>+                    for ( dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++ )<br>+                    {<br>+                        dst_ptr = dst_row_ptr[dst_blk_x];<br>+                        if ( dst_blk_x < comp_width )<br>+                        {<br>+                            /* Process the blocks that can be mirrored both ways. */<br>+                            src_ptr = src_row_ptr[comp_width - dst_blk_x - 1];<br>+                            for ( i = 0; i < DCTSIZE; i += 2 )<br>+                            {<br>+                                /* For even row, negate every odd column. */<br>+                                for ( j = 0; j < DCTSIZE; j += 2 )<br>+                                {<br>+                                    *dst_ptr++ = *src_ptr++;<br>+                                    *dst_ptr++ = -*src_ptr++;<br>+                                }<br>+                                /* For odd row, negate every even column. */<br>+                                for ( j = 0; j < DCTSIZE; j += 2 )<br>+                                {<br>+                                    *dst_ptr++ = -*src_ptr++;<br>+                                    *dst_ptr++ = *src_ptr++;<br>+                                }<br>+                            }<br>+                        }<br>+                        else<br>+                        {<br>+                            /* Any remaining right-edge blocks are only mirrored vertically. */<br>+                            src_ptr = src_row_ptr[dst_blk_x];<br>+                            for ( i = 0; i < DCTSIZE; i += 2 )<br>+                            {<br>+                                for ( j = 0; j < DCTSIZE; j++ )<br>+                                    *dst_ptr++ = *src_ptr++;<br>+                                for ( j = 0; j < DCTSIZE; j++ )<br>+                                    *dst_ptr++ = -*src_ptr++;<br>+                            }<br>+                        }<br>+                    }<br>+                }<br>+                else<br>+                {<br>+                    /* Remaining rows are just mirrored horizontally. */<br>+                    src_row_ptr = src_buffer[offset_y];<br>+                    for ( dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++ )<br>+                    {<br>+                        if ( dst_blk_x < comp_width )<br>+                        {<br>+                            /* Process the blocks that can be mirrored. */<br>+                            dst_ptr = dst_row_ptr[dst_blk_x];<br>+                            src_ptr = src_row_ptr[comp_width - dst_blk_x - 1];<br>+                            for ( i = 0; i < DCTSIZE2; i += 2 )<br>+                            {<br>+                                *dst_ptr++ = *src_ptr++;<br>+                                *dst_ptr++ = -*src_ptr++;<br>+                            }<br>+                        }<br>+                        else<br>+                        {<br>+                            /* Any remaining right-edge blocks are only copied. */<br>+                            jcopy_block_row( src_row_ptr + dst_blk_x,<br>+                                             dst_row_ptr + dst_blk_x,<br>+                                             (JDIMENSION)1 );<br>+                        }<br>+                    }<br>+                }<br>+            }<br>+        }<br>+    }<br>+}<br>+<br>+LOCAL( void )<br>+do_transverse( j_decompress_ptr srcinfo, j_compress_ptr dstinfo,<br>+               jvirt_barray_ptr * src_coef_arrays,<br>+               jvirt_barray_ptr * dst_coef_arrays ) {<br>+/* Transverse transpose is equivalent to<br>+ *   1. 180 degree rotation;<br>+ *   2. Transposition;<br>+ * or<br>+ *   1. Horizontal mirroring;<br>+ *   2. Transposition;<br>+ *   3. Horizontal mirroring.<br>+ * These steps are merged into a single processing routine.<br>+ */<br>+    JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;<br>+    int ci, i, j, offset_x, offset_y;<br>+    JBLOCKARRAY src_buffer, dst_buffer;<br>+    JCOEFPTR src_ptr, dst_ptr;<br>+    jpeg_component_info * compptr;<br>+<br>+    MCU_cols = srcinfo->output_height /<br>+               ( dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size );<br>+    MCU_rows = srcinfo->output_width /<br>+               ( dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size );<br>+<br>+    for ( ci = 0; ci < dstinfo->num_components; ci++ )<br>+    {<br>+        compptr = dstinfo->comp_info + ci;<br>+        comp_width = MCU_cols * compptr->h_samp_factor;<br>+        comp_height = MCU_rows * compptr->v_samp_factor;<br>+        for ( dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;<br>+              dst_blk_y += compptr->v_samp_factor )<br>+        {<br>+            dst_buffer = ( *srcinfo->mem->access_virt_barray )<br>+                             ( (j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,<br>+                             (JDIMENSION)compptr->v_samp_factor, TRUE );<br>+            for ( offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++ )<br>+            {<br>+                for ( dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;<br>+                      dst_blk_x += compptr->h_samp_factor )<br>+                {<br>+                    if ( dst_blk_x < comp_width )<br>+                    {<br>+                        /* Block is within the mirrorable area. */<br>+                        src_buffer = ( *srcinfo->mem->access_virt_barray )<br>+                                         ( (j_common_ptr)srcinfo, src_coef_arrays[ci],<br>+                                         comp_width - dst_blk_x -<br>+                                         (JDIMENSION)compptr->h_samp_factor,<br>+                                         (JDIMENSION)compptr->h_samp_factor, FALSE );<br>+                    }<br>+                    else<br>+                    {<br>+                        src_buffer = ( *srcinfo->mem->access_virt_barray )<br>+                                         ( (j_common_ptr)srcinfo, src_coef_arrays[ci],<br>+                                         dst_blk_x,<br>+                                         (JDIMENSION)compptr->h_samp_factor, FALSE );<br>+                    }<br>+                    for ( offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++ )<br>+                    {<br>+                        dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];<br>+                        if ( dst_blk_y < comp_height )<br>+                        {<br>+                            if ( dst_blk_x < comp_width )<br>+                            {<br>+                                /* Block is within the mirrorable area. */<br>+                                src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]<br>+                                          [comp_height - dst_blk_y - offset_y - 1];<br>+                                for ( i = 0; i < DCTSIZE; i++ )<br>+                                {<br>+                                    for ( j = 0; j < DCTSIZE; j++ )<br>+                                    {<br>+                                        dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];<br>+                                        j++;<br>+                                        dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];<br>+                                    }<br>+                                    i++;<br>+                                    for ( j = 0; j < DCTSIZE; j++ )<br>+                                    {<br>+                                        dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];<br>+                                        j++;<br>+                                        dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];<br>+                                    }<br>+                                }<br>+                            }<br>+                            else<br>+                            {<br>+                                /* Right-edge blocks are mirrored in y only */<br>+                                src_ptr = src_buffer[offset_x]<br>+                                          [comp_height - dst_blk_y - offset_y - 1];<br>+                                for ( i = 0; i < DCTSIZE; i++ )<br>+                                {<br>+                                    for ( j = 0; j < DCTSIZE; j++ )<br>+                                    {<br>+                                        dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];<br>+                                        j++;<br>+                                        dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];<br>+                                    }<br>+                                }<br>+                            }<br>+                        }<br>+                        else<br>+                        {<br>+                            if ( dst_blk_x < comp_width )<br>+                            {<br>+                                /* Bottom-edge blocks are mirrored in x only */<br>+                                src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]<br>+                                          [dst_blk_y + offset_y];<br>+                                for ( i = 0; i < DCTSIZE; i++ )<br>+                                {<br>+                                    for ( j = 0; j < DCTSIZE; j++ )<br>+                                        dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];<br>+                                    i++;<br>+                                    for ( j = 0; j < DCTSIZE; j++ )<br>+                                        dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];<br>+                                }<br>+                            }<br>+                            else<br>+                            {<br>+                                /* At lower right corner, just transpose, no mirroring */<br>+                                src_ptr = src_buffer[offset_x]<br>+                                          [dst_blk_y + offset_y];<br>+                                for ( i = 0; i < DCTSIZE; i++ )<br>+                                    for ( j = 0; j < DCTSIZE; j++ )<br>+                                        dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];<br>+                            }<br>+                        }<br>+                    }<br>+                }<br>+            }<br>+        }<br>+    }<br>+}<br>+<br>+/* Execute the actual transformation, if any.<br>+ *<br>+ * This must be called *after* jpeg_write_coefficients, because it depends<br>+ * on jpeg_write_coefficients to have computed subsidiary values such as<br>+ * the per-component width and height fields in the destination object.<br>+ *<br>+ * Note that some transformations will modify the source data arrays!<br>+ */<br>+<br>+LOCAL( void )<br>+jtransform_execute_transform( j_decompress_ptr srcinfo,<br>+                              j_compress_ptr dstinfo,<br>+                              jvirt_barray_ptr * src_coef_arrays,<br>+                              jpeg_transform_info * info ) {<br>+    jvirt_barray_ptr * dst_coef_arrays = info->workspace_coef_arrays;<br>+<br>+    /* Note: conditions tested here should match those in switch statement<br>+     * in jtransform_request_workspace()<br>+     */<br>+    switch ( info->transform )<br>+    {<br>+    case JXFORM_FLIP_H:<br>+        do_flip_h( srcinfo, dstinfo, src_coef_arrays );<br>+        break;<br>+    case JXFORM_FLIP_V:<br>+        do_flip_v( srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays );<br>+        break;<br>+    case JXFORM_TRANSPOSE:<br>+        do_transpose( srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays );<br>+        break;<br>+    case JXFORM_TRANSVERSE:<br>+        do_transverse( srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays );<br>+        break;<br>+    case JXFORM_ROT_90:<br>+        do_rot_90( srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays );<br>+        break;<br>+    case JXFORM_ROT_180:<br>+        do_rot_180( srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays );<br>+        break;<br>+    case JXFORM_ROT_270:<br>+        do_rot_270( srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays );<br>+        break;<br>+    }<br>+}<br>+<br>+/* End of code to handle Auto Orient */<br>+<br> /*<br>  * This function must be fed with a complete compressed frame.<br>  */<br>@@ -186,8 +1356,15 @@ static picture_t * DecodeBlock ( decoder_t * p_dec, block_t * * pp_block )<br>     decoder_sys_t * p_sys = p_dec->p_sys;<br>     block_t * p_block;<br>     picture_t * p_pic = 0;<br>-<br>+    bool b_autoorient;<br>+    int i_otag;<br>     JSAMPARRAY p_row_pointers = NULL;<br>+    jpeg_transform_info transformoption;<br>+    struct jpeg_compress_struct dinfo = { 0 };<br>+    unsigned char * p_dmem = NULL;<br>+    unsigned long l_dmem_size = 0;<br>+    jvirt_barray_ptr * src_coef_arrays;<br>+    jvirt_barray_ptr * dst_coef_arrays;<br> <br>     if ( !pp_block || !*pp_block )<br>     {<br>@@ -209,12 +1386,77 @@ static picture_t * DecodeBlock ( decoder_t * p_dec, block_t * * pp_block )<br>         goto error;<br>     }<br> <br>+    /*<br>+        We only initialise dinfo if we need to rotate a jpeg.<br>+        Make sure we don't try to destroy an uninitialised structure<br>+        if an error occurs<br>+    */<br>+    dinfo.mem = NULL;<br>+<br>     jpeg_create_decompress( &p_sys->p_jpeg );<br>     jpeg_mem_src( &p_sys->p_jpeg, p_block->p_buffer, p_block->i_buffer );<br>-    jpeg_read_header( &p_sys->p_jpeg, TRUE );<br>+    b_autoorient = var_CreateGetBool( p_dec, "jpeg-autoorient" );<br>+<br>+    if ( b_autoorient )<br>+    {<br>+        jpeg_save_markers( &p_sys->p_jpeg, EXIF_JPEG_MARKER, 0xffff );<br>+    }<br> <br>+    jpeg_read_header( &p_sys->p_jpeg, TRUE );<br>     p_sys->p_jpeg.out_color_space = JCS_RGB;<br> <br>+    if ( b_autoorient )<br>+    {<br>+        i_otag = jpeg_GetOrientation( &p_sys->p_jpeg );<br>+        if ( i_otag > 1 ) /* Do we need to orient the image? */<br>+        {<br>+            msg_Info( p_dec, "Orientation is %d", i_otag );<br>+            switch ( i_otag )<br>+            {<br>+            case 2:<br>+                transformoption.transform = JXFORM_FLIP_H;<br>+                break;<br>+            case 3:<br>+                transformoption.transform = JXFORM_ROT_180;<br>+                break;<br>+            case 4:<br>+                transformoption.transform = JXFORM_FLIP_V;<br>+                break;<br>+            case 5:<br>+                transformoption.transform = JXFORM_TRANSPOSE;<br>+                break;<br>+            case 6:<br>+                transformoption.transform = JXFORM_ROT_90;<br>+                break;<br>+            case 7:<br>+                transformoption.transform = JXFORM_TRANSVERSE;<br>+                break;<br>+            case 8:<br>+            default:<br>+                transformoption.transform = JXFORM_ROT_270;<br>+            }<br>+            dinfo.err = jpeg_std_error( &p_sys->err );<br>+            jpeg_create_compress( &dinfo );<br>+            jpeg_copy_critical_parameters( &p_sys->p_jpeg, &dinfo );<br>+            jtransform_request_workspace( &p_sys->p_jpeg, &transformoption );<br>+            src_coef_arrays = jpeg_read_coefficients( &p_sys->p_jpeg );<br>+            dst_coef_arrays = jtransform_adjust_parameters( &dinfo, src_coef_arrays, &transformoption );<br>+            jpeg_mem_dest( &dinfo, &p_dmem, &l_dmem_size );<br>+            jpeg_write_coefficients( &dinfo, dst_coef_arrays );<br>+            jtransform_execute_transform( &p_sys->p_jpeg, &dinfo, src_coef_arrays, &transformoption );<br>+            jpeg_finish_compress( &dinfo );<br>+            jpeg_abort_decompress( &p_sys->p_jpeg );<br>+<br>+            /* Assign any change in height/width */<br>+            p_sys->p_jpeg.image_width = dinfo.image_width;<br>+            p_sys->p_jpeg.image_height = dinfo.image_height;<br>+<br>+            /* Restart processing with orientated image data */<br>+            jpeg_mem_src( &p_sys->p_jpeg, p_dmem, l_dmem_size );<br>+            jpeg_read_header( &p_sys->p_jpeg, TRUE );<br>+        }<br>+    }<br>+<br>     jpeg_start_decompress( &p_sys->p_jpeg );<br> <br>     /* Set output properties */<br>@@ -236,10 +1478,12 @@ static picture_t * DecodeBlock ( decoder_t * p_dec, block_t * * pp_block )<br> <br>     /* Decode picture */<br>     p_row_pointers = malloc( sizeof( JSAMPROW ) * p_sys->p_jpeg.output_height );<br>+<br>     if ( !p_row_pointers )<br>     {<br>         goto error;<br>     }<br>+<br>     for ( unsigned i = 0; i < p_sys->p_jpeg.output_height; i++ )<br>     {<br>         p_row_pointers[i] = p_pic->p->p_pixels + p_pic->p->i_pitch * i;<br>@@ -253,19 +1497,26 @@ static picture_t * DecodeBlock ( decoder_t * p_dec, block_t * * pp_block )<br>     }<br> <br>     jpeg_finish_decompress( &p_sys->p_jpeg );<br>+    jpeg_destroy_compress( &dinfo );<br>     jpeg_destroy_decompress( &p_sys->p_jpeg );<br>+    if ( l_dmem_size )<br>+    {<br>+        free( p_dmem );<br>+    }<br>     free( p_row_pointers );<br>-<br>     p_pic->date = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : p_block->i_dts;<br>-<br>     block_Release( p_block );<br>     return p_pic;<br> <br>  error:<br> <br>+    jpeg_destroy_compress( &dinfo );<br>     jpeg_destroy_decompress( &p_sys->p_jpeg );<br>+    if ( l_dmem_size )<br>+    {<br>+        free( p_dmem );<br>+    }<br>     free( p_row_pointers );<br>-<br>     block_Release( p_block );<br>     return NULL;<br> }<br>-- <br>2.7.4</div>