stream-deploy/ZLM/3rdpart/media-server/librtsp/test/media/ps-file-reader.cpp

204 lines
5.1 KiB
C++

#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, &notify, 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;
}