Permalink
Browse files

ssif remux

  • Loading branch information...
afedchin authored and popcornmix committed Jan 22, 2016
1 parent ed3c50c commit e5fb05e69475864c5cb7335150a58ee713d0e24b
@@ -52,6 +52,8 @@
#include "stdint.h"
#endif
//#define DEBUG_VERBOSE 1
extern "C" {
#include "libavutil/opt.h"
}
@@ -192,6 +194,8 @@ CDVDDemuxFFmpeg::CDVDDemuxFFmpeg() : CDVDDemux()
m_currentPts = DVD_NOPTS_VALUE;
m_bMatroska = false;
m_bAVI = false;
m_bSSIF = false;
m_bSSIFSyncing = false;
m_speed = DVD_PLAYSPEED_NORMAL;
m_program = UINT_MAX;
m_pkt.result = -1;
@@ -535,6 +539,17 @@ void CDVDDemuxFFmpeg::Dispose()
{
m_pkt.result = -1;
av_free_packet(&m_pkt.pkt);
while (!m_H264queue.empty())
{
CDVDDemuxUtils::FreeDemuxPacket(m_H264queue.front());
m_H264queue.pop();
}
while (!m_MVCqueue.empty())
{
CDVDDemuxUtils::FreeDemuxPacket(m_MVCqueue.front());
m_MVCqueue.pop();
}
m_bSSIFSyncing = true;
if (m_pFormatContext)
{
@@ -583,6 +598,17 @@ void CDVDDemuxFFmpeg::Flush()
m_pkt.result = -1;
av_free_packet(&m_pkt.pkt);
while (!m_H264queue.empty())
{
CDVDDemuxUtils::FreeDemuxPacket(m_H264queue.front());
m_H264queue.pop();
}
while (!m_MVCqueue.empty())
{
CDVDDemuxUtils::FreeDemuxPacket(m_MVCqueue.front());
m_MVCqueue.pop();
}
m_bSSIFSyncing = true;
}
void CDVDDemuxFFmpeg::Abort()
@@ -694,6 +720,148 @@ double CDVDDemuxFFmpeg::ConvertTimestamp(int64_t pts, int den, int num)
return timestamp*DVD_TIME_BASE;
}
DemuxPacket* mergePacket(DemuxPacket* &srcPkt, DemuxPacket* &appendPkt)
{
DemuxPacket* newpkt = NULL;
newpkt = CDVDDemuxUtils::AllocateDemuxPacket(srcPkt->iSize + appendPkt->iSize);
newpkt->iSize = srcPkt->iSize + appendPkt->iSize;
newpkt->pts = srcPkt->pts;
newpkt->dts = srcPkt->dts;
newpkt->duration = srcPkt->duration;
newpkt->iGroupId = srcPkt->iGroupId;
newpkt->iStreamId = srcPkt->iStreamId;
memcpy(newpkt->pData, srcPkt->pData, srcPkt->iSize);
memcpy(newpkt->pData + srcPkt->iSize, appendPkt->pData, appendPkt->iSize);
CDVDDemuxUtils::FreeDemuxPacket(srcPkt);
srcPkt = NULL;
CDVDDemuxUtils::FreeDemuxPacket(appendPkt);
appendPkt = NULL;
return newpkt;
}
DemuxPacket* movePacket(DemuxPacket* &srcPkt)
{
DemuxPacket* newpkt = NULL;
newpkt = CDVDDemuxUtils::AllocateDemuxPacket(srcPkt->iSize);
newpkt->iSize = srcPkt->iSize;
newpkt->pts = srcPkt->pts;
newpkt->dts = srcPkt->dts;
newpkt->duration = srcPkt->duration;
newpkt->iGroupId = srcPkt->iGroupId;
newpkt->iStreamId = srcPkt->iStreamId;
memcpy(newpkt->pData, srcPkt->pData, srcPkt->iSize);
CDVDDemuxUtils::FreeDemuxPacket(srcPkt);
srcPkt = NULL;
return newpkt;
}
DemuxPacket* CDVDDemuxFFmpeg::GetMVCPacket()
{
// Here, we recreate a h264 MVC packet from the base one + buffered MVC NALU's
DemuxPacket* newpkt = NULL;
double tsH264 = DVD_NOPTS_VALUE;
DemuxPacket* h264pkt = NULL;
if (!m_H264queue.empty())
{
h264pkt = m_H264queue.front();
tsH264 = (h264pkt->dts != DVD_NOPTS_VALUE ? h264pkt->dts : h264pkt->pts);
//CLog::Log(LOGDEBUG, ">>> MVC h264 packet: %d, pts(%f) dts (%f)", h264pkt->iSize, h264pkt->pts, h264pkt->dts);
}
double tsMVC = DVD_NOPTS_VALUE;
DemuxPacket* mvcpkt = NULL;
if (!m_MVCqueue.empty())
{
mvcpkt = m_MVCqueue.front();
tsMVC = (mvcpkt->dts != DVD_NOPTS_VALUE ? mvcpkt->dts : mvcpkt->pts);
//CLog::Log(LOGDEBUG, ">>> MVC mvc packet: %d, pts(%f) dts (%f)", mvcpkt->iSize, mvcpkt->pts, mvcpkt->dts);
}
if (tsH264 == tsMVC)
{
m_bSSIFSyncing = false;
m_H264queue.pop();
m_MVCqueue.pop();
#if defined(DEBUG_VERBOSE)
CLog::Log(LOGDEBUG, ">>> MVC merge packet: %d+%d, pts(%f/%f) dts (%f/%f)", h264pkt->iSize, mvcpkt->iSize, h264pkt->pts, mvcpkt->pts, h264pkt->dts, mvcpkt->dts);
#endif
newpkt = mergePacket(h264pkt, mvcpkt);
if (!m_MVCqueue.empty())
{
mvcpkt = m_MVCqueue.front();
while (mvcpkt->dts == DVD_NOPTS_VALUE && mvcpkt->pts == DVD_NOPTS_VALUE)
{
// Append leftover
#if defined(DEBUG_VERBOSE)
CLog::Log(LOGDEBUG, ">>> MVC merge leftover: %d+%d, pts(%f) dts (%f)", newpkt->iSize, mvcpkt->iSize, newpkt->pts, newpkt->dts);
#endif
newpkt = mergePacket(newpkt, mvcpkt);
m_MVCqueue.pop();
if (m_MVCqueue.empty())
break;
mvcpkt = m_MVCqueue.front();
}
}
}
else if (tsH264 > tsMVC)
{
// H264 before MVC ?
#if defined(DEBUG_VERBOSE)
CLog::Log(LOGDEBUG, ">>> MVC missing mvc: %d, pts(%f) dts (%f)", h264pkt->iSize, h264pkt->pts, h264pkt->dts);
#endif
if (m_bSSIFSyncing)
{
if (!m_H264queue.empty())
{
CDVDDemuxUtils::FreeDemuxPacket(m_H264queue.front());
m_H264queue.pop();
}
while (!m_MVCqueue.empty())
{
CDVDDemuxUtils::FreeDemuxPacket(m_MVCqueue.front());
m_MVCqueue.pop();
}
}
else if (!m_MVCqueue.empty())
{
// pop or we are stuck
CDVDDemuxUtils::FreeDemuxPacket(m_MVCqueue.front());
m_MVCqueue.pop();
}
newpkt = CDVDDemuxUtils::AllocateDemuxPacket(0);
newpkt->iSize = 0;
}
else
{
if (m_bSSIFSyncing && !m_H264queue.empty())
{
CDVDDemuxUtils::FreeDemuxPacket(m_H264queue.front());
m_H264queue.pop();
}
else if (!m_H264queue.empty())
{
// missing an MVC packets
#if defined(DEBUG_VERBOSE)
CLog::Log(LOGDEBUG, ">>> MVC missing mvc2: %d, pts(%f) dts (%f)", h264pkt->iSize, h264pkt->pts, h264pkt->dts);
#endif
// pop or we are stuck
CDVDDemuxUtils::FreeDemuxPacket(m_H264queue.front());
m_H264queue.pop();
}
newpkt = CDVDDemuxUtils::AllocateDemuxPacket(0);
newpkt->iSize = 0;
}
return newpkt;
}
DemuxPacket* CDVDDemuxFFmpeg::Read()
{
DemuxPacket* pPacket = NULL;
@@ -729,7 +897,9 @@ DemuxPacket* CDVDDemuxFFmpeg::Read()
{
Flush();
}
else if (IsProgramChange())
// libavformat is confused by the interleaved SSIF.
// Disable program management for those
else if (!m_bSSIF && IsProgramChange())
{
// update streams
CreateStreams(m_program);
@@ -756,6 +926,11 @@ DemuxPacket* CDVDDemuxFFmpeg::Read()
m_pkt.result = -1;
av_free_packet(&m_pkt.pkt);
while (!m_MVCqueue.empty())
{
CDVDDemuxUtils::FreeDemuxPacket(m_MVCqueue.front());
m_MVCqueue.pop();
}
}
else
{
@@ -765,7 +940,9 @@ DemuxPacket* CDVDDemuxFFmpeg::Read()
if (IsVideoReady())
{
if (m_program != UINT_MAX)
// libavformat is confused by the interleaved SSIF.
// Disable program management for those
if ( !m_bSSIF && m_program != UINT_MAX )
{
/* check so packet belongs to selected program */
for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++)
@@ -905,6 +1082,23 @@ DemuxPacket* CDVDDemuxFFmpeg::Read()
// content has changed
stream = AddStream(pPacket->iStreamId);
}
if (m_bSSIF && stream->iPhysicalId == 0x1011)
{
DemuxPacket* newpkt = movePacket(pPacket);
m_H264queue.push(newpkt);
pPacket = GetMVCPacket();
}
}
else if (stream->type == STREAM_DATA)
{
if (m_bSSIF && stream->iPhysicalId == 0x1012)
{
DemuxPacket* newpkt = movePacket(pPacket);
m_MVCqueue.push(newpkt);
pPacket = GetMVCPacket();
if (pPacket->iSize)
stream = GetStreamInternal(pPacket->iStreamId);
}
}
if (!stream)
{
@@ -928,6 +1122,17 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts)
m_pkt.result = -1;
av_free_packet(&m_pkt.pkt);
while (!m_H264queue.empty())
{
CDVDDemuxUtils::FreeDemuxPacket(m_H264queue.front());
m_H264queue.pop();
}
while (!m_MVCqueue.empty())
{
CDVDDemuxUtils::FreeDemuxPacket(m_MVCqueue.front());
m_MVCqueue.pop();
}
m_bSSIFSyncing = true;
CDVDInputStream::ISeekTime* ist = dynamic_cast<CDVDInputStream::ISeekTime*>(m_pInput);
if (ist)
@@ -995,6 +1200,17 @@ bool CDVDDemuxFFmpeg::SeekByte(int64_t pos)
m_pkt.result = -1;
av_free_packet(&m_pkt.pkt);
while (!m_H264queue.empty())
{
CDVDDemuxUtils::FreeDemuxPacket(m_H264queue.front());
m_H264queue.pop();
}
while (!m_MVCqueue.empty())
{
CDVDDemuxUtils::FreeDemuxPacket(m_MVCqueue.front());
m_MVCqueue.pop();
}
m_bSSIFSyncing = true;
return (ret >= 0);
}
@@ -1185,10 +1401,11 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int iId)
if (pStream->codec->codec_id == AV_CODEC_ID_H264_MVC)
{
// ignore MVC extension streams, they are handled specially
m_bSSIF = true;
stream = new CDemuxStream();
stream->type = STREAM_DATA;
stream->disabled = true;
pStream->need_parsing = AVSTREAM_PARSE_NONE;
pStream->codec->codec_type = AVMEDIA_TYPE_DATA;
break;
}
CDemuxStreamVideoFFmpeg* st = new CDemuxStreamVideoFFmpeg(this, pStream);
@@ -1287,6 +1504,30 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int iId)
if (h264_is_annexb(m_pFormatContext->iformat->name, pStream))
{
// TODO
if (m_bSSIF)
{
//pStream->codec->codec_id = AV_CODEC_ID_H264_MVC;
pStream->codec->codec_tag = MKTAG('m', 'v', 'c', 'C');
AVStream *mvc = nullptr;
for (size_t i = 0; i < m_pFormatContext->nb_streams; i++)
if (m_pFormatContext->streams[i]->codec->codec_id == AV_CODEC_ID_H264_MVC)
mvc = m_pFormatContext->streams[i];
if (mvc)
{
AVRational r_frame_rate = mvc->r_frame_rate;
if (r_frame_rate.den && r_frame_rate.num)
{
st->iFpsRate = r_frame_rate.num;
st->iFpsScale = r_frame_rate.den;
}
else if (mvc->avg_frame_rate.den && mvc->avg_frame_rate.num)
{
st->iFpsRate = r_frame_rate.num;
st->iFpsScale = r_frame_rate.den;
}
}
}
}
else
{
@@ -1402,7 +1643,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int iId)
if (langTag)
strncpy(stream->language, langTag->value, 3);
if( stream->type != STREAM_NONE && pStream->codec->extradata && pStream->codec->extradata_size > 0 )
if (stream->type != STREAM_NONE && pStream->codec->extradata && pStream->codec->extradata_size > 0)
{
stream->ExtraSize = pStream->codec->extradata_size;
stream->ExtraData = new uint8_t[pStream->codec->extradata_size];
@@ -25,6 +25,7 @@
#include "threads/SystemClock.h"
#include <map>
#include <vector>
#include <queue>
extern "C" {
#include "libavformat/avformat.h"
@@ -49,6 +50,18 @@ class CDemuxStreamVideoFFmpeg
virtual std::string GetStreamName() override;
};
class CDemuxStreamVideoFFmpegSSIF
: public CDemuxStreamVideo
{
CDVDDemuxFFmpeg *m_parent;
AVStream* m_mvcStream;
AVStream* m_h264Stream;
public:
CDemuxStreamVideoFFmpegSSIF(CDVDDemuxFFmpeg *parent, AVStream* mvc)
: m_parent(parent)
, m_mvcStream(mvc)
{}
};
class CDemuxStreamAudioFFmpeg
: public CDemuxStreamAudio
@@ -135,6 +148,7 @@ class CDVDDemuxFFmpeg : public CDVDDemux
void ParsePacket(AVPacket *pkt);
bool IsVideoReady();
void ResetVideoStreams();
DemuxPacket* GetMVCPacket();
AVDictionary *GetFFMpegOptionsFromURL(const CURL &url);
double ConvertTimestamp(int64_t pts, int den, int num);
@@ -156,6 +170,10 @@ class CDVDDemuxFFmpeg : public CDVDDemux
double m_currentPts; // used for stream length estimation
bool m_bMatroska;
bool m_bAVI;
bool m_bSSIF;
bool m_bSSIFSyncing;
std::queue<DemuxPacket*> m_H264queue;
std::queue<DemuxPacket*> m_MVCqueue;
int m_speed;
unsigned m_program;
XbmcThreads::EndTime m_timeout;
Oops, something went wrong.

0 comments on commit e5fb05e

Please sign in to comment.