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; }