Esempio n. 1
0
    void PsdImage::doWriteMetadata(BasicIo& outIo)
    {
        if (!io_->isopen()) throw Error(20);
        if (!outIo.isopen()) throw Error(21);

#ifdef DEBUG
        std::cout << "Exiv2::PsdImage::doWriteMetadata: Writing PSD file " << io_->path() << "\n";
        std::cout << "Exiv2::PsdImage::doWriteMetadata: tmp file created " << outIo.path() << "\n";
#endif

        // Ensure that this is the correct image type
        if (!isPsdType(*io_, true)) {
            if (io_->error() || io_->eof()) throw Error(20);
            throw Error(22);
        }

        io_->seek(0, BasicIo::beg);    // rewind

        DataBuf lbuf(4096);
        byte buf[8];

        // Get Photoshop header from original file
        byte psd_head[26];
        if (io_->read(psd_head, 26) != 26) throw Error(3, "Photoshop");

        // Write Photoshop header data out to new PSD file
        if (outIo.write(psd_head, 26) != 26) throw Error(21);

        // Read colorDataLength from original PSD 
        if (io_->read(buf, 4) != 4) throw Error(3, "Photoshop");

        uint32_t colorDataLength = getULong(buf, bigEndian);

        // Write colorDataLength
        ul2Data(buf, colorDataLength, bigEndian);
        if (outIo.write(buf, 4) != 4) throw Error(21);
#ifdef DEBUG
        std::cerr << std::dec << "colorDataLength: " << colorDataLength << "\n";
#endif
        // Copy colorData
        uint32_t readTotal = 0;
        long toRead = 0;
        while (readTotal < colorDataLength) {
            toRead =   static_cast<long>(colorDataLength - readTotal) < lbuf.size_
                     ? colorDataLength - readTotal : lbuf.size_;
            if (io_->read(lbuf.pData_, toRead) != toRead) throw Error(3, "Photoshop");
            readTotal += toRead;
            if (outIo.write(lbuf.pData_, toRead) != toRead) throw Error(21);
        }
        if (outIo.error()) throw Error(21);

        uint32_t resLenOffset = io_->tell();  // remember for later update

        // Read length of all resource blocks from original PSD
        if (io_->read(buf, 4) != 4) throw Error(3, "Photoshop");

        uint32_t oldResLength = getULong(buf, bigEndian);
        uint32_t newResLength = 0;

        // Write oldResLength (will be updated later)
        ul2Data(buf, oldResLength, bigEndian);
        if (outIo.write(buf, 4) != 4) throw Error(21);

#ifdef DEBUG
        std::cerr << std::dec << "oldResLength: " << oldResLength << "\n";
#endif

        // Iterate over original resource blocks.
        // Replace or insert IPTC, EXIF and XMP
        // Original resource blocks assumed to be sorted ASC

        bool iptcDone = false;
        bool exifDone = false;
        bool xmpDone = false;
        while (oldResLength > 0) {
            if (io_->read(buf, 8) != 8) throw Error(3, "Photoshop");

            // read resource type and ID
            uint32_t resourceType = getULong(buf, bigEndian);

            if (resourceType != kPhotoshopResourceType) {
                break; // bad resource type
            }
            uint16_t resourceId = getUShort(buf + 4, bigEndian);
            uint32_t resourceNameLength = buf[6];
            uint32_t adjResourceNameLen = resourceNameLength & ~1;
            unsigned char resourceNameFirstChar = buf[7];

            // read rest of resource name, plus any padding
            DataBuf resName(256);
            if (   io_->read(resName.pData_, adjResourceNameLen)
                != static_cast<long>(adjResourceNameLen)) throw Error(3, "Photoshop");

            // read resource size (actual length w/o padding!)
            if (io_->read(buf, 4) != 4) throw Error(3, "Photoshop"); 

            uint32_t resourceSize = getULong(buf, bigEndian);
            uint32_t curOffset = io_->tell();

            // Write IPTC_NAA resource block
            if (   resourceId == kPhotoshopResourceID_IPTC_NAA
                || (resourceId > kPhotoshopResourceID_IPTC_NAA && iptcDone == false)) {
                newResLength += writeIptcData(iptcData_, outIo);
                resourceSize = (resourceSize + 1) & ~1;    // adjust for padding
                iptcDone = true;
            }

            // Write ExifInfo resource block
            else if (   resourceId == kPhotoshopResourceID_ExifInfo
                     || (resourceId > kPhotoshopResourceID_ExifInfo && exifDone == false)) {
                newResLength += writeExifData(exifData_, outIo);
                resourceSize = (resourceSize + 1) & ~1;    // adjust for padding
                exifDone = true;
            }

            // Write XMPpacket resource block
            else if (   resourceId == kPhotoshopResourceID_XMPPacket
                     || (resourceId > kPhotoshopResourceID_XMPPacket && xmpDone == false)) {
                newResLength += writeXmpData(xmpData_, outIo);
                resourceSize = (resourceSize + 1) & ~1;    // adjust for padding
                xmpDone = true;
            }

            // Copy all other resource blocks
            if (   resourceId != kPhotoshopResourceID_IPTC_NAA
                && resourceId != kPhotoshopResourceID_ExifInfo
                && resourceId != kPhotoshopResourceID_XMPPacket) {
#ifdef DEBUG
                std::cerr << std::hex << "copy : resourceId: " << resourceId << "\n";
                std::cerr << std::dec;
#endif
                // Copy resource block to new PSD file
                ul2Data(buf, kPhotoshopResourceType, bigEndian);
                if (outIo.write(buf, 4) != 4) throw Error(21);
                us2Data(buf, resourceId, bigEndian);
                if (outIo.write(buf, 2) != 2) throw Error(21);
                // Write resource name as Pascal string
                buf[0] = resourceNameLength & 0x000f;
                if (outIo.write(buf, 1) != 1) throw Error(21);
                buf[0] = resourceNameFirstChar;
                if (outIo.write(buf, 1) != 1) throw Error(21);
                if (   outIo.write(resName.pData_, adjResourceNameLen)
                    != static_cast<long>(adjResourceNameLen)) throw Error(21);
                ul2Data(buf, resourceSize, bigEndian);
                if (outIo.write(buf, 4) != 4) throw Error(21);

                readTotal = 0;
                toRead = 0;
                resourceSize = (resourceSize + 1) & ~1;        // pad to even
                while (readTotal < resourceSize) {
                    toRead =   static_cast<long>(resourceSize - readTotal) < lbuf.size_
                             ? resourceSize - readTotal : lbuf.size_;
                    if (io_->read(lbuf.pData_, toRead) != toRead) {
                        throw Error(3, "Photoshop");
                    }
                    readTotal += toRead;
                    if (outIo.write(lbuf.pData_, toRead) != toRead) throw Error(21);
                }
                if (outIo.error()) throw Error(21);
                newResLength += resourceSize + adjResourceNameLen + 12;
            }

            io_->seek(curOffset + resourceSize, BasicIo::beg);
            oldResLength -= (12 + adjResourceNameLen + resourceSize);
        }

        // Append IPTC_NAA resource block, if not yet written
        if (iptcDone == false) {
            newResLength += writeIptcData(iptcData_, outIo);
            iptcDone = true;
        }

        // Append ExifInfo resource block, if not yet written
        if (exifDone == false) {
            newResLength += writeExifData(exifData_, outIo);
            exifDone = true;
        }

        // Append XmpPacket resource block, if not yet written
        if (xmpDone == false) {
            newResLength += writeXmpData(xmpData_, outIo);
            xmpDone = true;
        }

        // Copy remaining data
        long readSize = 0;
        while ((readSize=io_->read(lbuf.pData_, lbuf.size_))) {
            if (outIo.write(lbuf.pData_, readSize) != readSize) throw Error(21);
        }
        if (outIo.error()) throw Error(21);

        // Update length of resources
#ifdef DEBUG
        std::cerr << "newResLength: " << newResLength << "\n";
#endif
        outIo.seek(resLenOffset, BasicIo::beg);
        ul2Data(buf, newResLength, bigEndian);
        if (outIo.write(buf, 4) != 4) throw Error(21);

    } // PsdImage::doWriteMetadata
/*==============================================================================
* Function : CompleteMainImage
* Parameters: QImage
* Return Value : int
* Description: Completes main image encoding.
==============================================================================*/
int OMXJpegEncoder::CompleteMainImage()
{
  OMX_ERRORTYPE lret = OMX_ErrorNone;

  /* Post ETB Done and FTB Done to the queue since we dont want to do a
     callback with the Event thread from the codec layer */
  QI_LOCK(&m_abortlock);

  if (!m_abort_flag && (OMX_FALSE == m_releaseFlag)) {
    //Post EBD to the message queue
    QIMessage *lebdMessage = new QIMessage();
    if (!lebdMessage) {
      QIDBG_ERROR("%s:%d] Could not alloate QIMessage", __func__,  __LINE__);
      QI_UNLOCK(&m_abortlock);
      return QI_ERR_NO_MEMORY;
    }
    lebdMessage->m_qMessage = OMX_MESSAGE_ETB_DONE;
    //The i/p buffer has been consumed completely. Set the nFilledLen to 0x0
    m_currentInBuffHdr->nFilledLen = 0;
    lebdMessage->pData = m_currentInBuffHdr;

    //Post FBD message to the message queue
    QIMessage *lfbdMessage = new QIMessage();
    if (!lfbdMessage) {
      QIDBG_ERROR("%s:%d] Could not allocate QIMessage", __func__,  __LINE__);
      QI_UNLOCK(&m_abortlock);
      return QI_ERR_NO_MEMORY;
    }
    if (NULL != m_memOps.get_memory) {
      omx_jpeg_ouput_buf_t *jpeg_out =
        (omx_jpeg_ouput_buf_t *)m_outputQIBuffer->Addr();

      if ( (m_outputMainImage->FilledLen() + getEstimatedExifSize()) <
          m_outputMainImage->Length() ) {

        QIBuffer lApp1Buf = QIBuffer((uint8_t*)m_outputMainImage->BaseAddr() +
            m_outputMainImage->FilledLen(),
            m_outputMainImage->Length() - m_outputMainImage->FilledLen());

        if ((m_thumbnailInfo.input_height != 0) &&
            (m_thumbnailInfo.input_width != 0)) {
          lret = writeExifData(m_outThumbImage, &lApp1Buf);
        } else {
          lret = writeExifData(NULL, &lApp1Buf);
        }

        if (lret != OMX_ErrorNone) {
          QIDBG_ERROR("%s:%d ", __func__,  __LINE__);
          QI_UNLOCK(&m_abortlock);
          return QI_ERR_GENERAL;
        }

        jpeg_out->size = lApp1Buf.FilledLen() + m_outputMainImage->FilledLen();
        m_memOps.get_memory(jpeg_out);

        if (!jpeg_out->vaddr) {
          QIDBG_ERROR("%s:%d get_memory failed", __func__,  __LINE__);
          return QI_ERR_GENERAL;
        }

        ATRACE_BEGIN("Camera:JPEG:memcpy");
        memcpy(jpeg_out->vaddr, m_outputMainImage->BaseAddr() +
            m_outputMainImage->FilledLen(), lApp1Buf.FilledLen());
        memcpy(jpeg_out->vaddr + lApp1Buf.FilledLen(), m_outputMainImage->BaseAddr(),
            m_outputMainImage->FilledLen());
        ATRACE_END();
        //Set the filled length of the ouput buffer
        m_currentOutBuffHdr->nFilledLen = m_outputMainImage->FilledLen() +
            lApp1Buf.FilledLen();
      } else {
        QIDBG_HIGH("%s:%d Allocating extra temp buffer for Exif ", __func__,  __LINE__);
        uint8_t *exif_buf = (uint8_t*)malloc (getEstimatedExifSize());
        if (exif_buf == NULL) {
          QIDBG_ERROR("%s:%d exif mem alloc failed", __func__,  __LINE__);
          return QI_ERR_GENERAL;
        }
        QIBuffer lApp1Buf = QIBuffer((uint8_t*)exif_buf, getEstimatedExifSize());

        if ((m_thumbnailInfo.input_height != 0) &&
            (m_thumbnailInfo.input_width != 0)) {
          lret = writeExifData(m_outThumbImage, &lApp1Buf);
        } else {
          lret = writeExifData(NULL, &lApp1Buf);
        }

        if (lret != OMX_ErrorNone) {
          QIDBG_ERROR("%s:%d ", __func__,  __LINE__);
          QI_UNLOCK(&m_abortlock);
          free (exif_buf);
          return QI_ERR_GENERAL;
        }

        jpeg_out->size = lApp1Buf.FilledLen() + m_outputMainImage->FilledLen();
        m_memOps.get_memory(jpeg_out);

        if (!jpeg_out->vaddr) {
          QIDBG_ERROR("%s:%d get_memory failed", __func__,  __LINE__);
          free (exif_buf);
          return QI_ERR_GENERAL;
        }

        ATRACE_BEGIN("Camera:JPEG:memcpy");
        memcpy(jpeg_out->vaddr, exif_buf, lApp1Buf.FilledLen());
        memcpy(jpeg_out->vaddr + lApp1Buf.FilledLen(),
            m_outputMainImage->BaseAddr(), m_outputMainImage->FilledLen());
        ATRACE_END();
        //Set the filled length of the ouput buffer
        m_currentOutBuffHdr->nFilledLen = m_outputMainImage->FilledLen() +
            lApp1Buf.FilledLen();
        free (exif_buf);
      }
    } else if (m_outputQIBuffer->Addr() != m_outputMainImage->BaseAddr()) {
      ATRACE_BEGIN("Camera:JPEG:memcpyQI");
      memcpy(m_outputQIBuffer->Addr() + m_outputQIBuffer->FilledLen(),
        m_outputMainImage->BaseAddr(), m_outputMainImage->FilledLen());
      ATRACE_END();
      //Set the filled length of the ouput buffer
      m_currentOutBuffHdr->nFilledLen = m_outputMainImage->FilledLen() +
          m_outputQIBuffer->FilledLen();
    }


    QIDBG_HIGH("%s:%d] Encoded image length %d", __func__, __LINE__,
      (int)m_currentOutBuffHdr->nFilledLen);

    lfbdMessage->m_qMessage = OMX_MESSAGE_FTB_DONE;
    lfbdMessage->pData = m_currentOutBuffHdr;

    lret = postMessage(lebdMessage);
    if (QI_ERROR(lret)) {
      QIDBG_ERROR("%s:%d] Could not send EBD", __func__,  __LINE__);
      delete lebdMessage;
      delete lfbdMessage;
      QI_UNLOCK(&m_abortlock);
      return QI_ERR_NO_MEMORY;
    }

    lret = postMessage(lfbdMessage);
    if (QI_ERROR(lret)) {
      QIDBG_ERROR("%s:%d] Could not send FBD", __func__,  __LINE__);
      delete lfbdMessage;
      QI_UNLOCK(&m_abortlock);
      return QI_ERR_NO_MEMORY;
    }

    // Send message for a new encode process
    QIMessage *lEncodeMessage = new QIMessage();
    if (!lebdMessage) {
      QIDBG_ERROR("%s:%d] Could not alloate QIMessage", __func__,  __LINE__);
      QI_UNLOCK(&m_abortlock);
      return QI_ERR_NO_MEMORY;
    }
    lEncodeMessage->m_qMessage = OMX_MESSAGE_START_NEW_ENCODE;
    lret = postMessage(lEncodeMessage);
    if (QI_ERROR(lret)) {
      QIDBG_ERROR("%s:%d] Could not send Start encode", __func__,  __LINE__);
      delete lEncodeMessage;
      QI_UNLOCK(&m_abortlock);
      return QI_ERR_NO_MEMORY;
    }

  }
  QI_UNLOCK(&m_abortlock);

  return QI_SUCCESS;
}
/*==============================================================================
* Function : EncodeComplete
* Parameters: None
* Return Value : int
* Description: This function is called from the JPEG component when encoding is
* complete
==============================================================================*/
int OMXJpegEncoder::EncodeComplete(QImage *aOutputImage)
{
  QIDBG_MED("%s:%d] ", __func__, __LINE__);
  OMX_ERRORTYPE lret = OMX_ErrorNone;
  QIMessage *lmessage = NULL;

  QI_LOCK(&mEncodeDoneLock);
  if ((m_thumbEncoding == OMX_TRUE) && (m_outThumbImage != NULL) &&
    m_outThumbImage->BaseAddr() == aOutputImage->BaseAddr()) {
    ATRACE_INT("Camera:thumbnail", 0);
    QIDBG_HIGH("%s:%d] Thumbnail Encoding complete.",
      __func__, __LINE__);
    m_thumbEncoding = OMX_FALSE;
    m_thumbEncodingComplete = OMX_TRUE;

    if (NULL == m_memOps.get_memory) {
      lret = writeExifData(aOutputImage, m_outputQIBuffer);
      QIDBG_ERROR("%s:%d] Exif length: %d", __func__,  __LINE__,
        m_outputQIBuffer->FilledLen());
      if (QI_ERROR(lret)) {
        goto error;
      }
    }

    /* send ETB for thumbnail */
    QIMessage *lEtbMessage = new QIMessage();
    if (!lEtbMessage) {
      QIDBG_ERROR("%s:%d] Could not allocate QIMessage", __func__,  __LINE__);
      goto error_nomem;
    }
    lEtbMessage->m_qMessage = OMX_MESSAGE_ETB_DONE;
    lEtbMessage->pData = m_currentInTmbBuffHdr;
    postMessage(lEtbMessage);

    if (m_encoding_mode == OMX_Serial_Encoding) {
      /* Thumbnail exif write successful, Start main image encode */
      lmessage = new QIMessage();
      if (!lmessage) {
        QIDBG_ERROR("%s:%d] Could not allocate QIMessage", __func__,  __LINE__);
        goto error_nomem;
      }
      lmessage->m_qMessage = OMX_MESSAGE_START_MAIN_ENCODE;
      postMessage(lmessage);
      lmessage = NULL;
    } else {
      /* parallel encoding */
      QIDBG_MED("%s:%d] parallel encoding m_mainEncodingComplete %d", __func__,
        __LINE__, m_mainEncodingComplete);

      if (m_outputMainImage != NULL && m_outputMainImage->FilledLen() &&
        (OMX_TRUE == m_mainEncodingComplete)) {
        /* MainImage was finished first, now write MainImage */
        CompleteMainImage();
      }
    }
  } else if (m_outputMainImage != NULL &&
    m_outputMainImage->BaseAddr() == aOutputImage->BaseAddr()) {
    /* main image encoding complete */
    QIDBG_HIGH("%s:%d] MainImage Encoding complete. Filled "
      "Length = %d m_thumbEncodingComplete %d",
      __func__, __LINE__, m_outputMainImage->FilledLen(),
      m_thumbEncodingComplete);
    ATRACE_INT("Camera:JPEG:encode", 0);
    m_mainImageEncoding = OMX_FALSE;
    m_mainEncodingComplete = OMX_TRUE;

    if (m_encoding_mode == OMX_Serial_Encoding) {
      CompleteMainImage();
    } else {
      /* parallel encoding */

      /* thumbnail does not exist OR has already been encoded.
         Write MainImage to EXIF*/
      if (!m_inTmbPort->bEnabled ||
        (m_outThumbImage != NULL && m_outThumbImage->FilledLen()
        && (OMX_TRUE == m_thumbEncodingComplete))) {
        CompleteMainImage();
      }
    }
  }

  QI_UNLOCK(&mEncodeDoneLock);
  return QI_SUCCESS;

error:
  QI_UNLOCK(&mEncodeDoneLock);
  /* Propagate error */
  lmessage = new QIMessage();
  if (lmessage) {
    lmessage->m_qMessage = OMX_MESSAGE_EVENT_ERROR;
    lmessage->iData = lret;
    postMessage(lmessage);
  }
  return QI_ERR_GENERAL;

error_nomem:
  /* TBD: Propagate error */
  QI_UNLOCK(&mEncodeDoneLock);
  return QI_ERR_NO_MEMORY;
}
/*==============================================================================
* Function : encodeImage
* Parameters: OMX_BUFFERHEADERTYPE *a_inBuffer - Input Buffer passed during
* ETB, OMX_BUFFERHEADERTYPE *a_outBuffer - O/p buffer passed during FTB
* Return Value : OMX_ERRORTYPE
* Description: Start Image Encoding
==============================================================================*/
OMX_ERRORTYPE OMXJpegEncoder::encodeImage(
  OMX_BUFFERHEADERTYPE *a_inBuffer,
  OMX_BUFFERHEADERTYPE *a_inTmbBuffer,
  OMX_BUFFERHEADERTYPE *a_outBuffer)
{
  OMX_ERRORTYPE lret = OMX_ErrorNone;

  if (!a_inBuffer || !a_outBuffer) {
    QIDBG_ERROR("%s:%d] Bad parameter",  __func__, __LINE__);
    return OMX_ErrorBadParameter;
  }
  if (m_state == OMX_StateInvalid) {
    QIDBG_ERROR("%s:%d] Invalid State",  __func__, __LINE__);
    return OMX_ErrorInvalidState;
  }

  pthread_mutex_lock(&m_abortlock);
  m_releaseFlag = OMX_FALSE;
  if (!m_abort_flag) {

    m_mainEncodingComplete = OMX_FALSE;
    if ((m_mainEncodeParams.Rotation() != (uint32_t)m_rotation.nRotation) &&
        (!m_mainEncodeParams.Rotation() || !m_rotation.nRotation)) {
      if (NULL != m_mainEncoder) {
        delete m_mainEncoder;
        m_mainEncoder = NULL;
      }
    }
    lret = configureEncodedata();
    if (lret != OMX_ErrorNone) {
      QIDBG_ERROR("%s:%d] Error in Encode configuration", __func__, __LINE__);
      goto error;
    }
    lret = configureBuffers(a_inBuffer, a_outBuffer);
    if (lret != OMX_ErrorNone) {
      QIDBG_ERROR("%s:%d] Error in Encode buffer configuration", __func__, __LINE__);
      goto error;
    }
    if ((m_thumbnailInfo.input_height != 0) &&
      (m_thumbnailInfo.input_width != 0)) {
      // Configure thumbnail buffer
      m_thumbEncodingComplete = OMX_FALSE;
      lret = configureTmbBuffer(a_inTmbBuffer);
      if (lret != OMX_ErrorNone) {
        QIDBG_ERROR("%s:%d] Error in Thumbnail bufffer configuration",
            __func__, __LINE__);
        goto error;
      }

      lret = configureThumbnailData();
      if (lret != OMX_ErrorNone) {
        QIDBG_ERROR("%s:%d] Error in Encode configuration", __func__, __LINE__);
        goto error;
      }

      /* Monochrome can only be encoded with HW encoder. Thus, switch to
         serial and use the HW for both thumbnail and main*/
      if (m_thumbFormat == QI_MONOCHROME) {
         m_encoding_mode = OMX_Serial_Encoding;
      }

      /* If Parallel encoding is enabled, encode both main image and thumbnail
         in parallel. Start main image first followed by thumbnail */
      if (m_encoding_mode == OMX_Parallel_Encoding) {
        lret = startEncode();
        if (lret != OMX_ErrorNone) {
          QIDBG_ERROR("%s:%d] Error in Start Encode", __func__, __LINE__);
          goto error;
        }
        lret = startThumbnailEncode();
        if (lret != OMX_ErrorNone) {
          QIDBG_ERROR("%s:%d] Error in Starting thumbnail encode",
            __func__, __LINE__);
          goto error;
        }
      } else {
        /*If serial encoding start thumbnail first*/
        lret = startThumbnailEncode();
        if (lret != OMX_ErrorNone) {
          QIDBG_ERROR("%s:%d] Error in Starting thumbnail encode",
            __func__, __LINE__);
          goto error;
        }
      }
    } else {
      /*If thumbnail is not present we call write exif from
        here with thumbnail as NULL*/
      if (NULL == m_memOps.get_memory) {
        lret = writeExifData(NULL, m_outputQIBuffer);
        if (lret != OMX_ErrorNone) {
          QIDBG_ERROR("%s:%d] Error in Exif Composer", __func__, __LINE__);
          goto error;
        }
        QIDBG_MED("%s:%d] Finished writing Exif", __func__, __LINE__);
      }
      lret = startEncode();
      if (lret != OMX_ErrorNone) {
        QIDBG_ERROR("%s:%d] Error in Start Encode", __func__, __LINE__);
        goto error;
      }
    }
  }

error:
  pthread_mutex_unlock(&m_abortlock);
  return lret;
}