sbTranscodeAlbumArt.cpp
Go to the documentation of this file.
1 /* vim: set sw=2 :miv */
2 /*
3 //
4 // BEGIN SONGBIRD GPL
5 //
6 // This file is part of the Songbird web player.
7 //
8 // Copyright(c) 2005-2009 POTI, Inc.
9 // http://songbirdnest.com
10 //
11 // This file may be licensed under the terms of of the
12 // GNU General Public License Version 2 (the "GPL").
13 //
14 // Software distributed under the License is distributed
15 // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
16 // express or implied. See the GPL for the specific language
17 // governing rights and limitations.
18 //
19 // You should have received a copy of the GPL along with this
20 // program. If not, go to http://www.gnu.org/licenses/gpl.html
21 // or write to the Free Software Foundation, Inc.,
22 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 //
24 // END SONGBIRD GPL
25 //
26 */
27 
28 #include "sbTranscodeAlbumArt.h"
29 
30 #include <prio.h>
31 
32 #include <nsIIOService.h>
33 #include <nsIURI.h>
34 #include <nsIResProtocolHandler.h>
35 #include <nsIFileProtocolHandler.h>
36 #include <nsIMIMEService.h>
37 #include <nsIProtocolHandler.h>
38 #include <nsIBufferedStreams.h>
39 #include <nsIArray.h>
40 #include <nsIMutableArray.h>
41 #include <nsIFileStreams.h>
42 #include <nsISeekableStream.h>
43 #include <nsIBinaryInputStream.h>
44 
45 #include <imgITools.h>
46 #include <imgIEncoder.h>
47 #include <nsComponentManagerUtils.h>
48 #include <nsTArray.h>
49 #include <nsThreadUtils.h>
50 
51 #include <sbStandardProperties.h>
54 #include <sbMemoryUtils.h>
55 
56 #include <sbIJobProgress.h>
57 #include <sbIFileMetadataService.h>
58 #include <sbIAlbumArtService.h>
59 
60 #include "sbImageTools.h"
61 
62 #define BUFFER_CHUNK_SIZE 1024
63 
66 
68  : mHasAlbumArt(PR_FALSE),
69  mImageHeight(0),
70  mImageWidth(0)
71 {
72 }
73 
75 {
76 }
77 
78 NS_IMETHODIMP
79 sbTranscodeAlbumArt::Init(sbIMediaItem *aItem, nsIArray *aImageFormats)
80 {
81  NS_ENSURE_ARG_POINTER (aItem);
82  NS_ENSURE_ARG_POINTER (aImageFormats);
83 
84  nsresult rv;
85  nsString imageSpec;
86  nsCString cImageSpec;
87 
88  mImageFormats = aImageFormats;
89  mItem = aItem;
90 
91  rv = mItem->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_PRIMARYIMAGEURL),
92  imageSpec);
93  if (NS_FAILED (rv) || imageSpec.IsEmpty()) {
94  mHasAlbumArt = PR_FALSE;
95  return NS_OK;
96  }
97 
98  nsCOMPtr<nsIIOService> ioservice =
99  do_ProxiedGetService("@mozilla.org/network/io-service;1", &rv);
100  NS_ENSURE_SUCCESS(rv, rv);
101 
102  cImageSpec = NS_LossyConvertUTF16toASCII(imageSpec);
103  nsCOMPtr<nsIURI> imageURI;
104  rv = ioservice->NewURI(cImageSpec, nsnull, nsnull,
105  getter_AddRefs(imageURI));
106  NS_ENSURE_SUCCESS(rv, rv);
107 
108  nsCOMPtr<nsIThread> target;
109  rv = NS_GetMainThread(getter_AddRefs(target));
110  NS_ENSURE_SUCCESS(rv, rv);
111 
112  nsCOMPtr<nsIURI> proxiedURI;
113  rv = do_GetProxyForObject(target,
114  NS_GET_IID(nsIURI),
115  imageURI,
116  NS_PROXY_SYNC | NS_PROXY_ALWAYS,
117  getter_AddRefs(proxiedURI));
118  NS_ENSURE_SUCCESS(rv, rv);
119 
120  PRBool isResource;
121  rv = proxiedURI->SchemeIs("resource", &isResource);
122  NS_ENSURE_SUCCESS(rv, rv);
123 
124  if (isResource) {
125  nsCOMPtr<nsIProtocolHandler> resHandler;
126  rv = ioservice->GetProtocolHandler("resource", getter_AddRefs(resHandler));
127  NS_ENSURE_SUCCESS(rv, rv);
128 
129  nsCOMPtr<nsIResProtocolHandler> proxiedResourceProtocolHandler;
130  rv = do_GetProxyForObject(target,
131  NS_GET_IID(nsIResProtocolHandler),
132  resHandler,
133  NS_PROXY_SYNC | NS_PROXY_ALWAYS,
134  getter_AddRefs(proxiedResourceProtocolHandler));
135  NS_ENSURE_SUCCESS(rv, rv);
136 
137  rv = proxiedResourceProtocolHandler->ResolveURI(imageURI, cImageSpec);
138  NS_ENSURE_SUCCESS(rv, rv);
139  }
140 
141  nsCOMPtr<nsIProtocolHandler> fileHandler;
142  rv = ioservice->GetProtocolHandler("file", getter_AddRefs(fileHandler));
143  NS_ENSURE_SUCCESS(rv, rv);
144 
145  nsCOMPtr<nsIFileProtocolHandler> proxiedFileProtocolHandler;
146  rv = do_GetProxyForObject(target,
147  NS_GET_IID(nsIFileProtocolHandler),
148  fileHandler,
149  NS_PROXY_SYNC | NS_PROXY_ALWAYS,
150  getter_AddRefs(proxiedFileProtocolHandler));
151  NS_ENSURE_SUCCESS(rv, rv);
152 
153  nsCOMPtr<nsIFile> imageFile;
154  rv = proxiedFileProtocolHandler->GetFileFromURLSpec(cImageSpec,
155  getter_AddRefs(imageFile));
156  NS_ENSURE_SUCCESS(rv, rv);
157 
158  nsCOMPtr<nsIMIMEService> mimeService =
159  do_ProxiedGetService("@mozilla.org/mime;1", &rv);
160  NS_ENSURE_SUCCESS(rv, rv);
161  rv = mimeService->GetTypeFromFile(imageFile, mImageMimeType);
162  NS_ENSURE_SUCCESS(rv, rv);
163 
164  // Load the actual data from the file; we'll reuse this
165  mInputStream = do_CreateInstance(
166  "@mozilla.org/network/file-input-stream;1", &rv);
167  NS_ENSURE_SUCCESS(rv, rv);
168 
169  rv = mInputStream->Init(imageFile, PR_RDONLY, 0, 0);
170  NS_ENSURE_SUCCESS(rv, rv);
171 
172  nsCOMPtr<nsIBufferedInputStream> bufferedInputStream =
173  do_CreateInstance("@mozilla.org/network/buffered-input-stream;1", &rv);
174  NS_ENSURE_SUCCESS(rv, rv);
175 
176  rv = bufferedInputStream->Init(mInputStream, BUFFER_CHUNK_SIZE);
177  NS_ENSURE_SUCCESS(rv, rv);
178 
179  rv = sbImageTools::DecodeImageData(bufferedInputStream,
180  mImageMimeType,
181  getter_AddRefs(mImgContainer));
182  NS_ENSURE_SUCCESS(rv, rv);
183 
184  rv = mImgContainer->GetHeight(&mImageHeight);
185  NS_ENSURE_SUCCESS(rv, rv);
186 
187  rv = mImgContainer->GetWidth(&mImageWidth);
188  NS_ENSURE_SUCCESS(rv, rv);
189 
190  mHasAlbumArt = PR_TRUE;
191 
192  // Reset the stream so we can reuse it later if required
193  nsCOMPtr<nsISeekableStream> seekableStream =
194  do_QueryInterface(mInputStream, &rv);
195  NS_ENSURE_SUCCESS(rv, rv);
196  rv = seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, 0);
197  NS_ENSURE_SUCCESS(rv, rv);
198 
199  return NS_OK;
200 }
201 
202 nsresult
204  PRBool *aIsValid)
205 {
206  NS_ENSURE_ARG_POINTER (aRange);
207  NS_ENSURE_ARG_POINTER (aVal);
208  NS_ENSURE_ARG_POINTER (aIsValid);
209 
210  nsresult rv;
211  PRUint32 valueCount;
212 
213  rv = aRange->GetValueCount(&valueCount);
214  NS_ENSURE_SUCCESS (rv, rv);
215 
216  if (valueCount == 0) {
217  PRInt32 min, max, step;
218  rv = aRange->GetMin(&min);
219  NS_ENSURE_SUCCESS (rv, rv);
220  rv = aRange->GetMax(&max);
221  NS_ENSURE_SUCCESS (rv, rv);
222  rv = aRange->GetStep(&step);
223  NS_ENSURE_SUCCESS (rv, rv);
224 
225  if (min <= aVal && max >= aVal && (step == 0 || aVal % step == 0)) {
226  *aIsValid = PR_TRUE;
227  }
228  else {
229  *aIsValid = PR_FALSE;
230  }
231  return NS_OK;
232  }
233 
234  for (PRUint32 i = 0; i < valueCount; i++) {
235  PRInt32 val;
236  rv = aRange->GetValue(i, &val);
237  NS_ENSURE_SUCCESS (rv, rv);
238 
239  if (val == aVal) {
240  *aIsValid = PR_TRUE;
241  return NS_OK;
242  }
243  }
244 
245  *aIsValid = PR_FALSE;
246  return NS_OK;
247 }
248 
249 nsresult
251  PRBool *aIsValid)
252 {
253  NS_ENSURE_ARG_POINTER (aFormat);
254  NS_ENSURE_ARG_POINTER (aIsValid);
255 
256  nsresult rv;
257  nsCOMPtr<sbIDevCapRange> widthRange;
258  nsCOMPtr<sbIDevCapRange> heightRange;
259 
260  rv = aFormat->GetSupportedWidths(getter_AddRefs(widthRange));
261  if (NS_SUCCEEDED (rv) && widthRange) {
262  rv = aFormat->GetSupportedHeights(getter_AddRefs(heightRange));
263  if (NS_SUCCEEDED (rv) && heightRange) {
264  // Ok, we have ranges: check if we're within them.
265  PRBool validWidth, validHeight;
266  rv = IsValidSizeForRange(widthRange, mImageWidth, &validWidth);
267  NS_ENSURE_SUCCESS (rv, rv);
268 
269  rv = IsValidSizeForRange(heightRange, mImageHeight, &validHeight);
270  NS_ENSURE_SUCCESS (rv, rv);
271 
272  if (validWidth && validHeight) {
273  *aIsValid = PR_TRUE;
274  return NS_OK;
275  }
276  }
277  }
278 
279  // We don't have ranges, so check for explicit sizes.
280  nsCOMPtr<nsIArray> explicitSizes;
281  rv = aFormat->GetSupportedExplicitSizes(getter_AddRefs(explicitSizes));
282  NS_ENSURE_SUCCESS (rv, rv);
283 
284  PRUint32 numSizes;
285  rv = explicitSizes->GetLength(&numSizes);
286  NS_ENSURE_SUCCESS (rv, rv);
287 
288  for (PRUint32 i = 0; i < numSizes; i++) {
289  nsCOMPtr<sbIImageSize> size;
290  rv = explicitSizes->QueryElementAt(i, NS_GET_IID(sbIImageSize),
291  getter_AddRefs(size));
292  NS_ENSURE_SUCCESS (rv, rv);
293 
294  PRInt32 width, height;
295  rv = size->GetWidth(&width);
296  NS_ENSURE_SUCCESS (rv, rv);
297  rv = size->GetHeight(&height);
298  NS_ENSURE_SUCCESS (rv, rv);
299 
300  if (mImageWidth == width && mImageHeight == height) {
301  *aIsValid = PR_TRUE;
302  return NS_OK;
303  }
304  }
305 
306  *aIsValid = PR_FALSE;
307  return NS_OK;
308 }
309 
310 NS_IMETHODIMP
311 sbTranscodeAlbumArt::GetNeedsAlbumArtConversion(PRBool *aNeedsConversion)
312 {
313  NS_ENSURE_ARG_POINTER (aNeedsConversion);
314  NS_ENSURE_STATE (mImageFormats);
315 
316  nsresult rv;
317 
318  if (!mHasAlbumArt) {
319  *aNeedsConversion = PR_FALSE;
320  return NS_OK;
321  }
322 
323  PRUint32 numFormats = 0;
324  rv = mImageFormats->GetLength(&numFormats);
325  NS_ENSURE_SUCCESS (rv, rv);
326 
327  /* If there are zero supported formats, then rather than saying that it's
328  not supported, we assume that we just don't have any information about
329  what formats are supported for this particular device - so there's no
330  point in converting. After all, what would we convert TO? */
331  if (numFormats == 0) {
332  *aNeedsConversion = PR_FALSE;
333  return NS_OK;
334  }
335 
336  for (PRUint32 i = 0; i < numFormats; i++) {
337  nsCOMPtr<sbIImageFormatType> format;
338  rv = mImageFormats->QueryElementAt(i, NS_GET_IID(sbIImageFormatType),
339  getter_AddRefs(format));
340  NS_ENSURE_SUCCESS (rv, rv);
341 
342  nsCString formatMimeType;
343  rv = format->GetImageFormat(formatMimeType);
344  NS_ENSURE_SUCCESS (rv, rv);
345 
346  if (formatMimeType == mImageMimeType) {
347  // Right format, now let's check sizes...
348  PRBool valid;
349  rv = IsValidSizeForFormat(format, &valid);
350  NS_ENSURE_SUCCESS (rv, rv);
351 
352  if (valid) {
353  *aNeedsConversion = PR_FALSE;
354  return NS_OK;
355  }
356  }
357  }
358 
359  *aNeedsConversion = PR_TRUE;
360  return NS_OK;
361 }
362 
363 static nsresult HaveEncoderForFormat(nsCString mimeType, PRBool *haveEncoder)
364 {
365  nsresult rv;
366  nsCString encoderCID = NS_LITERAL_CSTRING(
367  "@mozilla.org/image/encoder;2?type=");
368  encoderCID.Append(mimeType);
369 
370  nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get(), &rv);
371  if (NS_SUCCEEDED(rv)) {
372  *haveEncoder = PR_TRUE;
373  }
374  else {
375  *haveEncoder = PR_FALSE;
376  }
377 
378  return NS_OK;
379 }
380 
381 NS_IMETHODIMP
383  nsACString & aMimeType, PRInt32 *aWidth, PRInt32 *aHeight)
384 {
385  NS_ENSURE_ARG_POINTER (aWidth);
386  NS_ENSURE_ARG_POINTER (aHeight);
387  NS_ENSURE_STATE (mImageFormats);
388 
389  nsresult rv;
390  /* Figure out the target format as follows:
391 
392  1. If the input width and height are both supported for some format, choose
393  the first such format.
394  2. Otherwise, choose the first format that we have an encoder for.
395  Then, select the smallest explicitly-listed size larger than the
396  input image (unless there are none, in which case use the largest
397  explicit size).
398 
399  Note: if the input aspect ratio is not the same as the output aspect ratio,
400  we do not correctly maintain the image aspect ratio by putting black
401  bars/etc. around it. TODO!
402  */
403 
404  // 1: exact size match.
405  PRUint32 numFormats = 0;
406  rv = mImageFormats->GetLength(&numFormats);
407  NS_ENSURE_SUCCESS (rv, rv);
408  for (PRUint32 i = 0; i < numFormats; i++) {
409  nsCOMPtr<sbIImageFormatType> format;
410  rv = mImageFormats->QueryElementAt(i, NS_GET_IID(sbIImageFormatType),
411  getter_AddRefs(format));
412  NS_ENSURE_SUCCESS (rv, rv);
413 
414  nsCString formatMimeType;
415  rv = format->GetImageFormat(formatMimeType);
416  NS_ENSURE_SUCCESS (rv, rv);
417 
418  PRBool haveEncoder;
419  rv = HaveEncoderForFormat(formatMimeType, &haveEncoder);
420  NS_ENSURE_SUCCESS(rv, rv);
421 
422  // Skip this if we don't have an encoder for it.
423  if (!haveEncoder) {
424  continue;
425  }
426 
427  PRBool valid;
428  rv = IsValidSizeForFormat(format, &valid);
429  NS_ENSURE_SUCCESS (rv, rv);
430 
431  if (valid) {
432  aMimeType = formatMimeType;
433  *aWidth = mImageWidth;
434  *aHeight = mImageHeight;
435  return NS_OK;
436  }
437  }
438 
439  // 2: resize required.
440  nsCOMPtr<sbIImageFormatType> chosenformat;
441  for (PRUint32 i = 0; i < numFormats; i++) {
442  nsCOMPtr<sbIImageFormatType> format;
443  rv = mImageFormats->QueryElementAt(i, NS_GET_IID(sbIImageFormatType),
444  getter_AddRefs(format));
445  NS_ENSURE_SUCCESS (rv, rv);
446 
447  nsCString formatMimeType;
448  rv = format->GetImageFormat(formatMimeType);
449  NS_ENSURE_SUCCESS (rv, rv);
450 
451  PRBool haveEncoder;
452  rv = HaveEncoderForFormat(formatMimeType, &haveEncoder);
453  NS_ENSURE_SUCCESS(rv, rv);
454 
455  if (haveEncoder) {
456  chosenformat = format;
457  break;
458  }
459  }
460 
461  if (!chosenformat)
462  return NS_ERROR_FAILURE;
463 
464  nsCOMPtr<nsIArray> explicitSizes;
465  rv = chosenformat->GetSupportedExplicitSizes(getter_AddRefs(explicitSizes));
466  NS_ENSURE_SUCCESS (rv, rv);
467 
468  rv = chosenformat->GetImageFormat(aMimeType);
469  NS_ENSURE_SUCCESS (rv, rv);
470 
471  PRInt32 bestWidth = 0;
472  PRInt32 bestHeight = 0;
473  PRInt32 bestSmallerWidth = 0;
474  PRInt32 bestSmallerHeight = 0;
475 
476  PRUint32 numSizes = 0;
477  rv = explicitSizes->GetLength(&numSizes);
478  NS_ENSURE_SUCCESS (rv, rv);
479  for (PRUint32 i = 0; i < numSizes; i++) {
480  nsCOMPtr<sbIImageSize> size;
481  rv = explicitSizes->QueryElementAt(i, NS_GET_IID(sbIImageSize),
482  getter_AddRefs(size));
483  NS_ENSURE_SUCCESS (rv, rv);
484 
485  PRInt32 width, height;
486  rv = size->GetWidth(&width);
487  NS_ENSURE_SUCCESS (rv, rv);
488  rv = size->GetHeight(&height);
489  NS_ENSURE_SUCCESS (rv, rv);
490 
491  if (width >= mImageWidth && height >= mImageHeight &&
492  (bestWidth == 0 || bestHeight == 0 ||
493  width < bestWidth || height < bestHeight))
494  {
495  bestWidth = width;
496  bestHeight = height;
497  }
498  else if (width < mImageWidth && height < mImageHeight &&
499  (width > bestSmallerWidth || height > bestSmallerHeight))
500  {
501  bestSmallerWidth = width;
502  bestSmallerHeight = height;
503  }
504  }
505 
506  if (bestWidth && bestHeight) {
507  *aWidth = bestWidth;
508  *aHeight = bestHeight;
509  return NS_OK;
510  }
511  else if (bestSmallerWidth && bestSmallerHeight) {
512  *aWidth = bestSmallerWidth;
513  *aHeight = bestSmallerHeight;
514  return NS_OK;
515  }
516  else {
517  return NS_ERROR_FAILURE;
518  }
519 }
520 
521 NS_IMETHODIMP
522 sbTranscodeAlbumArt::GetTranscodedArt(nsIInputStream **aImageStream)
523 {
524  NS_ENSURE_ARG_POINTER(aImageStream);
525 
526  PRBool needsConversion = PR_FALSE;
527  nsresult rv = GetNeedsAlbumArtConversion(&needsConversion);
528  NS_ENSURE_SUCCESS(rv, rv);
529  if (needsConversion) {
530  nsresult rv;
531  nsCString mimeType;
532  PRInt32 width, height;
533 
534  rv = GetTargetFormat(mimeType, &width, &height);
535  NS_ENSURE_SUCCESS (rv, rv);
536 
537  nsCOMPtr<imgITools> imgTools = do_ProxiedGetService(
538  "@mozilla.org/image/tools;1", &rv);
539  NS_ENSURE_SUCCESS(rv, rv);
540 
541  rv = imgTools->EncodeScaledImage(mImgContainer, mimeType, width, height,
542  aImageStream);
543  NS_ENSURE_SUCCESS(rv, rv);
544 
545  return NS_OK;
546  }
547  else {
548  NS_IF_ADDREF(*aImageStream = mInputStream);
549  return NS_OK;
550  }
551 }
552 
553 NS_IMETHODIMP
555 {
556  NS_ENSURE_STATE (mImageFormats);
557  NS_ENSURE_STATE (mItem);
558 
559  NS_ASSERTION(!NS_IsMainThread(),
560  "ConvertArt must not be called from the main thread");
561 
562  nsresult rv;
563  nsCString mimeType;
564  PRInt32 width, height;
565 
566  rv = GetTargetFormat(mimeType, &width, &height);
567  NS_ENSURE_SUCCESS (rv, rv);
568 
569  nsCOMPtr<imgITools> imgTools = do_ProxiedGetService(
570  "@mozilla.org/image/tools;1", &rv);
571  NS_ENSURE_SUCCESS(rv, rv);
572 
573  nsCOMPtr<nsIInputStream> imageStream;
574  rv = imgTools->EncodeScaledImage(mImgContainer, mimeType, width, height,
575  getter_AddRefs(imageStream));
576  NS_ENSURE_SUCCESS(rv, rv);
577 
578  nsCOMPtr<nsIBinaryInputStream> binaryStream =
579  do_CreateInstance("@mozilla.org/binaryinputstream;1", &rv);
580  NS_ENSURE_SUCCESS(rv, rv);
581 
582  rv = binaryStream->SetInputStream(imageStream);
583  NS_ENSURE_SUCCESS(rv, rv);
584 
585  PRUint32 imageDataLen;
586  rv = imageStream->Available(&imageDataLen);
587  NS_ENSURE_SUCCESS(rv, rv);
588 
589  PRUint8 *imageData;
590  rv = binaryStream->ReadByteArray(imageDataLen, &imageData);
591  NS_ENSURE_SUCCESS(rv, rv);
592 
593  sbAutoNSMemPtr imageDataDestroy(imageData);
594 
595  nsCOMPtr<sbIAlbumArtService> albumArtService = do_ProxiedGetService(
597  NS_ENSURE_SUCCESS(rv, rv);
598 
599  nsCOMPtr<nsIURI> cacheURI;
600  rv = albumArtService->CacheImage(mimeType,
601  imageData,
602  imageDataLen,
603  getter_AddRefs(cacheURI));
604  NS_ENSURE_SUCCESS(rv, rv);
605 
606  nsCString imageURISpec;
607  rv = cacheURI->GetSpec(imageURISpec);
608  NS_ENSURE_SUCCESS(rv, rv);
609 
610  rv = mItem->SetProperty(NS_LITERAL_STRING(SB_PROPERTY_PRIMARYIMAGEURL),
611  NS_ConvertUTF8toUTF16(imageURISpec));
612  NS_ENSURE_SUCCESS(rv, rv);
613 
614  // Ok. We have a replacement image. Now we want to write it to the media item
615  // (which points at the copy of the file on the device).
616  // TODO: what if we can't write to that (e.g. MTP)?
617 
618  nsCOMPtr<nsIMutableArray> mediaItemArray =
619  do_CreateInstance("@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
620  NS_ENSURE_SUCCESS(rv, rv);
621 
622  rv = mediaItemArray->AppendElement(mItem, PR_FALSE);
623  NS_ENSURE_SUCCESS(rv, rv);
624 
625  nsTArray<nsString> propArray;
626  NS_ENSURE_TRUE(propArray.AppendElement(
627  NS_LITERAL_STRING(SB_PROPERTY_PRIMARYIMAGEURL)),
628  NS_ERROR_OUT_OF_MEMORY);
629 
630  nsCOMPtr<nsIStringEnumerator> propsToWrite =
631  new sbTArrayStringEnumerator(&propArray);
632  NS_ENSURE_TRUE(propsToWrite, NS_ERROR_OUT_OF_MEMORY);
633 
634  nsCOMPtr<sbIFileMetadataService> metadataService = do_ProxiedGetService(
635  "@songbirdnest.com/Songbird/FileMetadataService;1", &rv);
636  NS_ENSURE_SUCCESS(rv, rv);
637 
638  nsCOMPtr<sbIJobProgress> job;
639  rv = metadataService->Write(mediaItemArray, propsToWrite,
640  getter_AddRefs(job));
641  NS_ENSURE_SUCCESS(rv, rv);
642 
643  // The job progress object returnned from the this should only be used
644  // from the main thread, so proxy that too.
645  nsCOMPtr<nsIThread> target;
646  rv = NS_GetMainThread(getter_AddRefs(target));
647  NS_ENSURE_SUCCESS(rv, rv);
648 
649  nsCOMPtr<sbIJobProgress> proxiedJob;
650  rv = do_GetProxyForObject(target,
651  NS_GET_IID(sbIJobProgress),
652  job,
653  NS_PROXY_SYNC | NS_PROXY_ALWAYS,
654  getter_AddRefs(proxiedJob));
655  NS_ENSURE_SUCCESS(rv, rv);
656 
657  // Wait until the metadata reading completes. Poll instead of using
658  // callbacks because in practice it'll always be very quick, and this is
659  // simpler.
660  PRBool isRunning = PR_TRUE;
661  while (isRunning) {
662  // Check if the metadata job is running.
663  PRUint16 status;
664  rv = proxiedJob->GetStatus(&status);
665  NS_ENSURE_SUCCESS(rv, rv);
666  isRunning = (status == sbIJobProgress::STATUS_RUNNING);
667 
668  // If still running, sleep a bit and check again.
669  if (isRunning)
670  PR_Sleep(PR_MillisecondsToInterval(100));
671  else if (status == sbIJobProgress::STATUS_FAILED)
672  return NS_ERROR_FAILURE;
673  }
674 
675  // Metadata is written, so we're all done. Yay!
676  return NS_OK;
677 }
678 
return NS_OK
const PR_RDONLY
restoreDimensions aWidth
NS_IMPL_THREADSAFE_ISUPPORTS1(sbTranscodeAlbumArt, sbITranscodeAlbumArt) sbTranscodeAlbumArt
#define SB_ALBUMARTSERVICE_CONTRACTID
void GetTargetFormat(out AUTF8String mimeType, out long width, out long height)
Generic interface for exposing long running jobs to the UI.
nsresult IsValidSizeForFormat(sbIImageFormatType *aFormat, PRBool *aIsValid)
nsresult IsValidSizeForRange(sbIDevCapRange *aRange, PRInt32 aVal, PRBool *aIsValid)
void Init(in sbIMediaItem aItem, in nsIArray aSupportedFormats)
nsresult do_GetProxyForObject(nsIEventTarget *aTarget, REFNSIID aIID, nsISupports *aObj, PRInt32 aProxyType, void **aProxyObject)
function width(ele) rect(ele).width
nsIInputStream GetTranscodedArt()
restoreDimensions aHeight
const unsigned short STATUS_RUNNING
Constant indicating that the job is active.
const sbCreateProxiedComponent do_ProxiedGetService(const nsCID &aCID, nsresult *error=0)
#define BUFFER_CHUNK_SIZE
static nsresult HaveEncoderForFormat(nsCString mimeType, PRBool *haveEncoder)
this _dialogInput val(dateText)
_updateDatepicker height
long GetValue(in unsigned long aIndex)
Interface that defines a single item of media in the system.
#define min(a, b)
const unsigned short STATUS_FAILED
Constant indicating that the job has completed with errors.
_getSelectedPageStyle s i
#define SB_PROPERTY_PRIMARYIMAGEURL
static nsresult DecodeImageData(nsIInputStream *aInStr, const nsACString &aMimeType, imgIContainer **aContainer)