Pictures they move and everything and hark what is that noise
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30497 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
797f475dba
commit
94793d4d86
@ -92,11 +92,19 @@ ASFFileReader::ParseFile()
|
||||
}
|
||||
|
||||
uint32 totalStreams = getStreamCount();
|
||||
StreamHeader streamHeader;
|
||||
StreamEntry streamEntry;
|
||||
|
||||
for (int i=0;i < totalStreams;i++) {
|
||||
streamHeader.streamIndex = i;
|
||||
streams.push_back(streamHeader);
|
||||
for (uint32 i=0;i < totalStreams;i++) {
|
||||
streamEntry.streamIndex = i;
|
||||
streams.push_back(streamEntry);
|
||||
}
|
||||
|
||||
ParseIndex();
|
||||
|
||||
// load the first packet
|
||||
if (asf_get_packet(asfFile, packet) < 0) {
|
||||
printf("Could not get first packet\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
@ -194,15 +202,19 @@ ASFFileReader::getVideoFormat(uint32 streamIndex, ASFVideoFormat *format)
|
||||
|
||||
|
||||
bigtime_t
|
||||
ASFFileReader::getVideoDuration(uint32 streamIndex)
|
||||
ASFFileReader::getStreamDuration(uint32 streamIndex)
|
||||
{
|
||||
if (streamIndex < streams.size()) {
|
||||
return streams[streamIndex].getDuration();
|
||||
}
|
||||
|
||||
asf_stream_t *stream;
|
||||
|
||||
stream = asf_get_stream(asfFile, streamIndex);
|
||||
|
||||
if (stream) {
|
||||
if (stream->flags & ASF_STREAM_FLAG_EXTENDED) {
|
||||
printf("VIDEO end time %Ld, start time %Ld\n",stream->extended->end_time, stream->extended->start_time);
|
||||
printf("STREAM %ld end time %Ld, start time %Ld\n",streamIndex, stream->extended->end_time, stream->extended->start_time);
|
||||
if (stream->extended->end_time - stream->extended->start_time > 0) {
|
||||
return stream->extended->end_time - stream->extended->start_time;
|
||||
}
|
||||
@ -212,45 +224,14 @@ ASFFileReader::getVideoDuration(uint32 streamIndex)
|
||||
return asf_get_duration(asfFile) / 10;
|
||||
}
|
||||
|
||||
|
||||
bigtime_t
|
||||
ASFFileReader::getAudioDuration(uint32 streamIndex)
|
||||
{
|
||||
asf_stream_t *stream;
|
||||
|
||||
stream = asf_get_stream(asfFile, streamIndex);
|
||||
|
||||
if (stream) {
|
||||
if (stream->flags & ASF_STREAM_FLAG_EXTENDED) {
|
||||
printf("AUDIO end time %Ld, start time %Ld\n",stream->extended->end_time, stream->extended->start_time);
|
||||
if (stream->extended->end_time - stream->extended->start_time > 0) {
|
||||
return stream->extended->end_time - stream->extended->start_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return asf_get_duration(asfFile) / 10; // convert from 100 nanosecond units to microseconds
|
||||
}
|
||||
|
||||
|
||||
bigtime_t
|
||||
ASFFileReader::getMaxDuration()
|
||||
{
|
||||
return asf_get_duration(asfFile) / 10;
|
||||
}
|
||||
|
||||
|
||||
// Not really frame count, really total data packets
|
||||
uint32
|
||||
ASFFileReader::getFrameCount(uint32 streamIndex)
|
||||
{
|
||||
return asf_get_data_packets(asfFile);
|
||||
}
|
||||
|
||||
uint32
|
||||
ASFFileReader::getAudioChunkCount(uint32 streamIndex)
|
||||
{
|
||||
return asf_get_data_packets(asfFile);
|
||||
if (streamIndex < streams.size()) {
|
||||
return streams[streamIndex].getFrameCount();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -282,12 +263,6 @@ ASFFileReader::IsAudio(uint32 streamIndex)
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ASFFileReader::AddIndex(uint32 streamIndex, uint32 frameNo, bool keyFrame, bigtime_t pts, uint8 *data, uint32 size)
|
||||
{
|
||||
streams[streamIndex].AddIndex(frameNo, keyFrame, pts, data, size);
|
||||
}
|
||||
|
||||
IndexEntry
|
||||
ASFFileReader::GetIndex(uint32 streamIndex, uint32 frameNo)
|
||||
{
|
||||
@ -304,31 +279,115 @@ ASFFileReader::HasIndex(uint32 streamIndex, uint32 frameNo)
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32
|
||||
ASFFileReader::GetFrameForTime(uint32 streamIndex, bigtime_t time)
|
||||
{
|
||||
if (streamIndex < streams.size()) {
|
||||
return streams[streamIndex].GetIndex(time).frameNo;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ASFFileReader::ParseIndex() {
|
||||
// Try to build some sort of useful index
|
||||
// packet->send_time seems to be a better presentation time stamp than pts though
|
||||
|
||||
if (asf_seek_to_msec(asfFile,0) < 0) {
|
||||
printf("Seek to start of stream failed\n");
|
||||
}
|
||||
|
||||
asf_payload_t *payload;
|
||||
|
||||
while (asf_get_packet(asfFile, packet) > 0) {
|
||||
for (int i=0;i<packet->payload_count;i++) {
|
||||
payload = (asf_payload_t *)(&packet->payloads[i]);
|
||||
// printf("Payload %d Stream %d Keyframe %d send time %ld pts %ld id %d size %d\n",i+1,payload->stream_number,payload->key_frame, packet->send_time * 1000L, payload->pts * 1000L, payload->media_object_number, payload->datalen);
|
||||
if (payload->stream_number < streams.size()) {
|
||||
streams[payload->stream_number].AddPayload(payload->media_object_number, payload->key_frame, packet->send_time * 1000, payload->datalen, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32 i=0;i<streams.size();i++) {
|
||||
streams[i].AddPayload(0, false, 0, 0, true);
|
||||
streams[i].setDuration((packet->send_time + packet->duration) * 1000);
|
||||
}
|
||||
|
||||
if (asf_seek_to_msec(asfFile,0) < 0) {
|
||||
printf("Seek to start of stream failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ASFFileReader::GetNextChunkInfo(uint32 streamIndex, uint32 pFrameNo,
|
||||
char **buffer, uint32 *size, bool *keyframe, bigtime_t *pts)
|
||||
{
|
||||
// Ok, Need to join payloads together that have the same payload->pts
|
||||
// packet->send_time seems to be a better presentation time stamp than pts though
|
||||
|
||||
// Ok, Need to join payloads together that have the same payload->media_object_number
|
||||
asf_payload_t *payload;
|
||||
|
||||
IndexEntry indexEntry = GetIndex(streamIndex, pFrameNo);
|
||||
|
||||
while (!HasIndex(streamIndex, pFrameNo+1) && asf_get_packet(asfFile, packet) > 0) {
|
||||
for (int i=0;i<packet->payload_count;i++) {
|
||||
payload = (asf_payload_t *)(&packet->payloads[i]);
|
||||
printf("Payload %d ",i+1);
|
||||
printf("Stream %d Keyframe %d pts %d frame %d, size %d\n",payload->stream_number,payload->key_frame, payload->pts * 1000, payload->media_object_number, payload->datalen);
|
||||
AddIndex(payload->stream_number, payload->media_object_number, payload->key_frame, packet->send_time * 1000, payload->data, payload->datalen);
|
||||
if (indexEntry.noPayloads == 0) {
|
||||
// No index entry
|
||||
return false;
|
||||
}
|
||||
|
||||
while (packet->send_time * 1000 < indexEntry.pts) {
|
||||
if (asf_get_packet(asfFile, packet) < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (packet->send_time * 1000 > indexEntry.pts) {
|
||||
// seek back to pts
|
||||
printf("seeking back to %Ld status %Ld\n",indexEntry.pts, asf_seek_to_msec(asfFile, indexEntry.pts/1000));
|
||||
if (asf_get_packet(asfFile, packet) < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (HasIndex(streamIndex, pFrameNo+1)) {
|
||||
IndexEntry indexEntry = GetIndex(streamIndex, pFrameNo+1);
|
||||
*buffer = (char *)indexEntry.data;
|
||||
*size = indexEntry.size;
|
||||
*keyframe = indexEntry.keyFrame;
|
||||
*pts = indexEntry.pts;
|
||||
return true;
|
||||
// fillin some details
|
||||
*size = indexEntry.dataSize;
|
||||
*keyframe = indexEntry.keyFrame;
|
||||
*pts = indexEntry.pts;
|
||||
|
||||
uint32 expectedPayloads = indexEntry.noPayloads;
|
||||
uint32 offset = 0;
|
||||
|
||||
for (int i=0;i<packet->payload_count;i++) {
|
||||
payload = (asf_payload_t *)(&packet->payloads[i]);
|
||||
// find the first payload matching the id we want and then
|
||||
// combine the next x payloads where x is the noPayloads in indexEntry
|
||||
if (payload->media_object_number == indexEntry.id && payload->stream_number == streamIndex) {
|
||||
// copy data to buffer
|
||||
memcpy(*buffer + offset, payload->data, payload->datalen);
|
||||
offset += payload->datalen;
|
||||
expectedPayloads--;
|
||||
|
||||
if (expectedPayloads == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// combine packets into a single buffer
|
||||
while ((asf_get_packet(asfFile, packet) > 0) && (expectedPayloads > 0)) {
|
||||
for (int i=0;i<packet->payload_count;i++) {
|
||||
payload = (asf_payload_t *)(&packet->payloads[i]);
|
||||
// find the first payload matching the id we want and then
|
||||
// combine the next x payloads where x is the noPayloads in indexEntry
|
||||
if (payload->media_object_number == indexEntry.id && payload->stream_number == streamIndex) {
|
||||
// copy data to buffer
|
||||
memcpy(*buffer + offset, payload->data, payload->datalen);
|
||||
offset += payload->datalen;
|
||||
expectedPayloads--;
|
||||
if (expectedPayloads == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -35,6 +35,7 @@
|
||||
extern "C" {
|
||||
#include "libasf/asf.h"
|
||||
}
|
||||
#include "ASFIndex.h"
|
||||
|
||||
struct ASFAudioFormat {
|
||||
uint16 Compression;
|
||||
@ -60,71 +61,6 @@ struct ASFVideoFormat {
|
||||
uint8 *extraData;
|
||||
};
|
||||
|
||||
class IndexEntry {
|
||||
public:
|
||||
IndexEntry() {frameNo = 0;data=NULL;size=0;pts=0;keyFrame=false;};
|
||||
|
||||
uint32 frameNo; // frame_no or sample_no
|
||||
uint8 * data; // The data for this frame
|
||||
uint32 size; // The size of the data available
|
||||
bigtime_t pts; // Presentation Time Stamp for this frame
|
||||
bool keyFrame; // Is this a keyframe.
|
||||
};
|
||||
|
||||
class StreamHeader {
|
||||
public:
|
||||
StreamHeader() {streamIndex = 0;};
|
||||
~StreamHeader() {index.clear();};
|
||||
|
||||
void AddIndex(uint32 frameNo, bool keyFrame, bigtime_t pts, uint8 *data, uint32 size)
|
||||
{
|
||||
IndexEntry indexEntry;
|
||||
|
||||
// Should be in a constructor
|
||||
indexEntry.frameNo = frameNo;
|
||||
indexEntry.data = data;
|
||||
indexEntry.size = size;
|
||||
indexEntry.pts = pts;
|
||||
indexEntry.keyFrame = keyFrame;
|
||||
|
||||
index.push_back(indexEntry);
|
||||
};
|
||||
|
||||
IndexEntry GetIndex(uint32 frameNo)
|
||||
{
|
||||
IndexEntry indexEntry;
|
||||
|
||||
for (std::vector<IndexEntry>::iterator itr = index.begin();
|
||||
itr != index.end();
|
||||
++itr) {
|
||||
if (itr->frameNo == frameNo) {
|
||||
indexEntry = *itr;
|
||||
index.erase(itr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return indexEntry;
|
||||
};
|
||||
|
||||
bool HasIndex(uint32 frameNo)
|
||||
{
|
||||
if (!index.empty()) {
|
||||
for (std::vector<IndexEntry>::iterator itr = index.begin();
|
||||
itr != index.end();
|
||||
++itr) {
|
||||
if (itr->frameNo == frameNo) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
uint16 streamIndex;
|
||||
std::vector<IndexEntry> index;
|
||||
};
|
||||
|
||||
// ASF file reader
|
||||
class ASFFileReader {
|
||||
private:
|
||||
@ -132,7 +68,9 @@ private:
|
||||
BPositionIO *theStream;
|
||||
asf_file_t *asfFile;
|
||||
asf_packet_t *packet;
|
||||
std::vector<StreamHeader> streams;
|
||||
std::vector<StreamEntry> streams;
|
||||
|
||||
void ParseIndex();
|
||||
|
||||
public:
|
||||
ASFFileReader(BPositionIO *pStream);
|
||||
@ -150,20 +88,15 @@ public:
|
||||
// How many tracks in file
|
||||
uint32 getStreamCount();
|
||||
|
||||
// The first video track duration indexed by streamIndex
|
||||
bigtime_t getVideoDuration(uint32 streamIndex);
|
||||
// the first audio track duration indexed by streamIndex
|
||||
bigtime_t getAudioDuration(uint32 streamIndex);
|
||||
// the max of all active audio or video durations
|
||||
bigtime_t getMaxDuration();
|
||||
// the Stream duration indexed by streamIndex
|
||||
bigtime_t getStreamDuration(uint32 streamIndex);
|
||||
|
||||
bool getAudioFormat(uint32 streamIndex, ASFAudioFormat *format);
|
||||
bool getVideoFormat(uint32 streamIndex, ASFVideoFormat *format);
|
||||
|
||||
// The no of frames in the video track indexed by streamIndex
|
||||
// The no of frames in the Stream indexed by streamIndex
|
||||
uint32 getFrameCount(uint32 streamIndex);
|
||||
// The no of chunks in the audio track indexed by streamIndex
|
||||
uint32 getAudioChunkCount(uint32 streamIndex);
|
||||
|
||||
// Is stream (track) a video track
|
||||
bool IsVideo(uint32 streamIndex);
|
||||
// Is stream (track) a audio track
|
||||
@ -171,17 +104,16 @@ public:
|
||||
|
||||
BPositionIO *Source() {return theStream;};
|
||||
|
||||
void AddIndex(uint32 streamIndex, uint32 frameNo, bool keyFrame, bigtime_t pts, uint8 *data, uint32 size);
|
||||
IndexEntry GetIndex(uint32 streamIndex, uint32 frameNo);
|
||||
bool HasIndex(uint32 streamIndex, uint32 frameNo);
|
||||
|
||||
uint32 GetFrameForTime(uint32 streamIndex, bigtime_t time);
|
||||
|
||||
bool GetNextChunkInfo(uint32 streamIndex, uint32 pFrameNo, char **buffer, uint32 *size, bool *keyframe, bigtime_t *pts);
|
||||
|
||||
static int32_t read(void *opaque, void *buffer, int32_t size);
|
||||
static int32_t write(void *opaque, void *buffer, int32_t size);
|
||||
static int64_t seek(void *opaque, int64_t offset);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
158
src/add-ons/media/plugins/asf_reader/ASFIndex.cpp
Normal file
158
src/add-ons/media/plugins/asf_reader/ASFIndex.cpp
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2009, David McPaul
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "ASFIndex.h"
|
||||
|
||||
void
|
||||
IndexEntry::Clear()
|
||||
{
|
||||
frameNo=0;
|
||||
noPayloads=0;
|
||||
dataSize=0;
|
||||
pts=0;
|
||||
keyFrame=false;
|
||||
}
|
||||
|
||||
void
|
||||
IndexEntry::AddPayload(uint32 pdataSize)
|
||||
{
|
||||
noPayloads++;
|
||||
dataSize += pdataSize;
|
||||
}
|
||||
|
||||
StreamEntry::StreamEntry()
|
||||
{
|
||||
lastID = 0;
|
||||
frameCount = 0;
|
||||
maxPTS = 0;
|
||||
duration = 0;
|
||||
}
|
||||
|
||||
StreamEntry::~StreamEntry()
|
||||
{
|
||||
index.clear();
|
||||
}
|
||||
|
||||
void
|
||||
StreamEntry::setDuration(bigtime_t pduration)
|
||||
{
|
||||
duration = pduration;
|
||||
}
|
||||
|
||||
|
||||
IndexEntry
|
||||
StreamEntry::GetIndex(uint32 frameNo)
|
||||
{
|
||||
IndexEntry indexEntry;
|
||||
|
||||
for (std::vector<IndexEntry>::iterator itr = index.begin(); itr != index.end(); ++itr) {
|
||||
if (itr->frameNo == frameNo) {
|
||||
indexEntry = *itr;
|
||||
index.erase(itr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return indexEntry;
|
||||
}
|
||||
|
||||
bool
|
||||
StreamEntry::HasIndex(uint32 frameNo)
|
||||
{
|
||||
if (!index.empty()) {
|
||||
for (std::vector<IndexEntry>::iterator itr = index.begin();
|
||||
itr != index.end();
|
||||
++itr) {
|
||||
if (itr->frameNo == frameNo) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IndexEntry
|
||||
StreamEntry::GetIndex(bigtime_t pts)
|
||||
{
|
||||
IndexEntry indexEntry;
|
||||
|
||||
for (std::vector<IndexEntry>::iterator itr = index.begin(); itr != index.end(); ++itr) {
|
||||
if (pts <= itr->pts) {
|
||||
indexEntry = *itr;
|
||||
index.erase(itr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return indexEntry;
|
||||
}
|
||||
|
||||
bool
|
||||
StreamEntry::HasIndex(bigtime_t pts)
|
||||
{
|
||||
if (!index.empty()) {
|
||||
for (std::vector<IndexEntry>::iterator itr = index.begin();
|
||||
itr != index.end();
|
||||
++itr) {
|
||||
if (pts <= itr->pts) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Combine payloads with the same id into a single IndexEntry
|
||||
When isLast flag is set then no more payloads are available (ie add current entry to index)
|
||||
|
||||
*/
|
||||
void
|
||||
StreamEntry::AddPayload(uint32 id, bool keyFrame, bigtime_t pts, uint32 dataSize, bool isLast)
|
||||
{
|
||||
if (isLast) {
|
||||
maxPTS = indexEntry.pts;
|
||||
index.push_back(indexEntry);
|
||||
printf("Stream Index Loaded for Stream %d Max Index %ld Max PTS %Ld\n",streamIndex, frameCount, maxPTS);
|
||||
} else {
|
||||
if (id > lastID) {
|
||||
if (lastID != 0) {
|
||||
// add indexEntry to Index
|
||||
index.push_back(indexEntry);
|
||||
}
|
||||
lastID = id;
|
||||
indexEntry.Clear();
|
||||
|
||||
indexEntry.frameNo = frameCount++;
|
||||
indexEntry.keyFrame = keyFrame;
|
||||
indexEntry.pts = pts;
|
||||
indexEntry.dataSize = dataSize;
|
||||
indexEntry.noPayloads = 1;
|
||||
indexEntry.id = id;
|
||||
} else {
|
||||
indexEntry.AddPayload(dataSize);
|
||||
}
|
||||
}
|
||||
}
|
76
src/add-ons/media/plugins/asf_reader/ASFIndex.h
Normal file
76
src/add-ons/media/plugins/asf_reader/ASFIndex.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2009, David McPaul
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _ASF_INDEX_H
|
||||
#define _ASF_INDEX_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
class IndexEntry {
|
||||
public:
|
||||
IndexEntry() {frameNo = 0;noPayloads=0;dataSize=0;pts=0;keyFrame=false;};
|
||||
|
||||
uint32 frameNo; // frame_no or sample_no
|
||||
uint8 noPayloads; // The number of payloads that make up this frame
|
||||
uint32 dataSize; // The size of the data available
|
||||
bigtime_t pts; // Presentation Time Stamp for this frame
|
||||
bool keyFrame; // Is this a keyframe.
|
||||
uint8 id; // The id for this Entry
|
||||
|
||||
void Clear();
|
||||
void AddPayload(uint32 pdataSize);
|
||||
};
|
||||
|
||||
class StreamEntry {
|
||||
public:
|
||||
uint16 streamIndex;
|
||||
|
||||
StreamEntry();
|
||||
~StreamEntry();
|
||||
|
||||
IndexEntry GetIndex(uint32 frameNo);
|
||||
bool HasIndex(uint32 frameNo);
|
||||
IndexEntry GetIndex(bigtime_t pts);
|
||||
bool HasIndex(bigtime_t pts);
|
||||
|
||||
bigtime_t getMaxPTS() {return maxPTS;};
|
||||
uint32 getFrameCount() {return frameCount;};
|
||||
bigtime_t getDuration() {return duration;};
|
||||
void setDuration(bigtime_t pduration);
|
||||
|
||||
void AddPayload(uint32 id, bool keyFrame, bigtime_t pts, uint32 dataSize, bool isLast);
|
||||
|
||||
private:
|
||||
std::vector<IndexEntry> index;
|
||||
|
||||
IndexEntry indexEntry;
|
||||
uint32 lastID;
|
||||
uint32 frameCount;
|
||||
bigtime_t maxPTS;
|
||||
bigtime_t duration;
|
||||
};
|
||||
|
||||
#endif
|
@ -9,6 +9,7 @@ SubDirHdrs [ FDirName $(SUBDIR) libasf ] ;
|
||||
Addon asf_reader :
|
||||
asf_reader.cpp
|
||||
ASFFileReader.cpp
|
||||
ASFIndex.cpp
|
||||
:
|
||||
libasfreader.a
|
||||
be libmedia.so $(TARGET_LIBSTDC++)
|
||||
|
@ -185,22 +185,27 @@ asfReader::AllocateCookie(int32 streamNumber, void **_cookie)
|
||||
cookie->line_count = videoFormat.VideoHeight;
|
||||
cookie->frame_size = 1;
|
||||
|
||||
cookie->duration = theFileReader->getVideoDuration(streamNumber);
|
||||
cookie->duration = theFileReader->getStreamDuration(streamNumber);
|
||||
cookie->frame_count = theFileReader->getFrameCount(streamNumber);
|
||||
|
||||
TRACE("frame_count %Ld\n", cookie->frame_count);
|
||||
TRACE("duration %.6f (%Ld)\n", cookie->duration / 1E6, cookie->duration);
|
||||
|
||||
// asf does not have a frame rate! The extended descriptor defines an average time per frame.
|
||||
if (videoFormat.FrameScale && videoFormat.FrameRate) {
|
||||
cookie->frames_per_sec_rate = videoFormat.FrameRate;
|
||||
cookie->frames_per_sec_scale = videoFormat.FrameScale;
|
||||
TRACE("frames_per_sec_rate %ld, frames_per_sec_scale %ld (using both)\n", cookie->frames_per_sec_rate, cookie->frames_per_sec_scale);
|
||||
} else {
|
||||
cookie->frames_per_sec_rate = 25;
|
||||
cookie->frames_per_sec_scale = 1;
|
||||
TRACE("frames_per_sec_rate %ld, frames_per_sec_scale %ld (using fallback)\n", cookie->frames_per_sec_rate, cookie->frames_per_sec_scale);
|
||||
}
|
||||
// asf does not have a frame rate! The extended descriptor defines an average time per frame which is generally useless.
|
||||
|
||||
cookie->frames_per_sec_rate = cookie->frame_count;
|
||||
cookie->frames_per_sec_scale = cookie->duration / 1000000LL;
|
||||
TRACE("frames_per_sec_rate %ld, frames_per_sec_scale %ld (using both)\n", cookie->frames_per_sec_rate, cookie->frames_per_sec_scale);
|
||||
|
||||
// if (videoFormat.FrameScale && videoFormat.FrameRate) {
|
||||
// cookie->frames_per_sec_rate = videoFormat.FrameRate;
|
||||
// cookie->frames_per_sec_scale = videoFormat.FrameScale;
|
||||
// TRACE("frames_per_sec_rate %ld, frames_per_sec_scale %ld (using both)\n", cookie->frames_per_sec_rate, cookie->frames_per_sec_scale);
|
||||
// } else {
|
||||
// cookie->frames_per_sec_rate = 25;
|
||||
// cookie->frames_per_sec_scale = 1;
|
||||
// TRACE("frames_per_sec_rate %ld, frames_per_sec_scale %ld (using fallback)\n", cookie->frames_per_sec_rate, cookie->frames_per_sec_scale);
|
||||
// }
|
||||
|
||||
description.family = B_AVI_FORMAT_FAMILY;
|
||||
description.u.avi.codec = videoFormat.Compression;
|
||||
@ -277,6 +282,9 @@ asfReader::AllocateCookie(int32 streamNumber, void **_cookie)
|
||||
*(uint32 *)format->user_data = codecID; format->user_data[4] = 0;
|
||||
}
|
||||
|
||||
cookie->buffer_size = ((videoFormat.VideoWidth * videoFormat.VideoHeight * 4) + 15) & ~15; // WRONG Find max input buffer size needed
|
||||
cookie->buffer = new char [cookie->buffer_size];
|
||||
|
||||
return B_OK;
|
||||
|
||||
}
|
||||
@ -293,15 +301,16 @@ asfReader::AllocateCookie(int32 streamNumber, void **_cookie)
|
||||
uint32 sampleSize = (audioFormat.NoChannels * audioFormat.BitsPerSample / 8);
|
||||
|
||||
cookie->audio = true;
|
||||
cookie->duration = theFileReader->getAudioDuration(streamNumber);
|
||||
cookie->frame_count = (cookie->duration * audioFormat.SamplesPerSec) / sampleSize / 1000000LL;
|
||||
cookie->duration = theFileReader->getStreamDuration(streamNumber);
|
||||
// Calculate sample count using duration
|
||||
cookie->frame_count = (cookie->duration * audioFormat.SamplesPerSec) / 1000000LL;
|
||||
cookie->frame_pos = 0;
|
||||
cookie->frames_per_sec_rate = audioFormat.SamplesPerSec;
|
||||
cookie->frames_per_sec_scale = 1;
|
||||
cookie->bytes_per_sec_rate = audioFormat.AvgBytesPerSec;
|
||||
cookie->bytes_per_sec_scale = 1;
|
||||
|
||||
TRACE("Chunk Count %ld\n", theFileReader->getAudioChunkCount(streamNumber));
|
||||
TRACE("Chunk Count %ld\n", theFileReader->getFrameCount(streamNumber));
|
||||
TRACE("audio frame_count %Ld, duration %.6f\n", cookie->frame_count, cookie->duration / 1E6 );
|
||||
|
||||
if (audioFormat.Compression == 0x0001) {
|
||||
@ -349,6 +358,9 @@ asfReader::AllocateCookie(int32 streamNumber, void **_cookie)
|
||||
cookie->frame_size);
|
||||
}
|
||||
|
||||
cookie->buffer_size = (audioFormat.BlockAlign + 15) & ~15;
|
||||
cookie->buffer = new char [cookie->buffer_size];
|
||||
|
||||
// TODO: this doesn't seem to work (it's not even a fourcc)
|
||||
format->user_data_type = B_CODEC_TYPE_INFO;
|
||||
*(uint32 *)format->user_data = audioFormat.Compression; format->user_data[4] = 0;
|
||||
@ -386,7 +398,6 @@ status_t
|
||||
asfReader::FreeCookie(void *_cookie)
|
||||
{
|
||||
asf_cookie *cookie = (asf_cookie *)_cookie;
|
||||
cookie->buffer = NULL; // we don't own the buffer
|
||||
|
||||
delete [] cookie->buffer;
|
||||
|
||||
@ -436,13 +447,13 @@ asfReader::Seek(void *cookie, uint32 flags, int64 *frame, bigtime_t *time)
|
||||
if (flags & B_MEDIA_SEEK_TO_TIME) {
|
||||
// frame = (time * rate) / fps / 1000000LL
|
||||
*frame = ((*time * asfCookie->frames_per_sec_rate) / (int64)asfCookie->frames_per_sec_scale) / 1000000LL;
|
||||
asfCookie->frame_pos = *frame;
|
||||
asfCookie->frame_pos = theFileReader->GetFrameForTime(asfCookie->stream,*time);
|
||||
}
|
||||
|
||||
if (flags & B_MEDIA_SEEK_TO_FRAME) {
|
||||
// time = frame * 1000000LL * fps / rate
|
||||
*time = (*frame * 1000000LL * (int64)asfCookie->frames_per_sec_scale) / asfCookie->frames_per_sec_rate;
|
||||
asfCookie->frame_pos = *frame;
|
||||
asfCookie->frame_pos = theFileReader->GetFrameForTime(asfCookie->stream,*time);
|
||||
}
|
||||
|
||||
TRACE("asfReader::Seek: seekTo%s%s%s%s, time %Ld, frame %Ld\n",
|
||||
@ -514,9 +525,10 @@ asfReader::GetNextChunk(void *_cookie, const void **chunkBuffer,
|
||||
mediaHeader->u.encoded_video.field_number = 0;
|
||||
mediaHeader->u.encoded_video.field_sequence = cookie->frame_pos;
|
||||
}
|
||||
|
||||
TRACE(" stream %d: frame %ld start time %.6f Size %ld key frame %s\n",cookie->stream, cookie->frame_pos, mediaHeader->start_time / 1000000.0, size, keyframe ? "true" : "false");
|
||||
|
||||
cookie->frame_pos ++;
|
||||
cookie->frame_pos++;
|
||||
|
||||
*chunkBuffer = cookie->buffer;
|
||||
*chunkSize = size;
|
||||
|
@ -243,7 +243,8 @@ asf_seek_to_msec(asf_file_t *file, int64_t msec)
|
||||
}
|
||||
|
||||
/* Index structure is missing, check if we can still seek */
|
||||
if (file->index == NULL) {
|
||||
// DLM we can always seek to 0
|
||||
if (file->index == NULL && msec > 0) {
|
||||
int i, audiocount;
|
||||
|
||||
audiocount = 0;
|
||||
|
@ -31,14 +31,14 @@
|
||||
INLINE void
|
||||
debug_printf(char *fmt, ...)
|
||||
{
|
||||
//#ifdef DEBUG
|
||||
#ifdef DEBUG
|
||||
va_list argp;
|
||||
|
||||
va_start(argp, fmt);
|
||||
vfprintf(stderr, fmt, argp);
|
||||
va_end(argp);
|
||||
fprintf(stderr, "\n");
|
||||
//#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user