예제 #1
0
bool CHTTPRequestHandler::handleImageRequest(std::string p_sObjectId, CHTTPMessage* pRequest, CHTTPMessage* pResponse)
{
	/*cout << "image request" << endl;
	cout << pRequest->getVarAsInt("width") << "x" << pRequest->getVarAsInt("height") << endl;*/
	
  std::stringstream sSql;
  //OBJECT_TYPE       nObjectType;
  std::string       sExt;
  std::string       sPath;
  std::string       sMimeType;
  SQLQuery  				qry;

  
  string sDevice = pRequest->virtualFolderLayout();
  if(pRequest->GetVarExists("vfolder")) {
    sDevice = pRequest->getGetVar("vfolder");
    if(sDevice == "none")
      sDevice = "";
  }

  object_id_t objectId = HexToInt(p_sObjectId);  
  DbObject* tmp = DbObject::createFromObjectId(objectId, &qry, sDevice);
  if(tmp == NULL) {
		CSharedLog::Log(L_EXT, __FILE__, __LINE__, "unknown object id: %s", p_sObjectId.c_str());
    return false;
  }

  DbObject obj = *tmp;
  delete tmp;

/*
  bool result = false;

  // real image
  if(obj->type() >= ITEM_IMAGE_ITEM && obj->type() < ITEM_IMAGE_ITEM_MAX) {
    result = handleRealImageRequest(obj, pRequest, pResponse);
  }
  // audio file embedded image
  else if(obj->type() >= ITEM_AUDIO_ITEM && obj->type() < ITEM_AUDIO_ITEM_MAX) {
    result = handleAudioEmbeddedImageRequest(obj, pRequest, pResponse);
  }
  // video file thumbnail image
  else if(obj->type() >= ITEM_VIDEO_ITEM && obj->type() < ITEM_VIDEO_ITEM_MAX) {
    result = handleVideoImageRequest(obj, pRequest, pResponse);
  }
  else {
		CSharedLog::Log(L_EXT, __FILE__, __LINE__, "unsupported image request on object type %d", obj->type());
	}

  delete obj;
  return result;
  */
  

  
  
  string sql = qry.build(SQL_GET_OBJECT_DETAILS, objectId, sDevice);
  qry.select(sql);
    
  if(qry.eof()) {
		CSharedLog::Log(L_EXT, __FILE__, __LINE__, "unknown object id: %s", p_sObjectId.c_str());
		return false;
	}

	sPath = qry.result()->asString("PATH") + qry.result()->asString("FILE_NAME");
  sExt  = ExtractFileExt(sPath);
  sMimeType = pRequest->DeviceSettings()->MimeType(sExt);
    
	bool audioFile = false;
	bool videoFile = false;
  bool hasCached = false;
	
	//OBJECT_TYPE type = (OBJECT_TYPE)qry.result()->asInt("TYPE");
	if(obj.type() >= ITEM_IMAGE_ITEM && obj.type() < ITEM_IMAGE_ITEM_MAX) {
		//cout << "request image file " << sPath << endl;
	}
	else if(obj.type() >= ITEM_AUDIO_ITEM && obj.type() < ITEM_AUDIO_ITEM_MAX) {
		//cout << "request image from audio file " << sPath << endl;
		audioFile = true;
	}
	else if(obj.type() >= ITEM_VIDEO_ITEM && obj.type() < ITEM_VIDEO_ITEM_MAX) {
		//cout << "request image from video file " << sPath << endl;
		videoFile = true;

    if(qry.result()->asUInt("ALBUM_ART_ID") > 0) {
      sPath = PathFinder::findThumbnailsDir() + qry.result()->asString("ALBUM_ART_ID") + ".jpg";
      hasCached = fuppes::File::exists(sPath);
      sExt = "jpg";
      sMimeType = pRequest->DeviceSettings()->MimeType(sExt);
    }
	}
	else {
		CSharedLog::Log(L_EXT, __FILE__, __LINE__, "unsupported image request on object type %d", obj.type());
		return false;
	}
    
  if(!fuppes::File::exists(sPath)) {
    CSharedLog::Log(L_EXT, __FILE__, __LINE__, "file: %s not found", sPath.c_str());
    return false;
  }
	//cout << "image request: " << sPath << endl;

	
	int width = pRequest->getVarAsInt("width");
	int height = pRequest->getVarAsInt("height");
	/*int less = pRequest->getVarAsInt("less");
	int greater = pRequest->getVarAsInt("greater");*/
	
	// transcode | scale request via GET
	// and/or embedded image from audio file
	if((width > 0 || height > 0 || audioFile || videoFile) && !hasCached) {
		CSharedLog::Log(L_EXT, __FILE__, __LINE__, "GET transcode %s - %dx%d",  sPath.c_str(), width, height);
		
		size_t inSize = 0;
		size_t outSize = 0;
		unsigned char* inBuffer = (unsigned char*)malloc(1);
		unsigned char* outBuffer = (unsigned char*)malloc(1);
		char tmpMime[100];
		//memset(tmpMime, 0, 1);
		
		// embedded image from audio or video file
		bool transcode = true;
		if(audioFile || videoFile) {

      string plugin;
			if(audioFile) {
        plugin = "taglib";
			}
      else if(videoFile) {
        plugin = "ffmpegthumbnailer";
				transcode = false;
			}

			CMetadataPlugin* metadata = CPluginMgr::metadataPlugin(plugin);
			if(!metadata) {
				CSharedLog::Log(L_EXT, __FILE__, __LINE__, "metadata plugin %s not found", plugin.c_str());
				free(inBuffer);
				free(outBuffer);
				//free(tmpMime);
			  return false;
      }
      
      
			metadata->openFile(sPath);
			inSize = 0;
			if(!metadata->readImage(&tmpMime[0], &inBuffer, &inSize)) {
				metadata->closeFile();
				CSharedLog::Log(L_EXT, __FILE__, __LINE__, "metadata plugin %s failed to read embedded image", "taglib");
				free(inBuffer);
				free(outBuffer);
				//free(tmpMime);
		    return false;
			}
			metadata->closeFile();

      // get the mime type and the extension of the extracted file      
      sMimeType = tmpMime;
      sExt = pRequest->DeviceSettings()->extensionByMimeType(sMimeType);        
			delete metadata;
		} // embedded image



    // an actual image file or a cached image is requested
		else {

      if(hasCached) {
				transcode = false;        
      }
      
			std::fstream fsImg;
			fsImg.open(sPath.c_str(), ios::binary|ios::in);
		  if(fsImg.fail() == 1) {
				CSharedLog::Log(L_EXT, __FILE__, __LINE__, "failed to load image file %s", sPath.c_str());
				free(inBuffer);
				free(outBuffer);
				//free(tmpMime);
			  return false;
			}
			fsImg.seekg(0, ios::end); 
  		inSize = streamoff(fsImg.tellg()); 
  		fsImg.seekg(0, ios::beg);
			inBuffer = (unsigned char*)realloc(inBuffer, inSize);
			fsImg.read((char*)inBuffer, inSize);
			fsImg.close();
		} // image file

		if(transcode) {
			CTranscoderBase* transcoder = CPluginMgr::transcoderPlugin("magickWand");
			if(transcoder == NULL) {
				CSharedLog::Log(L_EXT, __FILE__, __LINE__, "image magick transcoder not available");
				free(inBuffer);
				free(outBuffer);
				//free(tmpMime);
			  return false;
			}
		
			CFileSettings* settings = new CFileSettings(pRequest->DeviceSettings()->FileSettings(sExt));
		
			// TODO fixme. Robert: What are we supposed to be fixing?
			if(!settings->pImageSettings) {
				settings->pImageSettings = new CImageSettings();
			}
			settings->pImageSettings->nHeight = height;
			settings->pImageSettings->nWidth = width;
			settings->pImageSettings->bGreater = true;
			settings->pImageSettings->bLess = true;
		
			transcoder->TranscodeMem(settings,
															 (const unsigned char**)&inBuffer, inSize, &outBuffer, &outSize);
			delete settings;
			delete transcoder;

			pResponse->SetBinContent((char*)outBuffer, outSize);

      // todo: get the actual image dimensions
      //width = width;
      //height = height:
      sMimeType = pRequest->DeviceSettings()->MimeType(sExt);


		} else { // transcode
			pResponse->SetBinContent((char*)inBuffer, inSize);

      width = obj.details()->width();
      height = obj.details()->height();
		}

    
/*
		pResponse->SetMessageType(HTTP_MESSAGE_TYPE_200_OK);
#warning todo: set correct mime type 
    // the current mimeType variable only holds a dummy mime type set above
		pResponse->SetContentType(sMimeType);
*/
		free(inBuffer);
		free(outBuffer);
		//free(tmpMime);
		//return true;
	} // embedded audio or width|height via GET
	

  // a real image file
  else {

    width = obj.details()->width();
    height = obj.details()->height();
    
	  if(pRequest->DeviceSettings()->DoTranscode(sExt, qry.result()->asString("AUDIO_CODEC"), qry.result()->asString("VIDEO_CODEC"))) {
		  CSharedLog::Log(L_EXT, __FILE__, __LINE__, "transcode %s",  sPath.c_str());
   
		  sMimeType = pRequest->DeviceSettings()->MimeType(sExt, qry.result()->asString("AUDIO_CODEC"), qry.result()->asString("VIDEO_CODEC"));
		  if(pRequest->GetMessageType() == HTTP_MESSAGE_TYPE_GET) {          
			  DbObject object(qry.result());
			  if(!pResponse->TranscodeContentFromFile(sPath, &object)) {
				  return false;
			  }
		  }
		  else if(pRequest->GetMessageType() == HTTP_MESSAGE_TYPE_HEAD) {
			  // mark the head response as chunked so
			  // the correct header will be build
			  pResponse->SetIsBinary(true);
				
			  if(pRequest->DeviceSettings()->TranscodingHTTPResponse(sExt) == RESPONSE_CHUNKED) {
				  pResponse->SetTransferEncoding(HTTP_TRANSFER_ENCODING_CHUNKED);
			  }
			  else if(pRequest->DeviceSettings()->TranscodingHTTPResponse(sExt) == RESPONSE_STREAM) {
				  pResponse->SetTransferEncoding(HTTP_TRANSFER_ENCODING_NONE);
			  }
		  }
	  }
	  else {
		  sMimeType = pRequest->DeviceSettings()->MimeType(sExt, qry.result()->asString("AUDIO_CODEC"), qry.result()->asString("VIDEO_CODEC"));
		  pResponse->LoadContentFromFile(sPath);
	  }

  } // a real image file



  
  // dlna
  if(//(pRequest->dlnaGetContentFeatures() == true) &&
     (pRequest->DeviceSettings()->dlnaVersion() != CMediaServerSettings::dlna_none)) {

    std::string mimeType;
    std::string profile;
    DLNA::getImageProfile(sExt, width, height, profile, mimeType);
    sMimeType = mimeType;

    std::string dlnaFeatures = CContentDirectory::buildDlnaInfo(false, profile);
    std::string dlnaMode = "Interactive";

    pResponse->dlnaContentFeatures(dlnaFeatures);
    pResponse->dlnaTransferMode(dlnaMode);        
  }
  
	// we always set the response type to "200 OK"
	// if the message should be a "206 partial content" 
	// CHTTPServer will change the type
	pResponse->SetMessageType(HTTP_MESSAGE_TYPE_200_OK);
	pResponse->SetContentType(sMimeType);

  return true;
}
예제 #2
0
bool CHTTPRequestHandler::handleAVItemRequest(std::string p_sObjectId, CHTTPMessage* pRequest, CHTTPMessage* pResponse, bool audio, std::string requestExt)
{
  std::stringstream sSql;
  //OBJECT_TYPE       nObjectType;
  std::string       sExt;
  std::string       sPath;
  std::string       sMimeType;
  string            targetExt;
  SQLQuery				  qry;
  bool              bResult = true;  
  bool              transcode = false;
  
  unsigned int      objectId = HexToInt(p_sObjectId);
  
  string sDevice = pRequest->virtualFolderLayout();
  string sql = qry.build(SQL_GET_OBJECT_DETAILS, objectId, sDevice);
  qry.select(sql);
  if(qry.eof()) {
    CSharedLog::Log(L_EXT, __FILE__, __LINE__, "unknown object id: %s", p_sObjectId.c_str());
    return false;
  }
  
  // TODO Object Types are still on the todo list
  //nObjectType = (OBJECT_TYPE)atoi(pDb->GetResult()->asString("TYPE").c_str());
  //cout << "OBJECT_TYPE: " << nObjectType << endl;
      
  sPath = qry.result()->asString("PATH") + qry.result()->asString("FILE_NAME");
  sExt  = ExtractFileExt(sPath);
  
  if(!fuppes::File::exists(sPath)) {
    CSharedLog::Log(L_EXT, __FILE__, __LINE__, "file: %s not found", sPath.c_str());
    return false;
  }


  // check for subtitles
  if(!audio && requestExt.compare("srt") == 0) {
    sPath = TruncateFileExt(sPath) + "." + requestExt;
    cout << "SUB REQUEST: " << sPath << "*" << endl;
    if(!fuppes::File::exists(sPath))
      return false;

    pResponse->LoadContentFromFile(sPath);
    pResponse->SetMessageType(HTTP_MESSAGE_TYPE_200_OK);
    pResponse->SetContentType("application/x-subrip");
    return true;
  }

  transcode = pRequest->DeviceSettings()->DoTranscode(sExt, qry.result()->asString("AUDIO_CODEC"), qry.result()->asString("VIDEO_CODEC"));
  sMimeType = pRequest->DeviceSettings()->MimeType(sExt, qry.result()->asString("AUDIO_CODEC"), qry.result()->asString("VIDEO_CODEC"));
  targetExt = pRequest->DeviceSettings()->Extension(sExt, qry.result()->asString("AUDIO_CODEC"), qry.result()->asString("VIDEO_CODEC"));


  if(!transcode) {
    pResponse->LoadContentFromFile(sPath);
  }  
  else {
    CSharedLog::Log(L_EXT, __FILE__, __LINE__, "transcode %s",  sPath.c_str());
 
    if(pRequest->GetMessageType() == HTTP_MESSAGE_TYPE_GET) {  
      DbObject object(qry.result());
      bResult = pResponse->TranscodeContentFromFile(sPath, &object);
    }
    else if(pRequest->GetMessageType() == HTTP_MESSAGE_TYPE_HEAD) {
      // mark the head response as chunked so
      // the correct header will be build
      pResponse->SetIsBinary(true);
      bResult = true;

      if(pRequest->DeviceSettings()->TranscodingHTTPResponse(sExt) == RESPONSE_CHUNKED) {
        pResponse->SetTransferEncoding(HTTP_TRANSFER_ENCODING_CHUNKED);
      }
      else if(pRequest->DeviceSettings()->TranscodingHTTPResponse(sExt) == RESPONSE_STREAM) {
        pResponse->SetTransferEncoding(HTTP_TRANSFER_ENCODING_NONE);
      }
    }
  }
  
  

  // dlna
  if(//(CPluginMgr::dlnaPlugin() != NULL) &&
     //(pRequest->dlnaGetContentFeatures() == true) &&
     (pRequest->DeviceSettings()->dlnaVersion() != CMediaServerSettings::dlna_none)) {

    bool hasProfile = false;
    std::string profile;
    if(audio) {

      int channels = 0;
      int bitrate = 0;
      if(!transcode) {
        channels = qry.result()->asInt("A_CHANNELS");
        bitrate = qry.result()->asInt("A_BITRATE");
      }

      if(audio) {
        hasProfile = DLNA::getAudioProfile(targetExt, channels, bitrate, profile, sMimeType);
      }
      else {
        //hasProfile = CPluginMgr::dlnaPlugin()->getVideoProfile(targetExt, channels, bitrate, &profile, &sMimeType);
      }
    }
    else {
      //CPluginMgr::dlnaPlugin()->getVideoProfile();
    }

    //if(hasProfile) {
      std::string dlnaFeatures = CContentDirectory::buildDlnaInfo(transcode, profile);
      std::string dlnaMode = (transcode ? "Streaming" : "Interactive");

      pResponse->dlnaContentFeatures(dlnaFeatures);
      pResponse->dlnaTransferMode(dlnaMode);
    //}
  } // end dlna
  
  // we always set the response type to "200 OK"
  // if the message should be a "206 partial content" 
  // CHTTPServer will change the type
  pResponse->SetMessageType(HTTP_MESSAGE_TYPE_200_OK);
  pResponse->SetContentType(sMimeType);
  
  bResult = true;
    
  
  return bResult;
}