651 lines
14 KiB
C++
651 lines
14 KiB
C++
/*
|
|
* Copyright 2009, Stephan Aßmus <superstippi@gmx.de>
|
|
* Copyright 2002-2004, Marcus Overhagen <marcus@overhagen.de>
|
|
* All rights reserved. Distributed under the terms of the MIT license.
|
|
*/
|
|
|
|
#include <MediaFile.h>
|
|
|
|
#include <new>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <File.h>
|
|
#include <MediaTrack.h>
|
|
#include <Url.h>
|
|
|
|
#include "MediaDebug.h"
|
|
|
|
#include "MediaExtractor.h"
|
|
#include "MediaStreamer.h"
|
|
#include "MediaWriter.h"
|
|
|
|
|
|
BMediaFile::BMediaFile(const entry_ref* ref)
|
|
{
|
|
CALLED();
|
|
_Init();
|
|
fDeleteSource = true;
|
|
_InitReader(new(std::nothrow) BFile(ref, O_RDONLY));
|
|
}
|
|
|
|
|
|
BMediaFile::BMediaFile(BDataIO* source)
|
|
{
|
|
CALLED();
|
|
_Init();
|
|
_InitReader(source);
|
|
}
|
|
|
|
|
|
BMediaFile::BMediaFile(const entry_ref* ref, int32 flags)
|
|
{
|
|
CALLED();
|
|
_Init();
|
|
fDeleteSource = true;
|
|
_InitReader(new(std::nothrow) BFile(ref, O_RDONLY), NULL, flags);
|
|
}
|
|
|
|
|
|
BMediaFile::BMediaFile(BDataIO* source, int32 flags)
|
|
{
|
|
CALLED();
|
|
_Init();
|
|
_InitReader(source, NULL, flags);
|
|
}
|
|
|
|
|
|
BMediaFile::BMediaFile(const entry_ref* ref, const media_file_format* mfi,
|
|
int32 flags)
|
|
{
|
|
CALLED();
|
|
_Init();
|
|
fDeleteSource = true;
|
|
_InitWriter(new(std::nothrow) BFile(ref, B_CREATE_FILE | B_ERASE_FILE
|
|
| B_WRITE_ONLY), NULL, mfi, flags);
|
|
}
|
|
|
|
|
|
BMediaFile::BMediaFile(BDataIO* destination, const media_file_format* mfi,
|
|
int32 flags)
|
|
{
|
|
CALLED();
|
|
_Init();
|
|
_InitWriter(destination, NULL, mfi, flags);
|
|
}
|
|
|
|
|
|
// File will be set later by SetTo()
|
|
BMediaFile::BMediaFile(const media_file_format* mfi, int32 flags)
|
|
{
|
|
debugger("BMediaFile::BMediaFile not implemented");
|
|
}
|
|
|
|
|
|
BMediaFile::BMediaFile(const BUrl& url)
|
|
{
|
|
CALLED();
|
|
_Init();
|
|
fDeleteSource = true;
|
|
_InitReader(NULL, &url);
|
|
}
|
|
|
|
|
|
BMediaFile::BMediaFile(const BUrl& url, int32 flags)
|
|
{
|
|
CALLED();
|
|
_Init();
|
|
fDeleteSource = true;
|
|
_InitReader(NULL, &url, flags);
|
|
}
|
|
|
|
|
|
BMediaFile::BMediaFile(const BUrl& destination, const media_file_format* mfi,
|
|
int32 flags)
|
|
{
|
|
CALLED();
|
|
_Init();
|
|
fDeleteSource = true;
|
|
_InitWriter(NULL, &destination, mfi, flags);
|
|
// TODO: Implement streaming server support, it's
|
|
// a pretty complex thing compared to client mode
|
|
// and will require to expand the current BMediaFile
|
|
// design to be aware of it.
|
|
}
|
|
|
|
|
|
status_t
|
|
BMediaFile::SetTo(const entry_ref* ref)
|
|
{
|
|
CALLED();
|
|
|
|
if (ref == NULL)
|
|
return B_BAD_VALUE;
|
|
|
|
_UnInit();
|
|
fDeleteSource = true;
|
|
_InitReader(new(std::nothrow) BFile(ref, O_RDONLY));
|
|
|
|
return fErr;
|
|
}
|
|
|
|
|
|
status_t
|
|
BMediaFile::SetTo(BDataIO* destination)
|
|
{
|
|
CALLED();
|
|
|
|
if (destination == NULL)
|
|
return B_BAD_VALUE;
|
|
|
|
_UnInit();
|
|
_InitReader(destination);
|
|
|
|
return fErr;
|
|
}
|
|
|
|
|
|
status_t
|
|
BMediaFile::SetTo(const BUrl& url)
|
|
{
|
|
CALLED();
|
|
|
|
_UnInit();
|
|
_InitReader(NULL, &url);
|
|
|
|
return fErr;
|
|
}
|
|
|
|
|
|
BMediaFile::~BMediaFile()
|
|
{
|
|
CALLED();
|
|
|
|
_UnInit();
|
|
}
|
|
|
|
|
|
status_t
|
|
BMediaFile::InitCheck() const
|
|
{
|
|
CALLED();
|
|
return fErr;
|
|
}
|
|
|
|
|
|
status_t
|
|
BMediaFile::GetFileFormatInfo(media_file_format* mfi) const
|
|
{
|
|
CALLED();
|
|
if (mfi == NULL)
|
|
return B_BAD_VALUE;
|
|
if (fErr)
|
|
return B_ERROR;
|
|
*mfi = fMFI;
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
BMediaFile::GetMetaData(BMessage* _data) const
|
|
{
|
|
if (fExtractor == NULL)
|
|
return B_NO_INIT;
|
|
if (_data == NULL)
|
|
return B_BAD_VALUE;
|
|
|
|
_data->MakeEmpty();
|
|
|
|
return fExtractor->GetMetaData(_data);
|
|
}
|
|
|
|
|
|
const char*
|
|
BMediaFile::Copyright() const
|
|
{
|
|
return fExtractor->Copyright();
|
|
}
|
|
|
|
|
|
int32
|
|
BMediaFile::CountTracks() const
|
|
{
|
|
return fTrackNum;
|
|
}
|
|
|
|
|
|
// Can be called multiple times with the same index. You must call
|
|
// ReleaseTrack() when you're done with a track.
|
|
BMediaTrack*
|
|
BMediaFile::TrackAt(int32 index)
|
|
{
|
|
CALLED();
|
|
if (fTrackList == NULL || fExtractor == NULL
|
|
|| index < 0 || index >= fTrackNum) {
|
|
return NULL;
|
|
}
|
|
if (fTrackList[index] == NULL) {
|
|
TRACE("BMediaFile::TrackAt, creating new track for index %"
|
|
B_PRId32 "\n", index);
|
|
fTrackList[index] = new(std::nothrow) BMediaTrack(fExtractor, index);
|
|
TRACE("BMediaFile::TrackAt, new track is %p\n", fTrackList[index]);
|
|
}
|
|
return fTrackList[index];
|
|
}
|
|
|
|
|
|
// Release the resource used by a given BMediaTrack object, to reduce
|
|
// the memory usage of your application. The specific 'track' object
|
|
// can no longer be used, but you can create another one by calling
|
|
// TrackAt() with the same track index.
|
|
status_t
|
|
BMediaFile::ReleaseTrack(BMediaTrack* track)
|
|
{
|
|
CALLED();
|
|
if (!fTrackList || !track)
|
|
return B_ERROR;
|
|
for (int32 i = 0; i < fTrackNum; i++) {
|
|
if (fTrackList[i] == track) {
|
|
TRACE("BMediaFile::ReleaseTrack, releasing track %p with index "
|
|
"%" B_PRId32 "\n", track, i);
|
|
delete track;
|
|
fTrackList[i] = NULL;
|
|
return B_OK;
|
|
}
|
|
}
|
|
fprintf(stderr, "BMediaFile::ReleaseTrack track %p not found\n", track);
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
status_t
|
|
BMediaFile::ReleaseAllTracks()
|
|
{
|
|
CALLED();
|
|
if (!fTrackList)
|
|
return B_ERROR;
|
|
for (int32 i = 0; i < fTrackNum; i++) {
|
|
if (fTrackList[i]) {
|
|
TRACE("BMediaFile::ReleaseAllTracks, releasing track %p with "
|
|
"index %" B_PRId32 "\n", fTrackList[i], i);
|
|
delete fTrackList[i];
|
|
fTrackList[i] = NULL;
|
|
}
|
|
}
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
// Create and add a track to the media file
|
|
BMediaTrack*
|
|
BMediaFile::CreateTrack(media_format* mediaFormat,
|
|
const media_codec_info* codecInfo, uint32 flags)
|
|
{
|
|
if (mediaFormat == NULL)
|
|
return NULL;
|
|
|
|
// NOTE: It is allowed to pass NULL for codecInfo. In that case, the
|
|
// track won't have an Encoder and you can only use WriteChunk() with
|
|
// already encoded data.
|
|
|
|
// Make room for the new track.
|
|
BMediaTrack** trackList = (BMediaTrack**)realloc(fTrackList,
|
|
(fTrackNum + 1) * sizeof(BMediaTrack*));
|
|
if (trackList == NULL)
|
|
return NULL;
|
|
|
|
int32 streamIndex = fTrackNum;
|
|
fTrackList = trackList;
|
|
fTrackNum += 1;
|
|
|
|
BMediaTrack* track = new(std::nothrow) BMediaTrack(fWriter, streamIndex,
|
|
mediaFormat, codecInfo);
|
|
|
|
fTrackList[streamIndex] = track;
|
|
|
|
return track;
|
|
}
|
|
|
|
|
|
// Create and add a raw track to the media file (it has no encoder)
|
|
BMediaTrack*
|
|
BMediaFile::CreateTrack(media_format* mf, uint32 flags)
|
|
{
|
|
return CreateTrack(mf, NULL, flags);
|
|
}
|
|
|
|
|
|
// For BeOS R5 compatibility
|
|
extern "C" BMediaTrack*
|
|
CreateTrack__10BMediaFileP12media_formatPC16media_codec_info(
|
|
BMediaFile* self, media_format* mf, const media_codec_info* mci);
|
|
BMediaTrack*
|
|
CreateTrack__10BMediaFileP12media_formatPC16media_codec_info(BMediaFile* self,
|
|
media_format* mf, const media_codec_info* mci)
|
|
{
|
|
return self->CreateTrack(mf, mci, 0);
|
|
}
|
|
|
|
|
|
// For BeOS R5 compatibility
|
|
extern "C" BMediaTrack* CreateTrack__10BMediaFileP12media_format(
|
|
BMediaFile* self, media_format* mf);
|
|
BMediaTrack*
|
|
CreateTrack__10BMediaFileP12media_format(BMediaFile* self, media_format* mf)
|
|
{
|
|
return self->CreateTrack(mf, NULL, 0);
|
|
}
|
|
|
|
|
|
// Lets you set the copyright info for the entire file
|
|
status_t
|
|
BMediaFile::AddCopyright(const char* copyright)
|
|
{
|
|
if (fWriter == NULL)
|
|
return B_NO_INIT;
|
|
|
|
return fWriter->SetCopyright(copyright);
|
|
}
|
|
|
|
|
|
// Call this to add user-defined chunks to a file (if they're supported)
|
|
status_t
|
|
BMediaFile::AddChunk(int32 type, const void* data, size_t size)
|
|
{
|
|
UNIMPLEMENTED();
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
// After you have added all the tracks you want, call this
|
|
status_t
|
|
BMediaFile::CommitHeader()
|
|
{
|
|
if (fWriter == NULL)
|
|
return B_NO_INIT;
|
|
|
|
return fWriter->CommitHeader();
|
|
}
|
|
|
|
|
|
// After you have written all the data to the track objects, call this
|
|
status_t
|
|
BMediaFile::CloseFile()
|
|
{
|
|
if (fWriter == NULL)
|
|
return B_NO_INIT;
|
|
|
|
return fWriter->Close();
|
|
}
|
|
|
|
// This is for controlling file format parameters
|
|
|
|
// returns a copy of the parameter web
|
|
status_t
|
|
BMediaFile::GetParameterWeb(BParameterWeb** outWeb)
|
|
{
|
|
UNIMPLEMENTED();
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
// deprecated BeOS R5 API
|
|
BParameterWeb*
|
|
BMediaFile::Web()
|
|
{
|
|
UNIMPLEMENTED();
|
|
return 0;
|
|
}
|
|
|
|
|
|
status_t
|
|
BMediaFile::GetParameterValue(int32 id, void* value, size_t* size)
|
|
{
|
|
UNIMPLEMENTED();
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
BMediaFile::SetParameterValue(int32 id, const void* value, size_t size)
|
|
{
|
|
UNIMPLEMENTED();
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
BView*
|
|
BMediaFile::GetParameterView()
|
|
{
|
|
UNIMPLEMENTED();
|
|
return 0;
|
|
}
|
|
|
|
|
|
status_t
|
|
BMediaFile::Perform(int32 selector, void* data)
|
|
{
|
|
UNIMPLEMENTED();
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
BMediaFile::ControlFile(int32 selector, void* ioData, size_t size)
|
|
{
|
|
UNIMPLEMENTED();
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
// #pragma mark - private
|
|
|
|
|
|
void
|
|
BMediaFile::_Init()
|
|
{
|
|
CALLED();
|
|
|
|
fSource = NULL;
|
|
fTrackNum = 0;
|
|
fTrackList = NULL;
|
|
fExtractor = NULL;
|
|
fStreamer = NULL;
|
|
fWriter = NULL;
|
|
fWriterID = 0;
|
|
fErr = B_OK;
|
|
fDeleteSource = false;
|
|
|
|
// not used so far:
|
|
fEncoderMgr = NULL;
|
|
fWriterMgr = NULL;
|
|
fFileClosed = false;
|
|
}
|
|
|
|
|
|
void
|
|
BMediaFile::_UnInit()
|
|
{
|
|
ReleaseAllTracks();
|
|
free(fTrackList);
|
|
fTrackList = NULL;
|
|
fTrackNum = 0;
|
|
|
|
// Tells the extractor to stop its asynchronous processing
|
|
// before deleting its source
|
|
if (fExtractor != NULL)
|
|
fExtractor->StopProcessing();
|
|
|
|
if (fDeleteSource) {
|
|
delete fSource;
|
|
fDeleteSource = false;
|
|
}
|
|
fSource = NULL;
|
|
|
|
// Deleting the extractor or writer can cause unloading of the plugins.
|
|
// The source must be deleted before that, because it can come from a
|
|
// plugin (for example the http_streamer)
|
|
delete fExtractor;
|
|
fExtractor = NULL;
|
|
delete fWriter;
|
|
fWriter = NULL;
|
|
delete fStreamer;
|
|
fStreamer = NULL;
|
|
}
|
|
|
|
|
|
void
|
|
BMediaFile::_InitReader(BDataIO* source, const BUrl* url, int32 flags)
|
|
{
|
|
CALLED();
|
|
|
|
if (source == NULL && url == NULL) {
|
|
fErr = B_NO_MEMORY;
|
|
return;
|
|
}
|
|
|
|
if (source == NULL)
|
|
_InitStreamer(*url, &source);
|
|
else if (BFile* file = dynamic_cast<BFile*>(source))
|
|
fErr = file->InitCheck();
|
|
|
|
if (fErr != B_OK)
|
|
return;
|
|
|
|
fExtractor = new(std::nothrow) MediaExtractor(source, flags);
|
|
|
|
if (fExtractor == NULL)
|
|
fErr = B_NO_MEMORY;
|
|
else
|
|
fErr = fExtractor->InitCheck();
|
|
|
|
if (fErr != B_OK)
|
|
return;
|
|
|
|
fSource = source;
|
|
|
|
fExtractor->GetFileFormatInfo(&fMFI);
|
|
fTrackNum = fExtractor->StreamCount();
|
|
fTrackList = (BMediaTrack**)malloc(fTrackNum * sizeof(BMediaTrack*));
|
|
if (fTrackList == NULL) {
|
|
fErr = B_NO_MEMORY;
|
|
return;
|
|
}
|
|
memset(fTrackList, 0, fTrackNum * sizeof(BMediaTrack*));
|
|
}
|
|
|
|
|
|
void
|
|
BMediaFile::_InitWriter(BDataIO* target, const BUrl* url,
|
|
const media_file_format* fileFormat, int32 flags)
|
|
{
|
|
CALLED();
|
|
|
|
if (fileFormat == NULL) {
|
|
fErr = B_BAD_VALUE;
|
|
return;
|
|
}
|
|
|
|
if (target == NULL && url == NULL) {
|
|
fErr = B_NO_MEMORY;
|
|
return;
|
|
}
|
|
|
|
fMFI = *fileFormat;
|
|
|
|
if (target == NULL) {
|
|
_InitStreamer(*url, &target);
|
|
if (fErr != B_OK)
|
|
return;
|
|
}
|
|
|
|
fWriter = new(std::nothrow) MediaWriter(target, fMFI);
|
|
|
|
if (fWriter == NULL)
|
|
fErr = B_NO_MEMORY;
|
|
else
|
|
fErr = fWriter->InitCheck();
|
|
if (fErr != B_OK)
|
|
return;
|
|
|
|
// Get the actual source from the writer
|
|
fSource = fWriter->Target();
|
|
fTrackNum = 0;
|
|
}
|
|
|
|
|
|
void
|
|
BMediaFile::_InitStreamer(const BUrl& url, BDataIO** adapter)
|
|
{
|
|
if (fStreamer != NULL)
|
|
delete fStreamer;
|
|
|
|
TRACE(url.UrlString());
|
|
|
|
fStreamer = new(std::nothrow) MediaStreamer(url);
|
|
if (fStreamer == NULL) {
|
|
fErr = B_NO_MEMORY;
|
|
return;
|
|
}
|
|
|
|
fErr = fStreamer->CreateAdapter(adapter);
|
|
}
|
|
|
|
/*
|
|
//unimplemented
|
|
BMediaFile::BMediaFile();
|
|
BMediaFile::BMediaFile(const BMediaFile&);
|
|
BMediaFile::BMediaFile& operator=(const BMediaFile&);
|
|
*/
|
|
|
|
status_t BMediaFile::_Reserved_BMediaFile_0(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_1(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_2(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_3(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_4(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_5(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_6(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_7(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_8(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_9(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_10(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_11(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_12(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_13(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_14(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_15(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_16(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_17(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_18(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_19(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_20(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_21(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_22(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_23(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_24(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_25(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_26(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_27(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_28(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_29(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_30(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_31(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_32(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_33(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_34(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_35(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_36(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_37(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_38(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_39(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_40(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_41(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_42(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_43(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_44(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_45(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_46(int32 arg, ...) { return B_ERROR; }
|
|
status_t BMediaFile::_Reserved_BMediaFile_47(int32 arg, ...) { return B_ERROR; }
|
|
|