mirror of
https://github.com/ireader/media-server.git
synced 2026-01-12 00:18:51 +08:00
fix: avpacket queue iterator invalid
This commit is contained in:
@@ -93,6 +93,7 @@ enum EPSI_STREAM_TYPE
|
||||
PSI_STREAM_AUDIO_DTS = 0x8a, // ffmpeg/libavformat/mpegts.h
|
||||
PSI_STREAM_VIDEO_DIRAC = 0xd1, // ffmpeg/libavformat/mpegts.h
|
||||
PSI_STREAM_VIDEO_AVS3 = 0xd4, // ffmpeg/libavformat/mpegts.h
|
||||
PSI_STREAM_AUDIO_AVS3 = 0xd5, // avs3-p6
|
||||
PSI_STREAM_VIDEO_VC1 = 0xea, // ffmpeg/libavformat/mpegts.h
|
||||
PSI_STREAM_VIDEO_SVAC = 0x80, // GBT 25724-2010 SVAC(2014)
|
||||
PSI_STREAM_AUDIO_SVAC = 0x9B, // GBT 25724-2010 SVAC(2014)
|
||||
|
||||
@@ -1,163 +1,128 @@
|
||||
#include "avpacket-queue.h"
|
||||
#include "sys/sync.hpp"
|
||||
#include <deque>
|
||||
|
||||
struct avpacket_queue_t
|
||||
{
|
||||
std::deque<avpacket_t*>::size_type maxsize;
|
||||
std::deque<avpacket_t*> q;
|
||||
std::deque<avpacket_t*>::iterator it;
|
||||
ThreadLocker locker;
|
||||
ThreadEvent event;
|
||||
};
|
||||
|
||||
struct avpacket_queue_t* avpacket_queue_create(int size)
|
||||
{
|
||||
struct avpacket_queue_t* q = new struct avpacket_queue_t;
|
||||
q->maxsize = size;
|
||||
q->it = q->q.begin();
|
||||
return q;
|
||||
}
|
||||
|
||||
void avpacket_queue_destroy(struct avpacket_queue_t* q)
|
||||
{
|
||||
avpacket_queue_clear(q);
|
||||
delete q;
|
||||
}
|
||||
|
||||
void avpacket_queue_clear(struct avpacket_queue_t* q)
|
||||
{
|
||||
AutoThreadLocker locker(q->locker);
|
||||
while (!q->q.empty())
|
||||
{
|
||||
struct avpacket_t* pkt = q->q.front();
|
||||
avpacket_release(pkt);
|
||||
q->q.pop_front();
|
||||
}
|
||||
q->it = q->q.begin();
|
||||
}
|
||||
|
||||
int avpacket_queue_count(struct avpacket_queue_t* q)
|
||||
{
|
||||
AutoThreadLocker locker(q->locker);
|
||||
return (int)q->q.size();
|
||||
}
|
||||
|
||||
int avpacket_queue_pop(struct avpacket_queue_t* q)
|
||||
{
|
||||
struct avpacket_t* pkt;
|
||||
{
|
||||
AutoThreadLocker locker(q->locker);
|
||||
if (q->q.empty())
|
||||
return -1;
|
||||
|
||||
pkt = q->q.front();
|
||||
q->q.pop_front();
|
||||
q->event.Signal();
|
||||
}
|
||||
|
||||
if (*q->it == pkt)
|
||||
q->it++;
|
||||
|
||||
avpacket_release(pkt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct avpacket_t* avpacket_queue_front(struct avpacket_queue_t* q)
|
||||
{
|
||||
struct avpacket_t* pkt;
|
||||
AutoThreadLocker locker(q->locker);
|
||||
if (q->q.empty())
|
||||
return NULL;
|
||||
|
||||
pkt = q->q.front();
|
||||
avpacket_addref(pkt);
|
||||
return pkt;
|
||||
}
|
||||
|
||||
int avpacket_queue_push(struct avpacket_queue_t* q, struct avpacket_t* pkt)
|
||||
{
|
||||
AutoThreadLocker locker(q->locker);
|
||||
if (q->maxsize > 0 && q->q.size() >= q->maxsize)
|
||||
return -1;
|
||||
|
||||
avpacket_addref(pkt);
|
||||
q->q.push_back(pkt);
|
||||
q->event.Signal();
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct avpacket_t* avpacket_queue_front_wait(struct avpacket_queue_t* q, int ms)
|
||||
{
|
||||
q->locker.Lock();
|
||||
if (q->q.empty())
|
||||
{
|
||||
q->locker.Unlock();
|
||||
if (0 != q->event.TimeWait(ms))
|
||||
return NULL;
|
||||
q->locker.Lock();
|
||||
}
|
||||
|
||||
if (q->q.empty())
|
||||
{
|
||||
q->locker.Unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct avpacket_t* pkt = q->q.front();
|
||||
avpacket_addref(pkt);
|
||||
q->locker.Unlock();
|
||||
return pkt;
|
||||
}
|
||||
|
||||
int avpacket_queue_push_wait(struct avpacket_queue_t* q, struct avpacket_t* pkt, int ms)
|
||||
{
|
||||
q->locker.Lock();
|
||||
if (q->maxsize > 0 && q->q.size() >= q->maxsize)
|
||||
{
|
||||
q->locker.Unlock();
|
||||
if (0 != q->event.TimeWait(ms))
|
||||
return -1;
|
||||
q->locker.Lock();
|
||||
}
|
||||
|
||||
if (q->maxsize > 0 && q->q.size() >= q->maxsize)
|
||||
{
|
||||
q->locker.Unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
avpacket_addref(pkt);
|
||||
q->q.push_back(pkt);
|
||||
q->locker.Unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct avpacket_t* avpacket_queue_cur(struct avpacket_queue_t* q)
|
||||
{
|
||||
struct avpacket_t* pkt;
|
||||
AutoThreadLocker locker(q->locker);
|
||||
if (q->q.empty())
|
||||
return NULL;
|
||||
|
||||
if (q->it == q->q.end())
|
||||
return NULL;
|
||||
|
||||
pkt = *q->it++;
|
||||
avpacket_addref(pkt);
|
||||
return pkt;
|
||||
}
|
||||
|
||||
bool avpacket_queue_end(struct avpacket_queue_t* q)
|
||||
{
|
||||
AutoThreadLocker locker(q->locker);
|
||||
|
||||
return q->it == q->q.end();
|
||||
}
|
||||
|
||||
void avpacket_queue_reset(struct avpacket_queue_t* q)
|
||||
{
|
||||
AutoThreadLocker locker(q->locker);
|
||||
|
||||
q->it = q->q.begin();
|
||||
}
|
||||
#include "avpacket-queue.h"
|
||||
#include "sys/sync.hpp"
|
||||
#include <queue>
|
||||
|
||||
struct avpacket_queue_t
|
||||
{
|
||||
std::queue<avpacket_t*>::size_type maxsize;
|
||||
std::queue<avpacket_t*> q;
|
||||
ThreadLocker locker;
|
||||
ThreadEvent event;
|
||||
};
|
||||
|
||||
struct avpacket_queue_t* avpacket_queue_create(int size)
|
||||
{
|
||||
struct avpacket_queue_t* q = new struct avpacket_queue_t;
|
||||
q->maxsize = size;
|
||||
return q;
|
||||
}
|
||||
|
||||
void avpacket_queue_destroy(struct avpacket_queue_t* q)
|
||||
{
|
||||
avpacket_queue_clear(q);
|
||||
delete q;
|
||||
}
|
||||
|
||||
void avpacket_queue_clear(struct avpacket_queue_t* q)
|
||||
{
|
||||
AutoThreadLocker locker(q->locker);
|
||||
while (!q->q.empty())
|
||||
{
|
||||
struct avpacket_t* pkt = q->q.front();
|
||||
avpacket_release(pkt);
|
||||
q->q.pop();
|
||||
}
|
||||
}
|
||||
|
||||
int avpacket_queue_count(struct avpacket_queue_t* q)
|
||||
{
|
||||
AutoThreadLocker locker(q->locker);
|
||||
return (int)q->q.size();
|
||||
}
|
||||
|
||||
int avpacket_queue_pop(struct avpacket_queue_t* q)
|
||||
{
|
||||
struct avpacket_t* pkt;
|
||||
{
|
||||
AutoThreadLocker locker(q->locker);
|
||||
if (q->q.empty())
|
||||
return -1;
|
||||
|
||||
pkt = q->q.front();
|
||||
q->q.pop();
|
||||
q->event.Signal();
|
||||
}
|
||||
|
||||
avpacket_release(pkt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct avpacket_t* avpacket_queue_front(struct avpacket_queue_t* q)
|
||||
{
|
||||
struct avpacket_t* pkt;
|
||||
AutoThreadLocker locker(q->locker);
|
||||
if (q->q.empty())
|
||||
return NULL;
|
||||
|
||||
pkt = q->q.front();
|
||||
avpacket_addref(pkt);
|
||||
return pkt;
|
||||
}
|
||||
|
||||
int avpacket_queue_push(struct avpacket_queue_t* q, struct avpacket_t* pkt)
|
||||
{
|
||||
AutoThreadLocker locker(q->locker);
|
||||
if (q->q.size() >= q->maxsize)
|
||||
return -1;
|
||||
|
||||
avpacket_addref(pkt);
|
||||
q->q.push(pkt);
|
||||
q->event.Signal();
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct avpacket_t* avpacket_queue_front_wait(struct avpacket_queue_t* q, int ms)
|
||||
{
|
||||
q->locker.Lock();
|
||||
if (q->q.empty())
|
||||
{
|
||||
q->locker.Unlock();
|
||||
if (0 != q->event.TimeWait(ms))
|
||||
return NULL;
|
||||
q->locker.Lock();
|
||||
}
|
||||
|
||||
if (q->q.empty())
|
||||
{
|
||||
q->locker.Unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct avpacket_t* pkt = q->q.front();
|
||||
avpacket_addref(pkt);
|
||||
q->locker.Unlock();
|
||||
return pkt;
|
||||
}
|
||||
|
||||
int avpacket_queue_push_wait(struct avpacket_queue_t* q, struct avpacket_t* pkt, int ms)
|
||||
{
|
||||
q->locker.Lock();
|
||||
if (q->q.size() >= q->maxsize)
|
||||
{
|
||||
q->locker.Unlock();
|
||||
if (0 != q->event.TimeWait(ms))
|
||||
return -1;
|
||||
q->locker.Lock();
|
||||
}
|
||||
|
||||
if (q->q.size() >= q->maxsize)
|
||||
{
|
||||
q->locker.Unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
avpacket_addref(pkt);
|
||||
q->q.push(pkt);
|
||||
q->locker.Unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,51 +1,43 @@
|
||||
#ifndef _avpacket_queue_h_
|
||||
#define _avpacket_queue_h_
|
||||
|
||||
#include "avpacket.h"
|
||||
#include <stdint.h>
|
||||
|
||||
struct avpacket_queue_t;
|
||||
|
||||
struct avpacket_queue_t* avpacket_queue_create(int size);
|
||||
void avpacket_queue_destroy(struct avpacket_queue_t* q);
|
||||
|
||||
void avpacket_queue_clear(struct avpacket_queue_t* q);
|
||||
int avpacket_queue_count(struct avpacket_queue_t* q);
|
||||
int avpacket_queue_pop(struct avpacket_queue_t* q);
|
||||
|
||||
struct avpacket_t* avpacket_queue_front(struct avpacket_queue_t* q);
|
||||
int avpacket_queue_push(struct avpacket_queue_t* q, struct avpacket_t* pkt);
|
||||
|
||||
struct avpacket_t* avpacket_queue_front_wait(struct avpacket_queue_t* q, int ms);
|
||||
int avpacket_queue_push_wait(struct avpacket_queue_t* q, struct avpacket_t* pkt, int ms);
|
||||
|
||||
struct avpacket_t* avpacket_queue_cur(struct avpacket_queue_t* q);
|
||||
bool avpacket_queue_end(struct avpacket_queue_t* q);
|
||||
void avpacket_queue_reset(struct avpacket_queue_t* q);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
class AVPacketQueue
|
||||
{
|
||||
public:
|
||||
AVPacketQueue(int size) :m_pkts(avpacket_queue_create(size)) {}
|
||||
~AVPacketQueue() { if (m_pkts) avpacket_queue_destroy(m_pkts); }
|
||||
|
||||
public:
|
||||
void Clear() { avpacket_queue_clear(m_pkts); }
|
||||
int Count() const { return avpacket_queue_count(m_pkts); }
|
||||
|
||||
int Pop() { return avpacket_queue_pop(m_pkts); }
|
||||
int Push(struct avpacket_t* pkt) { return avpacket_queue_push(m_pkts, pkt); }
|
||||
int PushWait(struct avpacket_t* pkt, int ms) { return avpacket_queue_push_wait(m_pkts, pkt, ms); }
|
||||
struct avpacket_t* Front() { return avpacket_queue_front(m_pkts); }
|
||||
struct avpacket_t* FrontWait(int ms) { return avpacket_queue_front_wait(m_pkts, ms); }
|
||||
|
||||
struct avpacket_t* Cur() { return avpacket_queue_cur(m_pkts); };
|
||||
bool End() { return avpacket_queue_end(m_pkts); };
|
||||
void Reset() { return avpacket_queue_reset(m_pkts); };
|
||||
|
||||
private:
|
||||
struct avpacket_queue_t* m_pkts;
|
||||
};
|
||||
#endif
|
||||
#endif /* !_avpacket_queue_h_*/
|
||||
#ifndef _avpacket_queue_h_
|
||||
#define _avpacket_queue_h_
|
||||
|
||||
#include "avpacket.h"
|
||||
#include <stdint.h>
|
||||
|
||||
struct avpacket_queue_t;
|
||||
|
||||
struct avpacket_queue_t* avpacket_queue_create(int size);
|
||||
void avpacket_queue_destroy(struct avpacket_queue_t* q);
|
||||
|
||||
void avpacket_queue_clear(struct avpacket_queue_t* q);
|
||||
int avpacket_queue_count(struct avpacket_queue_t* q);
|
||||
int avpacket_queue_pop(struct avpacket_queue_t* q);
|
||||
|
||||
struct avpacket_t* avpacket_queue_front(struct avpacket_queue_t* q);
|
||||
int avpacket_queue_push(struct avpacket_queue_t* q, struct avpacket_t* pkt);
|
||||
|
||||
struct avpacket_t* avpacket_queue_front_wait(struct avpacket_queue_t* q, int ms);
|
||||
int avpacket_queue_push_wait(struct avpacket_queue_t* q, struct avpacket_t* pkt, int ms);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
class AVPacketQueue
|
||||
{
|
||||
public:
|
||||
AVPacketQueue(int size) :m_pkts(avpacket_queue_create(size)) {}
|
||||
~AVPacketQueue() { if (m_pkts) avpacket_queue_destroy(m_pkts); }
|
||||
|
||||
public:
|
||||
void Clear() { avpacket_queue_clear(m_pkts); }
|
||||
int Count() const { return avpacket_queue_count(m_pkts); }
|
||||
|
||||
int Pop() { return avpacket_queue_pop(m_pkts); }
|
||||
int Push(struct avpacket_t* pkt) { return avpacket_queue_push(m_pkts, pkt); }
|
||||
int PushWait(struct avpacket_t* pkt, int ms) { return avpacket_queue_push_wait(m_pkts, pkt, ms); }
|
||||
struct avpacket_t* Front() { return avpacket_queue_front(m_pkts); }
|
||||
struct avpacket_t* FrontWait(int ms) { return avpacket_queue_front_wait(m_pkts, ms); }
|
||||
|
||||
private:
|
||||
struct avpacket_queue_t* m_pkts;
|
||||
};
|
||||
#endif
|
||||
#endif /* !_avpacket_queue_h_*/
|
||||
|
||||
@@ -1,210 +1,203 @@
|
||||
#include "ps-file-reader.h"
|
||||
#include "mpeg-util.h"
|
||||
#include "mpeg-types.h"
|
||||
#include "mov-format.h"
|
||||
#include "avcodecid.h"
|
||||
#include "rtsp-payloads.h"
|
||||
#include <inttypes.h>
|
||||
#include <map>
|
||||
|
||||
PSFileReader::PSFileReader(const char* file)
|
||||
:m_fp(NULL), m_pos(0), m_v_start_ts(-1), m_v_end_ts(-1), m_v_codecid(-1), m_a_codecid(-1), m_duration(0), m_demuxer(NULL)
|
||||
{
|
||||
memset(&m_utils, 0, sizeof(m_utils));
|
||||
m_fp = fopen(file, "rb");
|
||||
if (m_fp)
|
||||
{
|
||||
static struct ps_demuxer_notify_t notify = {
|
||||
PSOnStream,
|
||||
};
|
||||
m_demuxer = ps_demuxer_create(PSOnRead, this);
|
||||
ps_demuxer_set_notify(m_demuxer, ¬ify, this);
|
||||
|
||||
m_pkts = std::shared_ptr<AVPacketQueue>(new AVPacketQueue(-1));
|
||||
|
||||
Init();
|
||||
}
|
||||
}
|
||||
|
||||
PSFileReader::~PSFileReader()
|
||||
{
|
||||
avpktutil_destroy(&m_utils);
|
||||
|
||||
if (m_demuxer)
|
||||
{
|
||||
ps_demuxer_destroy(m_demuxer);
|
||||
m_demuxer = NULL;
|
||||
}
|
||||
|
||||
if (m_fp)
|
||||
fclose(m_fp);
|
||||
}
|
||||
|
||||
int PSFileReader::Init()
|
||||
{
|
||||
int n, i = 0, r = 0;
|
||||
while ((n = fread(m_packet + i, 1, sizeof(m_packet) - i, m_fp)) > 0)
|
||||
{
|
||||
r = ps_demuxer_input(m_demuxer, m_packet, n + i);
|
||||
assert(r == n + i);
|
||||
memmove(m_packet, m_packet + r, n + i - r);
|
||||
i = n + i - r;
|
||||
}
|
||||
while (i > 0 && r > 0)
|
||||
{
|
||||
r = ps_demuxer_input(m_demuxer, m_packet, i);
|
||||
memmove(m_packet, m_packet + r, i - r);
|
||||
i -= r;
|
||||
}
|
||||
|
||||
if (m_v_start_ts >= 0 && m_v_end_ts >= 0)
|
||||
{
|
||||
m_duration = (m_v_end_ts - m_v_start_ts) / 90;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PSFileReader::Seek(int64_t& dts)
|
||||
{
|
||||
int64_t fisrt_dts = -1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
std::shared_ptr<avpacket_t> pkt(m_pkts->Cur(), avpacket_release);
|
||||
if (NULL == pkt)
|
||||
return -1;
|
||||
|
||||
if (fisrt_dts == -1)
|
||||
fisrt_dts = pkt->dts / 90;
|
||||
|
||||
if (dts < fisrt_dts)
|
||||
break;
|
||||
|
||||
if (dts >= (pkt->dts / 90))
|
||||
{
|
||||
// only audio
|
||||
if (m_v_start_ts < 0)
|
||||
return 0;
|
||||
|
||||
if (pkt->flags & AVPACKET_FLAG_KEY)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
m_pkts->Reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PSFileReader::OnPacket(struct avpacket_t* pkt)
|
||||
{
|
||||
int ret = m_pkts->Push(pkt);
|
||||
m_pkts->Reset();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PSFileReader::GetNextFrame(int64_t& pts, int64_t& dts, const uint8_t*& ptr, size_t& bytes, int& codecid, int& flags)
|
||||
{
|
||||
if (m_pkts->End())
|
||||
return -1; // file end
|
||||
|
||||
std::shared_ptr<avpacket_t> pkt(m_pkts->Cur(), avpacket_release);
|
||||
|
||||
ptr = pkt->data;
|
||||
bytes = pkt->size;
|
||||
pts = pkt->pts;
|
||||
dts = pkt->dts;
|
||||
flags = pkt->flags;
|
||||
codecid = (pkt->stream->codecid >= AVCODEC_VIDEO_MPEG1 && pkt->stream->codecid <= AVCODEC_VIDEO_SVAC) ? m_v_codecid : m_a_codecid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PSFileReader::PSOnStream(void* param, int stream, int codecid, const void* extra, int bytes, int finish)
|
||||
{
|
||||
printf("stream %d, codecid: %d, finish: %s\n", stream, codecid, finish ? "true" : "false");
|
||||
|
||||
PSFileReader* self = (PSFileReader*)param;
|
||||
int r = avpayload_find_by_mpeg2(codecid);
|
||||
if (r == -1)
|
||||
return;
|
||||
|
||||
AVPACKET_CODEC_ID avcodecid = s_payloads[r].codecid;
|
||||
if (avcodecid >= AVCODEC_VIDEO_MPEG1 && avcodecid <= AVCODEC_VIDEO_SVAC)
|
||||
{
|
||||
avpktutil_addvideo(&self->m_utils, stream, avcodecid, 0, 0, extra, bytes);
|
||||
self->m_v_codecid = codecid;
|
||||
}
|
||||
else if (avcodecid >= AVCODEC_AUDIO_PCM && avcodecid <= AVCODEC_AUDIO_SVAC)
|
||||
{
|
||||
avpktutil_addaudio(&self->m_utils, stream, avcodecid, 0, 0, 0, extra, bytes);
|
||||
self->m_a_codecid = codecid;
|
||||
}
|
||||
}
|
||||
|
||||
inline const char* ftimestamp(int64_t t, char* buf)
|
||||
{
|
||||
if (PTS_NO_VALUE == t)
|
||||
{
|
||||
sprintf(buf, "(null)");
|
||||
}
|
||||
else
|
||||
{
|
||||
t /= 90;
|
||||
sprintf(buf, "%d:%02d:%02d.%03d", (int)(t / 3600000), (int)((t / 60000) % 60), (int)((t / 1000) % 60), (int)(t % 1000));
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
int PSFileReader::PSOnRead(void* param, int stream, int avtype, int flags, int64_t pts, int64_t dts, const void* data, size_t bytes)
|
||||
{
|
||||
PSFileReader* self = (PSFileReader*)param;
|
||||
static std::map<int, std::pair<int64_t, int64_t>> s_streams;
|
||||
static char s_pts[64], s_dts[64];
|
||||
|
||||
auto it = s_streams.find(stream);
|
||||
if (it == s_streams.end())
|
||||
it = s_streams.insert(std::make_pair(stream, std::pair<int64_t, int64_t>(pts, dts))).first;
|
||||
|
||||
if (mpeg_stream_type_audio(avtype))
|
||||
{
|
||||
//assert(0 == a_dts || dts >= a_dts);
|
||||
printf("[A] pts: %s(%" PRId64 "), dts: %s(%" PRId64 "), diff: %03d/%03d, size: %u\n",
|
||||
ftimestamp(pts, s_pts), pts, ftimestamp(dts, s_dts), dts, (int)(pts - it->second.first) / 90,
|
||||
(int)(dts - it->second.second) / 90, (unsigned int)bytes);
|
||||
}
|
||||
else if (mpeg_stream_type_video(avtype))
|
||||
{
|
||||
//assert(0 == v_dts || dts >= v_dts);
|
||||
printf("[V] pts: %s(%" PRId64 "), dts: %s(%" PRId64 "), diff: %03d/%03d, size: %u%s\n",
|
||||
ftimestamp(pts, s_pts), pts, ftimestamp(dts, s_dts), dts, (int)(pts - it->second.first) / 90,
|
||||
(int)(dts - it->second.second) / 90, (unsigned int)bytes, (flags & MPEG_FLAG_IDR_FRAME) ? " [I]" : "");
|
||||
|
||||
if (self->m_v_start_ts == -1)
|
||||
self->m_v_start_ts = dts < 0 ? pts : dts;
|
||||
self->m_v_end_ts = dts < 0 ? pts : dts;
|
||||
}
|
||||
else
|
||||
{
|
||||
//assert(0);
|
||||
//assert(0 == x_dts || dts >= x_dts);
|
||||
printf("[X] pts: %s(%" PRId64 "), dts: %s(%" PRId64 "), diff: %03d/%03d\n",
|
||||
ftimestamp(pts, s_pts), pts, ftimestamp(dts, s_dts), dts, (int)(pts - it->second.first), (int)(dts - it->second.second));
|
||||
}
|
||||
|
||||
it->second = std::make_pair(pts, dts);
|
||||
|
||||
for (int i = 0; i < self->m_utils.count; i++)
|
||||
{
|
||||
if (self->m_utils.streams[i]->stream == stream)
|
||||
{
|
||||
struct avpacket_t* pkt = NULL;
|
||||
avpktutil_input(&self->m_utils, self->m_utils.streams[i], data, bytes, pts, dts, flags, &pkt);
|
||||
self->OnPacket(pkt);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
#include "ps-file-reader.h"
|
||||
#include "mpeg-util.h"
|
||||
#include "mpeg-types.h"
|
||||
#include "mov-format.h"
|
||||
#include "avcodecid.h"
|
||||
#include "rtsp-payloads.h"
|
||||
#include <inttypes.h>
|
||||
#include <map>
|
||||
|
||||
PSFileReader::PSFileReader(const char* file)
|
||||
:m_pos(0), m_v_start_ts(-1), m_v_end_ts(-1), m_v_codecid(-1), m_a_codecid(-1), m_duration(0)
|
||||
{
|
||||
memset(&m_utils, 0, sizeof(m_utils));
|
||||
|
||||
Init(file);
|
||||
m_it = m_pkts.begin();
|
||||
}
|
||||
|
||||
PSFileReader::~PSFileReader()
|
||||
{
|
||||
avpktutil_destroy(&m_utils);
|
||||
|
||||
for (auto it = m_pkts.begin(); it != m_pkts.end(); ++it)
|
||||
{
|
||||
auto pkt = *it;
|
||||
avpacket_release(pkt);
|
||||
}
|
||||
m_pkts.clear();
|
||||
}
|
||||
|
||||
int PSFileReader::Init(const char* file)
|
||||
{
|
||||
FILE* fp = fopen(file, "rb");
|
||||
if (!fp)
|
||||
return -1;
|
||||
|
||||
static struct ps_demuxer_notify_t notify = {
|
||||
PSOnStream,
|
||||
};
|
||||
ps_demuxer_t* demuxer = ps_demuxer_create(PSOnRead, this);
|
||||
ps_demuxer_set_notify(demuxer, ¬ify, this);
|
||||
|
||||
int n, i = 0, r = 0;
|
||||
while ((n = fread(m_packet + i, 1, sizeof(m_packet) - i, fp)) > 0)
|
||||
{
|
||||
r = ps_demuxer_input(demuxer, m_packet, n + i);
|
||||
assert(r == n + i);
|
||||
memmove(m_packet, m_packet + r, n + i - r);
|
||||
i = n + i - r;
|
||||
}
|
||||
while (i > 0 && r > 0)
|
||||
{
|
||||
r = ps_demuxer_input(demuxer, m_packet, i);
|
||||
memmove(m_packet, m_packet + r, i - r);
|
||||
i -= r;
|
||||
}
|
||||
|
||||
if (m_v_start_ts >= 0 && m_v_end_ts >= 0)
|
||||
{
|
||||
m_duration = (m_v_end_ts - m_v_start_ts) / 90;
|
||||
}
|
||||
|
||||
ps_demuxer_destroy(demuxer);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PSFileReader::Seek(int64_t& dts)
|
||||
{
|
||||
int64_t fisrt_dts = -1;
|
||||
|
||||
for(m_it = m_pkts.begin(); m_it != m_pkts.end(); ++m_it)
|
||||
{
|
||||
auto pkt = *m_it;
|
||||
if (fisrt_dts == -1)
|
||||
fisrt_dts = pkt->dts / 90;
|
||||
|
||||
if (dts < fisrt_dts)
|
||||
break;
|
||||
|
||||
if (dts >= (pkt->dts / 90))
|
||||
{
|
||||
// only audio
|
||||
if (m_v_start_ts < 0)
|
||||
return 0;
|
||||
|
||||
if (pkt->flags & AVPACKET_FLAG_KEY)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int PSFileReader::OnPacket(struct avpacket_t* pkt)
|
||||
{
|
||||
m_pkts.push_back(pkt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PSFileReader::GetNextFrame(int64_t& pts, int64_t& dts, const uint8_t*& ptr, size_t& bytes, int& codecid, int& flags)
|
||||
{
|
||||
if (m_it == m_pkts.end())
|
||||
return -1; // file end
|
||||
|
||||
ptr = (*m_it)->data;
|
||||
bytes = (*m_it)->size;
|
||||
pts = (*m_it)->pts;
|
||||
dts = (*m_it)->dts;
|
||||
flags = (*m_it)->flags;
|
||||
codecid = ((*m_it)->stream->codecid >= AVCODEC_VIDEO_MPEG1 && (*m_it)->stream->codecid <= AVCODEC_VIDEO_SVAC) ? m_v_codecid : m_a_codecid;
|
||||
|
||||
++m_it;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PSFileReader::PSOnStream(void* param, int stream, int codecid, const void* extra, int bytes, int finish)
|
||||
{
|
||||
printf("stream %d, codecid: %d, finish: %s\n", stream, codecid, finish ? "true" : "false");
|
||||
|
||||
PSFileReader* self = (PSFileReader*)param;
|
||||
int r = avpayload_find_by_mpeg2(codecid);
|
||||
if (r == -1)
|
||||
return;
|
||||
|
||||
AVPACKET_CODEC_ID avcodecid = s_payloads[r].codecid;
|
||||
if (avcodecid >= AVCODEC_VIDEO_MPEG1 && avcodecid <= AVCODEC_VIDEO_SVAC)
|
||||
{
|
||||
avpktutil_addvideo(&self->m_utils, stream, avcodecid, 0, 0, extra, bytes);
|
||||
self->m_v_codecid = codecid;
|
||||
}
|
||||
else if (avcodecid >= AVCODEC_AUDIO_PCM && avcodecid <= AVCODEC_AUDIO_SVAC)
|
||||
{
|
||||
avpktutil_addaudio(&self->m_utils, stream, avcodecid, 0, 0, 0, extra, bytes);
|
||||
self->m_a_codecid = codecid;
|
||||
}
|
||||
}
|
||||
|
||||
inline const char* ftimestamp(int64_t t, char* buf)
|
||||
{
|
||||
if (PTS_NO_VALUE == t)
|
||||
{
|
||||
sprintf(buf, "(null)");
|
||||
}
|
||||
else
|
||||
{
|
||||
t /= 90;
|
||||
sprintf(buf, "%d:%02d:%02d.%03d", (int)(t / 3600000), (int)((t / 60000) % 60), (int)((t / 1000) % 60), (int)(t % 1000));
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
int PSFileReader::PSOnRead(void* param, int stream, int avtype, int flags, int64_t pts, int64_t dts, const void* data, size_t bytes)
|
||||
{
|
||||
PSFileReader* self = (PSFileReader*)param;
|
||||
static std::map<int, std::pair<int64_t, int64_t>> s_streams;
|
||||
static char s_pts[64], s_dts[64];
|
||||
|
||||
auto it = s_streams.find(stream);
|
||||
if (it == s_streams.end())
|
||||
it = s_streams.insert(std::make_pair(stream, std::pair<int64_t, int64_t>(pts, dts))).first;
|
||||
|
||||
if (mpeg_stream_type_audio(avtype))
|
||||
{
|
||||
//assert(0 == a_dts || dts >= a_dts);
|
||||
printf("[A] pts: %s(%" PRId64 "), dts: %s(%" PRId64 "), diff: %03d/%03d, size: %u\n",
|
||||
ftimestamp(pts, s_pts), pts, ftimestamp(dts, s_dts), dts, (int)(pts - it->second.first) / 90,
|
||||
(int)(dts - it->second.second) / 90, (unsigned int)bytes);
|
||||
}
|
||||
else if (mpeg_stream_type_video(avtype))
|
||||
{
|
||||
//assert(0 == v_dts || dts >= v_dts);
|
||||
printf("[V] pts: %s(%" PRId64 "), dts: %s(%" PRId64 "), diff: %03d/%03d, size: %u%s\n",
|
||||
ftimestamp(pts, s_pts), pts, ftimestamp(dts, s_dts), dts, (int)(pts - it->second.first) / 90,
|
||||
(int)(dts - it->second.second) / 90, (unsigned int)bytes, (flags & MPEG_FLAG_IDR_FRAME) ? " [I]" : "");
|
||||
|
||||
if (self->m_v_start_ts == -1)
|
||||
self->m_v_start_ts = dts < 0 ? pts : dts;
|
||||
self->m_v_end_ts = dts < 0 ? pts : dts;
|
||||
}
|
||||
else
|
||||
{
|
||||
//assert(0);
|
||||
//assert(0 == x_dts || dts >= x_dts);
|
||||
printf("[X] pts: %s(%" PRId64 "), dts: %s(%" PRId64 "), diff: %03d/%03d\n",
|
||||
ftimestamp(pts, s_pts), pts, ftimestamp(dts, s_dts), dts, (int)(pts - it->second.first), (int)(dts - it->second.second));
|
||||
}
|
||||
|
||||
it->second = std::make_pair(pts, dts);
|
||||
|
||||
for (int i = 0; i < self->m_utils.count; i++)
|
||||
{
|
||||
if (self->m_utils.streams[i]->stream == stream)
|
||||
{
|
||||
struct avpacket_t* pkt = NULL;
|
||||
avpktutil_input(&self->m_utils, self->m_utils.streams[i], data, bytes, pts, dts, flags, &pkt);
|
||||
self->OnPacket(pkt);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1,48 +1,47 @@
|
||||
#ifndef _ps_file_reader_h_
|
||||
#define _ps_file_reader_h_
|
||||
|
||||
#include "vod-file-source.h"
|
||||
#include "mpeg-ps.h"
|
||||
#include "avpktutil.h"
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
class PSFileReader : std::enable_shared_from_this<PSFileReader>
|
||||
{
|
||||
public:
|
||||
PSFileReader(const char* file);
|
||||
virtual ~PSFileReader();
|
||||
|
||||
public:
|
||||
virtual int OnPacket(struct avpacket_t* pkt);
|
||||
|
||||
int GetDuration(int64_t& duration) const { duration = m_duration; return 0; }
|
||||
int GetNextFrame(int64_t& pts, int64_t& dts, const uint8_t*& ptr, size_t& bytes, int& codecid, int& flags);
|
||||
int Seek(int64_t& dts);
|
||||
|
||||
private:
|
||||
int Init();
|
||||
|
||||
static void PSOnStream(void* param, int stream, int codecid, const void* extra, int bytes, int finish);
|
||||
static int PSOnRead(void* param, int stream, int avtype, int flags, int64_t pts, int64_t dts, const void* data, size_t bytes);
|
||||
|
||||
public:
|
||||
int64_t m_v_start_ts;
|
||||
int64_t m_v_end_ts;
|
||||
int m_v_codecid;
|
||||
int m_a_codecid;
|
||||
|
||||
private:
|
||||
FILE* m_fp;
|
||||
int64_t m_pos;
|
||||
int64_t m_duration;
|
||||
ps_demuxer_t* m_demuxer;
|
||||
struct avpacket_t** m_pkt;
|
||||
struct avpktutil_t m_utils;
|
||||
uint8_t m_packet[2 * 1024 * 1024];
|
||||
|
||||
std::shared_ptr<AVPacketQueue> m_pkts;
|
||||
};
|
||||
|
||||
#endif /* !_ps_file_reader_h_ */
|
||||
#ifndef _ps_file_reader_h_
|
||||
#define _ps_file_reader_h_
|
||||
|
||||
#include "vod-file-source.h"
|
||||
#include "mpeg-ps.h"
|
||||
#include "avpktutil.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
class PSFileReader : std::enable_shared_from_this<PSFileReader>
|
||||
{
|
||||
public:
|
||||
PSFileReader(const char* file);
|
||||
virtual ~PSFileReader();
|
||||
|
||||
public:
|
||||
virtual int OnPacket(struct avpacket_t* pkt);
|
||||
|
||||
int GetDuration(int64_t& duration) const { duration = m_duration; return 0; }
|
||||
int GetNextFrame(int64_t& pts, int64_t& dts, const uint8_t*& ptr, size_t& bytes, int& codecid, int& flags);
|
||||
int Seek(int64_t& dts);
|
||||
|
||||
private:
|
||||
int Init(const char* file);
|
||||
|
||||
static void PSOnStream(void* param, int stream, int codecid, const void* extra, int bytes, int finish);
|
||||
static int PSOnRead(void* param, int stream, int avtype, int flags, int64_t pts, int64_t dts, const void* data, size_t bytes);
|
||||
|
||||
public:
|
||||
int64_t m_v_start_ts;
|
||||
int64_t m_v_end_ts;
|
||||
int m_v_codecid;
|
||||
int m_a_codecid;
|
||||
|
||||
private:
|
||||
int64_t m_pos;
|
||||
int64_t m_duration;
|
||||
struct avpktutil_t m_utils;
|
||||
uint8_t m_packet[2 * 1024 * 1024];
|
||||
|
||||
std::vector<avpacket_t*> m_pkts;
|
||||
std::vector<avpacket_t*>::iterator m_it;
|
||||
};
|
||||
|
||||
#endif /* !_ps_file_reader_h_ */
|
||||
|
||||
Reference in New Issue
Block a user