libeplayer3: implement Writer class

This commit is contained in:
martii
2014-04-06 11:35:17 +02:00
parent 25948637ab
commit d97d2a84d8
26 changed files with 849 additions and 2357 deletions

View File

@@ -19,62 +19,21 @@
*
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <stdint.h>
#include <string.h>
#include <sys/uio.h>
#include <linux/dvb/video.h>
#include <linux/dvb/audio.h>
#include <linux/dvb/stm_ioctls.h>
#include <memory.h>
#include <asm/types.h>
#include <pthread.h>
#include <errno.h>
#include <assert.h>
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define H264_DEBUG
#ifdef H264_DEBUG
static short debug_level = 0;
#define h264_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define h264_printf(level, fmt, x...)
#endif
#ifndef H264_SILENT
#define h264_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define h264_err(fmt, x...)
#endif
#define NALU_TYPE_PLAYER2_CONTAINER_PARAMETERS 24
#define CONTAINER_PARAMETERS_VERSION 0x00
/* ***************************** */
/* Types */
/* ***************************** */
typedef struct avcC_s {
unsigned char Version; /* configurationVersion */
unsigned char Profile; /* AVCProfileIndication */
@@ -85,31 +44,30 @@ typedef struct avcC_s {
unsigned char Params[1]; /* {length,params}{length,params}...sequence then picture */
} avcC_t;
/* ***************************** */
/* Varaibles */
/* ***************************** */
const unsigned char Head[] = { 0, 0, 0, 1 };
static int initialHeader = 1;
static unsigned int NalLengthBytes = 1;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
class WriterH264 : public Writer
{
initialHeader = 1;
return 0;
private:
bool initialHeader;
unsigned int NalLengthBytes;
public:
bool Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket *packet, int64_t &pts);
void Init();
WriterH264();
};
void WriterH264::Init(void)
{
initialHeader = true;
initialHeader = 1;
NalLengthBytes = 1;
}
static int writeData(WriterAVCallData_t *call)
bool WriterH264::Write(int fd, AVFormatContext * /* avfc */, AVStream *stream, AVPacket *packet, int64_t &pts)
{
if (fd < 0 || !packet)
return false;
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
unsigned long long int VideoPts;
unsigned int TimeDelta;
@@ -118,50 +76,37 @@ static int writeData(WriterAVCallData_t *call)
int ic = 0;
struct iovec iov[128];
TimeDelta = 1000.0 * av_q2d(call->stream->r_frame_rate); /* rational to double */
TimeDelta = 1000.0 * av_q2d(stream->r_frame_rate); /* rational to double */
TimeScale = (TimeDelta < 23970) ? 1001 : 1000; /* fixme: revise this */
VideoPts = pts;
VideoPts = call->Pts;
h264_printf(10, "VideoPts %lld - %d %d\n", call->Pts, TimeDelta, TimeScale);
if (call->fd < 0) {
h264_err("file pointer < 0. ignoring ...\n");
return 0;
}
if ((call->packet->size > 3)
&&
((call->packet->data[0] == 0x00 && call->packet->data[1] == 0x00
&& call->packet->data[2] == 0x00 && call->packet->data[3] == 0x01)
|| (call->packet->data[0] == 0xff && call->packet->data[1] == 0xff
&& call->packet->data[2] == 0xff && call->packet->data[3] == 0xff))) {
if ((packet->size > 3)
&& ((packet->data[0] == 0x00 && packet->data[1] == 0x00 && packet->data[2] == 0x00 && packet->data[3] == 0x01)
|| (packet->data[0] == 0xff && packet->data[1] == 0xff && packet->data[2] == 0xff && packet->data[3] == 0xff))) {
unsigned int PacketLength = 0;
unsigned int FakeStartCode = /* (call->Version << 8) | */ PES_VERSION_FAKE_START_CODE;
iov[ic++].iov_base = PesHeader;
if (initialHeader) {
initialHeader = 0;
iov[ic].iov_base = call->stream->codec->extradata;
iov[ic++].iov_len = call->stream->codec->extradata_size;
PacketLength += call->stream->codec->extradata_size;
initialHeader = false;
iov[ic].iov_base = stream->codec->extradata;
iov[ic++].iov_len = stream->codec->extradata_size;
PacketLength += stream->codec->extradata_size;
}
iov[ic].iov_base = call->packet->data;
iov[ic++].iov_len = call->packet->size;
PacketLength += call->packet->size;
iov[ic].iov_base = packet->data;
iov[ic++].iov_len = packet->size;
PacketLength += packet->size;
/*Hellmaster1024: some packets will only be accepted by the player if we send one byte more than
data is available. The content of this byte does not matter. It will be ignored
by the player */
iov[ic].iov_base = (char *) "";
iov[ic].iov_base = (void *) "";
iov[ic++].iov_len = 1;
iov[0].iov_len =
InsertPesHeader(PesHeader, PacketLength,
MPEG_VIDEO_PES_START_CODE, call->Pts,
FakeStartCode);
return writev(call->fd, iov, ic);
InsertPesHeader(PesHeader, PacketLength, MPEG_VIDEO_PES_START_CODE, pts, FakeStartCode);
return writev(fd, iov, ic) > -1;
}
if (initialHeader) {
avcC_t *avcCHeader = (avcC_t *) call->stream->codec->extradata;
avcC_t *avcCHeader = (avcC_t *) stream->codec->extradata;
unsigned int i;
unsigned int ParamSets;
unsigned int ParamOffset;
@@ -169,13 +114,12 @@ static int writeData(WriterAVCallData_t *call)
unsigned int ParametersLength;
if (avcCHeader == NULL) {
h264_err("private_data NULL\n");
return -1;
fprintf(stderr, "stream->codec->extradata == NULL\n");
return false;
}
if (avcCHeader->Version != 1)
h264_err("Error unknown avcC version (%x). Expect problems.\n",
avcCHeader->Version);
fprintf(stderr, "Error unknown avcC version (%x). Expect problems.\n", avcCHeader->Version);
ParametersLength = 0;
@@ -211,33 +155,16 @@ static int writeData(WriterAVCallData_t *call)
ic = 0;
iov[ic].iov_base = PesHeader;
iov[ic++].iov_len =
InsertPesHeader(PesHeader, ParametersLength,
MPEG_VIDEO_PES_START_CODE, INVALID_PTS_VALUE,
0);
iov[ic++].iov_len = InsertPesHeader(PesHeader, ParametersLength, MPEG_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0);
iov[ic].iov_base = HeaderData;
iov[ic++].iov_len = ParametersLength;
len = writev(call->fd, iov, ic);
len = writev(fd, iov, ic);
if (len < 0)
return len;
return false;
NalLengthBytes = (avcCHeader->NalLengthMinusOne & 0x03) + 1;
ParamSets = avcCHeader->NumParamSets & 0x1f;
h264_printf(20, "avcC contents:\n");
h264_printf(20, " version: %d\n",
avcCHeader->Version);
h264_printf(20, " profile: %d\n",
avcCHeader->Profile);
h264_printf(20, " profile compatibility: %d\n",
avcCHeader->Compatibility);
h264_printf(20, " level: %d\n",
avcCHeader->Level);
h264_printf(20, " nal length bytes: %d\n",
NalLengthBytes);
h264_printf(20, " number of sequence param sets: %d\n",
ParamSets);
ParamOffset = 0;
ic = 0;
iov[ic++].iov_base = PesHeader;
@@ -246,9 +173,6 @@ static int writeData(WriterAVCallData_t *call)
(avcCHeader->Params[ParamOffset] << 8) +
avcCHeader->Params[ParamOffset + 1];
h264_printf(20, " sps %d has length %d\n", i,
PsLength);
iov[ic].iov_base = (char *) Head;
iov[ic++].iov_len = sizeof(Head);
InitialHeaderLength += sizeof(Head);
@@ -260,18 +184,12 @@ static int writeData(WriterAVCallData_t *call)
ParamSets = avcCHeader->Params[ParamOffset];
h264_printf(20, " number of picture param sets: %d\n",
ParamSets);
ParamOffset++;
for (i = 0; i < ParamSets; i++) {
unsigned int PsLength =
(avcCHeader->Params[ParamOffset] << 8) +
avcCHeader->Params[ParamOffset + 1];
h264_printf(20, " pps %d has length %d\n", i,
PsLength);
iov[ic].iov_base = (char *) Head;
iov[ic++].iov_len = sizeof(Head);
InitialHeaderLength += sizeof(Head);
@@ -281,19 +199,16 @@ static int writeData(WriterAVCallData_t *call)
ParamOffset += PsLength + 2;
}
iov[0].iov_len =
InsertPesHeader(PesHeader, InitialHeaderLength,
MPEG_VIDEO_PES_START_CODE, INVALID_PTS_VALUE,
0);
ssize_t l = writev(call->fd, iov, ic);
iov[0].iov_len = InsertPesHeader(PesHeader, InitialHeaderLength, MPEG_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0);
ssize_t l = writev(fd, iov, ic);
if (l < 0)
return l;
return false;
len += l;
initialHeader = 0;
}
unsigned int SampleSize = call->packet->size;
unsigned int SampleSize = packet->size;
unsigned int NalStart = 0;
unsigned int VideoPosition = 0;
@@ -302,7 +217,7 @@ static int writeData(WriterAVCallData_t *call)
unsigned char NalData[4];
int NalPresent = 1;
memcpy(NalData, call->packet->data + VideoPosition, NalLengthBytes);
memcpy(NalData, packet->data + VideoPosition, NalLengthBytes);
VideoPosition += NalLengthBytes;
NalStart += NalLengthBytes;
switch (NalLengthBytes) {
@@ -313,25 +228,15 @@ static int writeData(WriterAVCallData_t *call)
NalLength = (NalData[0] << 8) | (NalData[1]);
break;
case 3:
NalLength =
(NalData[0] << 16) | (NalData[1] << 8) | (NalData[2]);
NalLength = (NalData[0] << 16) | (NalData[1] << 8) | (NalData[2]);
break;
default:
NalLength =
(NalData[0] << 24) | (NalData[1] << 16) | (NalData[2] << 8)
| (NalData[3]);
NalLength = (NalData[0] << 24) | (NalData[1] << 16) | (NalData[2] << 8) | (NalData[3]);
break;
}
h264_printf(20,
"NalStart = %u + NalLength = %u > SampleSize = %u\n",
NalStart, NalLength, SampleSize);
if (NalStart + NalLength > SampleSize) {
h264_printf(20,
"nal length past end of buffer - size %u frame offset %u left %u\n",
NalLength, NalStart, SampleSize - NalStart);
fprintf(stderr, "nal length past end of buffer - size %u frame offset %u left %u\n", NalLength, NalStart, SampleSize - NalStart);
NalStart = SampleSize;
} else {
NalStart += NalLength;
@@ -344,46 +249,28 @@ static int writeData(WriterAVCallData_t *call)
iov[ic++].iov_len = sizeof(Head);
}
iov[ic].iov_base = call->packet->data + VideoPosition;
iov[ic].iov_base = packet->data + VideoPosition;
iov[ic++].iov_len = NalLength;
VideoPosition += NalLength;
h264_printf(20, " pts=%llu\n", VideoPts);
iov[0].iov_len =
InsertPesHeader(PesHeader, NalLength,
MPEG_VIDEO_PES_START_CODE, VideoPts, 0);
ssize_t l = writev(call->fd, iov, ic);
ssize_t l = writev(fd, iov, ic);
if (l < 0)
return l;
return false;
len += l;
VideoPts = INVALID_PTS_VALUE;
}
} while (NalStart < SampleSize);
if (len < 0) {
h264_err("error writing data errno = %d\n", errno);
h264_err("%s\n", strerror(errno));
}
h264_printf(10, "< len %d\n", len);
return len;
return len > -1;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
WriterH264::WriterH264()
{
Register(this, AV_CODEC_ID_H264, VIDEO_ENCODING_H264);
}
static WriterCaps_t caps = {
"h264",
eVideo,
"V_MPEG4/ISO/AVC",
VIDEO_ENCODING_H264
};
struct Writer_s WriterVideoH264 = {
&reset,
&writeData,
&caps
};
static WriterH264 writerh264 __attribute__ ((init_priority (300)));