Patch by SHINTA: add MediaPlayer cover image/artwork support.

This implemented #7430 enhancement.
Arigato gozaimasu!


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41271 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Philippe Houdoin 2011-04-20 17:58:07 +00:00
parent bf3381e771
commit ec2878c3cf
10 changed files with 670 additions and 202 deletions

View File

@ -77,6 +77,7 @@ Application MediaPlayer :
# supplier
AudioTrackSupplier.cpp
ImageTrackVideoSupplier.cpp
MediaFileTrackSupplier.cpp
MediaTrackAudioSupplier.cpp
MediaTrackVideoSupplier.cpp

View File

@ -14,39 +14,48 @@
#include <FindDirectory.h>
#include <MediaFile.h>
#include <Path.h>
#include <TranslationUtils.h>
#include "MediaFileTrackSupplier.h"
#include "SubTitlesSRT.h"
static const char* kPathKey = "path";
FilePlaylistItem::FilePlaylistItem(const entry_ref& ref)
:
fRef(ref),
fNameInTrash("")
{
fRefs.push_back(ref);
fNamesInTrash.push_back("");
}
FilePlaylistItem::FilePlaylistItem(const FilePlaylistItem& other)
:
fRef(other.fRef),
fNameInTrash(other.fNameInTrash)
fRefs(other.fRefs),
fNamesInTrash(other.fNamesInTrash),
fImageRefs(other.fImageRefs),
fImageNamesInTrash(other.fImageNamesInTrash)
{
}
FilePlaylistItem::FilePlaylistItem(const BMessage* archive)
:
fRef(),
fNameInTrash("")
{
const char* path;
if (archive != NULL && archive->FindString(kPathKey, &path) == B_OK) {
if (get_ref_for_path(path, &fRef) != B_OK)
fRef = entry_ref();
entry_ref ref;
if (archive != NULL) {
int32 i = 0;
while (archive->FindString(kPathKey, i, &path) == B_OK) {
if (get_ref_for_path(path, &ref) == B_OK) {
fRefs.push_back(ref);
}
i++;
}
}
if (fRefs.empty()) {
fRefs.push_back(entry_ref());
}
for (vector<entry_ref>::size_type i = 0; i < fRefs.size(); i++) {
fNamesInTrash.push_back("");
}
}
@ -82,11 +91,16 @@ FilePlaylistItem::Archive(BMessage* into, bool deep) const
status_t ret = BArchivable::Archive(into, deep);
if (ret != B_OK)
return ret;
BPath path(&fRef);
ret = path.InitCheck();
if (ret == B_OK)
for (vector<entry_ref>::size_type i = 0; i < fRefs.size(); i++) {
BPath path(&fRefs[i]);
ret = path.InitCheck();
if (ret != B_OK)
return ret;
ret = into->AddString(kPathKey, path.Path());
return ret;
if (ret != B_OK)
return ret;
}
return B_OK;
}
@ -97,7 +111,7 @@ FilePlaylistItem::SetAttribute(const Attribute& attribute,
switch (attribute) {
case ATTR_STRING_NAME:
{
BEntry entry(&fRef, false);
BEntry entry(&fRefs[0], false);
return entry.Rename(string.String(), false);
}
@ -135,7 +149,7 @@ FilePlaylistItem::GetAttribute(const Attribute& attribute,
BString& string) const
{
if (attribute == ATTR_STRING_NAME) {
string = fRef.name;
string = fRefs[0].name;
return B_OK;
}
@ -194,7 +208,7 @@ FilePlaylistItem::GetAttribute(const Attribute& attribute,
BString
FilePlaylistItem::LocationURI() const
{
BPath path(&fRef);
BPath path(&fRefs[0]);
BString locationURI("file://");
locationURI << path.Path();
return locationURI;
@ -204,7 +218,7 @@ FilePlaylistItem::LocationURI() const
status_t
FilePlaylistItem::GetIcon(BBitmap* bitmap, icon_size iconSize) const
{
BNode node(&fRef);
BNode node(&fRefs[0]);
BNodeInfo info(&node);
return info.GetTrackerIcon(bitmap, iconSize);
}
@ -213,150 +227,82 @@ FilePlaylistItem::GetIcon(BBitmap* bitmap, icon_size iconSize) const
status_t
FilePlaylistItem::MoveIntoTrash()
{
if (fNameInTrash.Length() != 0) {
if (fNamesInTrash[0].Length() != 0) {
// Already in the trash!
return B_ERROR;
}
char trashPath[B_PATH_NAME_LENGTH];
status_t err = find_directory(B_TRASH_DIRECTORY, fRef.device,
true /*create it*/, trashPath, B_PATH_NAME_LENGTH);
if (err != B_OK) {
fprintf(stderr, "failed to find Trash: %s\n", strerror(err));
status_t err;
err = _MoveIntoTrash(&fRefs, &fNamesInTrash);
if (err != B_OK)
return err;
}
if (fImageRefs.empty())
return B_OK;
BEntry entry(&fRef);
err = entry.InitCheck();
if (err != B_OK) {
fprintf(stderr, "failed to init BEntry for %s: %s\n",
fRef.name, strerror(err));
err = _MoveIntoTrash(&fImageRefs, &fImageNamesInTrash);
if (err != B_OK)
return err;
}
BDirectory trashDir(trashPath);
if (err != B_OK) {
fprintf(stderr, "failed to init BDirectory for %s: %s\n",
trashPath, strerror(err));
return err;
}
// Find a unique name for the entry in the trash
fNameInTrash = fRef.name;
int32 uniqueNameIndex = 1;
while (true) {
BEntry test(&trashDir, fNameInTrash.String());
if (!test.Exists())
break;
fNameInTrash = fRef.name;
fNameInTrash << ' ' << uniqueNameIndex;
uniqueNameIndex++;
}
// Remember the original path
BPath originalPath;
entry.GetPath(&originalPath);
// Finally, move the entry into the trash
err = entry.MoveTo(&trashDir, fNameInTrash.String());
if (err != B_OK) {
fprintf(stderr, "failed to move entry into trash %s: %s\n",
trashPath, strerror(err));
return err;
}
// Allow Tracker to restore this entry
BNode node(&entry);
BString originalPathString(originalPath.Path());
node.WriteAttrString("_trk/original_path", &originalPathString);
return err;
return B_OK;
}
status_t
FilePlaylistItem::RestoreFromTrash()
{
if (fNameInTrash.Length() <= 0) {
if (fNamesInTrash[0].Length() <= 0) {
// Not in the trash!
return B_ERROR;
}
char trashPath[B_PATH_NAME_LENGTH];
status_t err = find_directory(B_TRASH_DIRECTORY, fRef.device,
false /*create it*/, trashPath, B_PATH_NAME_LENGTH);
if (err != B_OK) {
fprintf(stderr, "failed to find Trash: %s\n", strerror(err));
status_t err;
err = _RestoreFromTrash(&fRefs, &fNamesInTrash);
if (err != B_OK)
return err;
}
// construct the entry to the file in the trash
// TODO: BEntry(const BDirectory* directory, const char* path) is broken!
// BEntry entry(trashPath, fNamesInTrash[i].String());
BPath path(trashPath, fNameInTrash.String());
BEntry entry(path.Path());
err = entry.InitCheck();
if (err != B_OK) {
fprintf(stderr, "failed to init BEntry for %s: %s\n",
fNameInTrash.String(), strerror(err));
if (fImageRefs.empty())
return B_OK;
err = _RestoreFromTrash(&fImageRefs, &fImageNamesInTrash);
if (err != B_OK)
return err;
}
//entry.GetPath(&path);
//printf("moving '%s'\n", path.Path());
// construct the folder of the original entry_ref
node_ref nodeRef;
nodeRef.device = fRef.device;
nodeRef.node = fRef.directory;
BDirectory originalDir(&nodeRef);
err = originalDir.InitCheck();
if (err != B_OK) {
fprintf(stderr, "failed to init original BDirectory for "
"%s: %s\n", fRef.name, strerror(err));
return err;
}
//path.SetTo(&originalDir, fItems[i].name);
//printf("as '%s'\n", path.Path());
// Reset the name here, the user may have already moved the entry
// out of the trash via Tracker for example.
fNameInTrash = "";
// Finally, move the entry back into the original folder
err = entry.MoveTo(&originalDir, fRef.name);
if (err != B_OK) {
fprintf(stderr, "failed to restore entry from trash "
"%s: %s\n", fRef.name, strerror(err));
return err;
}
// Remove the attribute that helps Tracker restore the entry.
BNode node(&entry);
node.RemoveAttr("_trk/original_path");
return err;
return B_OK;
}
// #pragma mark -
TrackSupplier*
FilePlaylistItem::CreateTrackSupplier() const
{
BMediaFile* mediaFile = new(std::nothrow) BMediaFile(&fRef);
if (mediaFile == NULL)
return NULL;
MediaFileTrackSupplier* supplier
= new(std::nothrow) MediaFileTrackSupplier(mediaFile);
if (supplier == NULL) {
delete mediaFile;
= new(std::nothrow) MediaFileTrackSupplier();
if (supplier == NULL)
return NULL;
for (vector<entry_ref>::size_type i = 0; i < fRefs.size(); i++) {
BMediaFile* mediaFile = new(std::nothrow) BMediaFile(&fRefs[i]);
if (mediaFile == NULL) {
delete supplier;
return NULL;
}
if (supplier->AddMediaFile(mediaFile) != B_OK)
delete mediaFile;
}
for (vector<entry_ref>::size_type i = 0; i < fImageRefs.size(); i++) {
BBitmap* bitmap = BTranslationUtils::GetBitmap(&fImageRefs[i]);
if (bitmap == NULL)
continue;
if (supplier->AddBitmap(bitmap) != B_OK)
delete bitmap;
}
// Search for subtitle files in the same folder
// TODO: Error checking
BEntry entry(&fRef, true);
BEntry entry(&fRefs[0], true);
char originalName[B_FILE_NAME_LENGTH];
entry.GetName(originalName);
@ -410,11 +356,41 @@ FilePlaylistItem::CreateTrackSupplier() const
}
status_t
FilePlaylistItem::AddRef(const entry_ref& ref)
{
fRefs.push_back(ref);
fNamesInTrash.push_back("");
return B_OK;
}
status_t
FilePlaylistItem::AddImageRef(const entry_ref& ref)
{
fImageRefs.push_back(ref);
fImageNamesInTrash.push_back("");
return B_OK;
}
const entry_ref&
FilePlaylistItem::ImageRef() const
{
static entry_ref ref;
if (fImageRefs.empty())
return ref;
return fImageRefs[0];
}
status_t
FilePlaylistItem::_SetAttribute(const char* attrName, type_code type,
const void* data, size_t size)
{
BEntry entry(&fRef, true);
BEntry entry(&fRefs[0], true);
BNode node(&entry);
if (node.InitCheck() != B_OK)
return node.InitCheck();
@ -433,7 +409,7 @@ status_t
FilePlaylistItem::_GetAttribute(const char* attrName, type_code type,
void* data, size_t size)
{
BEntry entry(&fRef, true);
BEntry entry(&fRefs[0], true);
BNode node(&entry);
if (node.InitCheck() != B_OK)
return node.InitCheck();
@ -447,3 +423,128 @@ FilePlaylistItem::_GetAttribute(const char* attrName, type_code type,
return B_OK;
}
status_t
FilePlaylistItem::_MoveIntoTrash(vector<entry_ref>* refs,
vector<BString>* namesInTrash)
{
char trashPath[B_PATH_NAME_LENGTH];
status_t err = find_directory(B_TRASH_DIRECTORY, (*refs)[0].device,
true /*create it*/, trashPath, B_PATH_NAME_LENGTH);
if (err != B_OK) {
fprintf(stderr, "failed to find Trash: %s\n", strerror(err));
return err;
}
BDirectory trashDir(trashPath);
if (err != B_OK) {
fprintf(stderr, "failed to init BDirectory for %s: %s\n",
trashPath, strerror(err));
return err;
}
for (vector<entry_ref>::size_type i = 0; i < refs->size(); i++) {
BEntry entry(&(*refs)[i]);
err = entry.InitCheck();
if (err != B_OK) {
fprintf(stderr, "failed to init BEntry for %s: %s\n",
(*refs)[i].name, strerror(err));
return err;
}
// Find a unique name for the entry in the trash
(*namesInTrash)[i] = (*refs)[i].name;
int32 uniqueNameIndex = 1;
while (true) {
BEntry test(&trashDir, (*namesInTrash)[i].String());
if (!test.Exists())
break;
(*namesInTrash)[i] = (*refs)[i].name;
(*namesInTrash)[i] << ' ' << uniqueNameIndex;
uniqueNameIndex++;
}
// Remember the original path
BPath originalPath;
entry.GetPath(&originalPath);
// Finally, move the entry into the trash
err = entry.MoveTo(&trashDir, (*namesInTrash)[i].String());
if (err != B_OK) {
fprintf(stderr, "failed to move entry into trash %s: %s\n",
trashPath, strerror(err));
return err;
}
// Allow Tracker to restore this entry
BNode node(&entry);
BString originalPathString(originalPath.Path());
node.WriteAttrString("_trk/original_path", &originalPathString);
}
return B_OK;
}
status_t
FilePlaylistItem::_RestoreFromTrash(vector<entry_ref>* refs,
vector<BString>* namesInTrash)
{
char trashPath[B_PATH_NAME_LENGTH];
status_t err = find_directory(B_TRASH_DIRECTORY, (*refs)[0].device,
false /*create it*/, trashPath, B_PATH_NAME_LENGTH);
if (err != B_OK) {
fprintf(stderr, "failed to find Trash: %s\n", strerror(err));
return err;
}
for (vector<entry_ref>::size_type i = 0; i < refs->size(); i++) {
// construct the entry to the file in the trash
// TODO: BEntry(const BDirectory* directory, const char* path) is broken!
// BEntry entry(trashPath, (*namesInTrash)[i].String());
BPath path(trashPath, (*namesInTrash)[i].String());
BEntry entry(path.Path());
err = entry.InitCheck();
if (err != B_OK) {
fprintf(stderr, "failed to init BEntry for %s: %s\n",
(*namesInTrash)[i].String(), strerror(err));
return err;
}
//entry.GetPath(&path);
//printf("moving '%s'\n", path.Path());
// construct the folder of the original entry_ref
node_ref nodeRef;
nodeRef.device = (*refs)[i].device;
nodeRef.node = (*refs)[i].directory;
BDirectory originalDir(&nodeRef);
err = originalDir.InitCheck();
if (err != B_OK) {
fprintf(stderr, "failed to init original BDirectory for "
"%s: %s\n", (*refs)[i].name, strerror(err));
return err;
}
//path.SetTo(&originalDir, fItems[i].name);
//printf("as '%s'\n", path.Path());
// Reset the name here, the user may have already moved the entry
// out of the trash via Tracker for example.
(*namesInTrash)[i] = "";
// Finally, move the entry back into the original folder
err = entry.MoveTo(&originalDir, (*refs)[i].name);
if (err != B_OK) {
fprintf(stderr, "failed to restore entry from trash "
"%s: %s\n", (*refs)[i].name, strerror(err));
return err;
}
// Remove the attribute that helps Tracker restore the entry.
BNode node(&entry);
node.RemoveAttr("_trk/original_path");
}
return B_OK;
}

View File

@ -7,8 +7,13 @@
#include "PlaylistItem.h"
#include <vector>
#include <Entry.h>
using std::vector;
class FilePlaylistItem : public PlaylistItem {
public:
FilePlaylistItem(const entry_ref& ref);
@ -50,7 +55,11 @@ public:
// playback
virtual TrackSupplier* CreateTrackSupplier() const;
const entry_ref& Ref() const { return fRef; }
status_t AddRef(const entry_ref& ref);
const entry_ref& Ref() const { return fRefs[0]; }
status_t AddImageRef(const entry_ref& ref);
const entry_ref& ImageRef() const;
private:
status_t _SetAttribute(const char* attrName,
@ -59,10 +68,18 @@ private:
status_t _GetAttribute(const char* attrName,
type_code type, void* data,
size_t size);
status_t _MoveIntoTrash(vector<entry_ref>* refs,
vector<BString>* namesInTrash);
status_t _RestoreFromTrash(vector<entry_ref>* refs,
vector<BString>* namesInTrash);
private:
entry_ref fRef;
BString fNameInTrash;
// always fRefs.size() == fNamesInTrash.size()
vector<entry_ref> fRefs;
vector<BString> fNamesInTrash;
// always fImageRefs.size() == fImageNamesInTrash.size()
vector<entry_ref> fImageRefs;
vector<BString> fImageNamesInTrash;
};
#endif // FILE_PLAYLIST_ITEM_H

View File

@ -57,14 +57,20 @@ ImportPLItemsCommand::ImportPLItemsCommand(Playlist* playlist,
memset(fNewItems, 0, fNewCount * sizeof(PlaylistItem*));
// init new entries
int32 added = 0;
for (int32 i = 0; i < fNewCount; i++) {
fNewItems[i] = temp.ItemAtFast(i)->Clone();
if (fNewItems[i] == NULL) {
// indicate bad object init
_CleanUp(fNewItems, fNewCount, true);
return;
FilePlaylistItem* fileItem = dynamic_cast<FilePlaylistItem*>(temp.ItemAtFast(i));
if (fileItem && !Playlist::ExtraMediaExists(playlist, fileItem->Ref())) {
fNewItems[added] = temp.ItemAtFast(i)->Clone();
if (fNewItems[added] == NULL) {
// indicate bad object init
_CleanUp(fNewItems, fNewCount, true);
return;
}
added++;
}
}
fNewCount = added;
fPlaylingIndex = fPlaylist->CurrentItemIndex();

View File

@ -456,8 +456,11 @@ Playlist::AppendRefs(const BMessage* refsReceivedMessage, int32 appendIndex)
} else {
if (_IsQuery(type))
AppendQueryToPlaylist(ref, &subPlaylist);
else
AppendToPlaylistRecursive(ref, &subPlaylist);
else {
if ( !ExtraMediaExists(this, ref) ) {
AppendToPlaylistRecursive(ref, &subPlaylist);
}
}
// At least sort this subsection of the playlist
// if the whole playlist is not sorted anymore.
@ -510,7 +513,11 @@ Playlist::AppendToPlaylistRecursive(const entry_ref& ref, Playlist* playlist)
BString mimeString = _MIMEString(&ref);
if (_IsMediaFile(mimeString)) {
PlaylistItem* item = new (std::nothrow) FilePlaylistItem(ref);
if (item != NULL && !playlist->AddItem(item))
if (!ExtraMediaExists(playlist, ref)) {
_BindExtraMedia(item);
if (item != NULL && !playlist->AddItem(item))
delete item;
} else
delete item;
} else
printf("MIME Type = %s\n", mimeString.String());
@ -584,9 +591,42 @@ Playlist::NotifyImportFailed()
}
/*static*/ bool
Playlist::ExtraMediaExists(Playlist* playlist, const entry_ref& ref)
{
BString exceptExtension = _GetExceptExtension(BPath(&ref).Path());
for (int32 i = 0; i < playlist->CountItems(); i++) {
FilePlaylistItem* compare = dynamic_cast<FilePlaylistItem*>(playlist->ItemAt(i));
if (compare == NULL)
continue;
if (compare->Ref() != ref
&& _GetExceptExtension(BPath(&compare->Ref()).Path()) == exceptExtension )
return true;
}
return false;
}
// #pragma mark - private
/*static*/ bool
Playlist::_IsImageFile(const BString& mimeString)
{
BMimeType superType;
BMimeType fileType(mimeString.String());
if (fileType.GetSupertype(&superType) != B_OK)
return false;
if (superType == "image")
return true;
return false;
}
/*static*/ bool
Playlist::_IsMediaFile(const BString& mimeString)
{
@ -668,6 +708,62 @@ Playlist::_MIMEString(const entry_ref* ref)
}
// _BindExtraMedia() searches additional videos and audios
// and addes them as extra medias.
/*static*/ void
Playlist::_BindExtraMedia(PlaylistItem* item)
{
FilePlaylistItem* fileItem = dynamic_cast<FilePlaylistItem*>(item);
if (!item)
return;
// If the media file is foo.mp3, _BindExtraMedia() searches foo.avi.
BPath mediaFilePath(&fileItem->Ref());
BString mediaFilePathString = mediaFilePath.Path();
BPath dirPath;
mediaFilePath.GetParent(&dirPath);
BDirectory dir(dirPath.Path());
if (dir.InitCheck() != B_OK)
return;
BEntry entry;
BString entryPathString;
while (dir.GetNextEntry(&entry, true) == B_OK) {
if (!entry.IsFile())
continue;
entryPathString = BPath(&entry).Path();
if (entryPathString != mediaFilePathString
&& _GetExceptExtension(entryPathString) == _GetExceptExtension(mediaFilePathString)) {
_BindExtraMedia(fileItem, entry);
}
}
}
/*static*/ void
Playlist::_BindExtraMedia(FilePlaylistItem* fileItem, const BEntry& entry)
{
entry_ref ref;
entry.GetRef(&ref);
BString mimeString = _MIMEString(&ref);
if (_IsMediaFile(mimeString)) {
fileItem->AddRef(ref);
} else if (_IsImageFile(mimeString)) {
fileItem->AddImageRef(ref);
}
}
/*static*/ BString
Playlist::_GetExceptExtension(const BString& path)
{
int32 periodPos = path.FindLast('.');
if (periodPos <= path.FindLast('/'))
return path;
return BString(path.String(), periodPos);
}
// #pragma mark - notifications

View File

@ -25,6 +25,7 @@
#include <List.h>
#include <Locker.h>
#include "FilePlaylistItem.h"
#include "PlaylistItem.h"
class BDataIO;
@ -113,17 +114,23 @@ public:
void NotifyImportFailed();
static bool ExtraMediaExists(Playlist* playlist, const entry_ref& ref);
private:
Playlist(const Playlist& other);
Playlist& operator=(const Playlist& other);
// unimplemented
static bool _IsImageFile(const BString& mimeString);
static bool _IsMediaFile(const BString& mimeString);
static bool _IsTextPlaylist(const BString& mimeString);
static bool _IsBinaryPlaylist(const BString& mimeString);
static bool _IsPlaylist(const BString& mimeString);
static bool _IsQuery(const BString& mimeString);
static BString _MIMEString(const entry_ref* ref);
static void _BindExtraMedia(PlaylistItem* item);
static void _BindExtraMedia(FilePlaylistItem* fileItem, const BEntry& entry);
static BString _GetExceptExtension(const BString& path);
void _NotifyItemAdded(PlaylistItem*,
int32 index) const;

View File

@ -0,0 +1,117 @@
/*
* Copyright 2011, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* SHINTA
*/
#include "ImageTrackVideoSupplier.h"
#include <string.h>
ImageTrackVideoSupplier::ImageTrackVideoSupplier(BBitmap* bitmap,
int32 trackIndex, status_t& initStatus)
:
VideoTrackSupplier(),
fPerformanceTime(0),
fDuration(0),
fCurrentFrame(0),
fBitmap(bitmap),
fTrackIndex(trackIndex)
{
fFormat.type = B_MEDIA_ENCODED_VIDEO;
fFormat.u.encoded_video.output.field_rate = 0.0;
fFormat.u.encoded_video.output.interlace = 1;
fFormat.u.encoded_video.output.first_active = 0;
fFormat.u.encoded_video.output.orientation = B_VIDEO_TOP_LEFT_RIGHT;
fFormat.u.encoded_video.output.display.format = B_RGB32;
fFormat.u.encoded_video.output.pixel_width_aspect
= fFormat.u.raw_video.display.line_width
= static_cast<int32>(fBitmap->Bounds().right) + 1;
fFormat.u.encoded_video.output.pixel_height_aspect
= fFormat.u.raw_video.display.line_count
= static_cast<int32>(fBitmap->Bounds().bottom) + 1;
fFormat.u.encoded_video.output.display.bytes_per_row
= fFormat.u.raw_video.display.line_width * sizeof(int32);
fFormat.u.encoded_video.output.display.pixel_offset = 0;
fFormat.u.encoded_video.output.display.line_offset = 0;
fFormat.u.encoded_video.output.display.flags = 0;
fFormat.u.encoded_video.output.last_active
= fFormat.u.raw_video.display.line_count - 1;
fFormat.u.encoded_video.avg_bit_rate = 0.0;
fFormat.u.encoded_video.max_bit_rate = 0.0;
fFormat.u.encoded_video.encoding = media_encoded_video_format::B_ANY;
fFormat.u.encoded_video.frame_size
= fFormat.u.encoded_video.output.display.bytes_per_row *
fFormat.u.raw_video.display.line_count;
fFormat.u.encoded_video.forward_history = 0;
fFormat.u.encoded_video.backward_history = 0;
initStatus = B_OK;
}
ImageTrackVideoSupplier::~ImageTrackVideoSupplier()
{
}
const media_format&
ImageTrackVideoSupplier::Format() const
{
return fFormat;
}
status_t
ImageTrackVideoSupplier::GetEncodedFormat(media_format* format) const
{
*format = fFormat;
return B_OK;
}
status_t
ImageTrackVideoSupplier::GetCodecInfo(media_codec_info* info) const
{
strlcpy(info->pretty_name, "Artwork (static image)",
sizeof(info->pretty_name));
strlcpy(info->short_name, "Artwork", sizeof(info->short_name));
info->id = info->sub_id = 0;
return B_OK;
}
status_t
ImageTrackVideoSupplier::ReadFrame(void* buffer, bigtime_t* performanceTime,
const media_raw_video_format& format, bool& wasCached)
{
uint32 size = format.display.bytes_per_row * format.display.line_count;
memcpy(buffer, fBitmap->Bits(), size);
return B_OK;
}
status_t
ImageTrackVideoSupplier::FindKeyFrameForFrame(int64* frame)
{
return B_OK;
}
status_t
ImageTrackVideoSupplier::SeekToTime(bigtime_t* performanceTime)
{
return B_OK;
}
status_t
ImageTrackVideoSupplier::SeekToFrame(int64* frame)
{
return B_OK;
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2011, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* SHINTA
*/
#ifndef IMAGE_TRACK_VIDEO_SUPPLIER_H
#define IMAGE_TRACK_VIDEO_SUPPLIER_H
#include <Bitmap.h>
#include <MediaFormats.h>
#include "VideoTrackSupplier.h"
class ImageTrackVideoSupplier : public VideoTrackSupplier {
public:
ImageTrackVideoSupplier(BBitmap* bitmap,
int32 trackIndex, status_t& initStatus);
virtual ~ImageTrackVideoSupplier();
virtual const media_format& Format() const;
virtual status_t GetEncodedFormat(media_format* format) const;
virtual status_t GetCodecInfo(media_codec_info* info) const;
virtual status_t ReadFrame(void* buffer,
bigtime_t* performanceTime,
const media_raw_video_format& format,
bool& wasCached);
virtual status_t FindKeyFrameForFrame(int64* frame);
virtual status_t SeekToTime(bigtime_t* performanceTime);
virtual status_t SeekToFrame(int64* frame);
virtual bigtime_t Position() const
{ return fPerformanceTime; }
virtual bigtime_t Duration() const
{ return fDuration; }
virtual int64 CurrentFrame() const
{ return fCurrentFrame; }
#if 0
virtual BRect Bounds() const;
virtual color_space ColorSpace() const;
virtual uint32 BytesPerRow() const;
#endif
virtual int32 TrackIndex() const
{ return fTrackIndex; }
private:
media_format fFormat;
bigtime_t fPerformanceTime;
bigtime_t fDuration;
int64 fCurrentFrame;
BBitmap* fBitmap;
int32 fTrackIndex;
};
#endif // IMAGE_TRACK_VIDEO_SUPPLIER_H

View File

@ -1,9 +1,11 @@
/*
* Copyright 2010, Stephan Aßmus <superstippi@gmx.de>. All rights reserved.
* Copyright 2010-2011, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* SHINTA
*/
#include "MediaFileTrackSupplier.h"
#include <new>
@ -17,58 +19,29 @@
#include "MediaTrackAudioSupplier.h"
#include "MediaTrackVideoSupplier.h"
#include "ImageTrackVideoSupplier.h"
MediaFileTrackSupplier::MediaFileTrackSupplier(BMediaFile* mediaFile)
MediaFileTrackSupplier::MediaFileTrackSupplier()
:
TrackSupplier(),
fMediaFile(mediaFile)
TrackSupplier()
{
if (fMediaFile->InitCheck() != B_OK)
return;
int trackCount = fMediaFile->CountTracks();
if (trackCount <= 0)
return;
for (int i = 0; i < trackCount; i++) {
BMediaTrack* track = fMediaFile->TrackAt(i);
media_format format;
status_t status = track->EncodedFormat(&format);
if (status != B_OK) {
fprintf(stderr, "MediaFileTrackSupplier: EncodedFormat failed for "
"track index %d, error: %s\n", i, strerror(status));
fMediaFile->ReleaseTrack(track);
continue;
}
if (track->Duration() <= 0) {
fprintf(stderr, "MediaFileTrackSupplier: warning! track index %d "
"has no duration\n", i);
}
if (format.IsAudio()) {
if (!fAudioTracks.AddItem(track)) {
fMediaFile->ReleaseTrack(track);
return;
}
} else if (format.IsVideo()) {
if (!fVideoTracks.AddItem(track)) {
fMediaFile->ReleaseTrack(track);
return;
}
} else {
printf("MediaFileTrackSupplier: track index %d has unknown "
"type\n", i);
fMediaFile->ReleaseTrack(track);
}
}
}
MediaFileTrackSupplier::~MediaFileTrackSupplier()
{
delete fMediaFile;
for (vector<BMediaFile*>::size_type i = fMediaFiles.size() - 1;
static_cast<int32>(i) >= 0; i--) {
delete fMediaFiles[i];
// BMediaFile destructor will call ReleaseAllTracks()
}
for (vector<BBitmap*>::size_type i = fBitmaps.size() - 1;
static_cast<int32>(i) >= 0; i--) {
delete fBitmaps[i];
}
for (int32 i = fSubTitleTracks.CountItems() - 1; i >= 0; i--)
delete reinterpret_cast<SubTitles*>(fSubTitleTracks.ItemAtFast(i));
}
@ -77,21 +50,30 @@ MediaFileTrackSupplier::~MediaFileTrackSupplier()
status_t
MediaFileTrackSupplier::InitCheck()
{
return fMediaFile->InitCheck();
if (fMediaFiles.empty())
return B_ERROR;
return fMediaFiles[0]->InitCheck();
}
status_t
MediaFileTrackSupplier::GetFileFormatInfo(media_file_format* fileFormat)
{
return fMediaFile->GetFileFormatInfo(fileFormat);
if (fMediaFiles.empty())
return B_ERROR;
return fMediaFiles[0]->GetFileFormatInfo(fileFormat);
}
status_t
MediaFileTrackSupplier::GetCopyright(BString* copyright)
{
*copyright = fMediaFile->Copyright();
if (fMediaFiles.empty())
return B_ERROR;
*copyright = fMediaFiles[0]->Copyright();
return B_OK;
}
@ -99,7 +81,10 @@ MediaFileTrackSupplier::GetCopyright(BString* copyright)
status_t
MediaFileTrackSupplier::GetMetaData(BMessage* metaData)
{
return fMediaFile->GetMetaData(metaData);
if (fMediaFiles.empty())
return B_ERROR;
return fMediaFiles[0]->GetMetaData(metaData);
}
@ -113,7 +98,7 @@ MediaFileTrackSupplier::CountAudioTracks()
int32
MediaFileTrackSupplier::CountVideoTracks()
{
return fVideoTracks.CountItems();
return fVideoTracks.CountItems() + fBitmaps.size();
}
@ -160,18 +145,26 @@ MediaFileTrackSupplier::CreateAudioTrackForIndex(int32 index)
VideoTrackSupplier*
MediaFileTrackSupplier::CreateVideoTrackForIndex(int32 index)
{
BMediaTrack* track = (BMediaTrack*)fVideoTracks.ItemAt(index);
if (track == NULL)
return NULL;
VideoTrackSupplier* supplier;
status_t initStatus;
MediaTrackVideoSupplier* supplier
= new(std::nothrow) MediaTrackVideoSupplier(track, index, initStatus);
if (fVideoTracks.CountItems() <= index
&& index < fVideoTracks.CountItems() + static_cast<int32>(fBitmaps.size())) {
supplier = new(std::nothrow) ImageTrackVideoSupplier(
fBitmaps[index - fVideoTracks.CountItems()], index, initStatus);
} else {
BMediaTrack* track = (BMediaTrack*)fVideoTracks.ItemAt(index);
if (track == NULL)
return NULL;
supplier = new(std::nothrow) MediaTrackVideoSupplier(track, index,
initStatus);
}
if (initStatus != B_OK) {
delete supplier;
return NULL;
}
return supplier;
}
@ -189,3 +182,62 @@ MediaFileTrackSupplier::AddSubTitles(SubTitles* subTitles)
return fSubTitleTracks.AddItem(subTitles);
}
status_t
MediaFileTrackSupplier::AddMediaFile(BMediaFile* mediaFile)
{
if (mediaFile->InitCheck() != B_OK)
return B_ERROR;
int trackCount = mediaFile->CountTracks();
if (trackCount <= 0)
return B_ERROR;
status_t funcStatus = B_ERROR;
for (int i = 0; i < trackCount; i++) {
BMediaTrack* track = mediaFile->TrackAt(i);
media_format format;
status_t status = track->EncodedFormat(&format);
if (status != B_OK) {
fprintf(stderr, "MediaFileTrackSupplier: EncodedFormat failed for "
"track index %d, error: %s\n", i, strerror(status));
mediaFile->ReleaseTrack(track);
continue;
}
if (track->Duration() <= 0) {
fprintf(stderr, "MediaFileTrackSupplier: warning! track index %d "
"has no duration\n", i);
}
if (format.IsAudio()) {
if (fAudioTracks.AddItem(track)) {
funcStatus = B_OK;
} else {
mediaFile->ReleaseTrack(track);
}
} else if (format.IsVideo()) {
if (fVideoTracks.AddItem(track)) {
funcStatus = B_OK;
} else {
mediaFile->ReleaseTrack(track);
}
} else {
printf("MediaFileTrackSupplier: track index %d has unknown "
"type\n", i);
mediaFile->ReleaseTrack(track);
}
}
if (funcStatus == B_OK)
fMediaFiles.push_back(mediaFile);
return funcStatus;
}
status_t
MediaFileTrackSupplier::AddBitmap(BBitmap* bitmap)
{
fBitmaps.push_back(bitmap);
return B_OK;
}

View File

@ -5,18 +5,21 @@
#ifndef MEDIA_FILE_TRACK_SUPPLIER_H
#define MEDIA_FILE_TRACK_SUPPLIER_H
#include <vector>
#include <Bitmap.h>
#include <List.h>
#include "TrackSupplier.h"
class BMediaFile;
using std::vector;
class MediaFileTrackSupplier : public TrackSupplier {
public:
MediaFileTrackSupplier(BMediaFile* mediaFile);
MediaFileTrackSupplier();
virtual ~MediaFileTrackSupplier();
virtual status_t InitCheck();
@ -41,8 +44,13 @@ public:
bool AddSubTitles(SubTitles* subTitles);
status_t AddMediaFile(BMediaFile* mediaFile);
status_t AddBitmap(BBitmap* bitmap);
private:
BMediaFile* fMediaFile;
vector<BMediaFile*> fMediaFiles;
vector<BBitmap*> fBitmaps;
BList fAudioTracks;
BList fVideoTracks;
BList fSubTitleTracks;