mirror of
https://github.com/tuxbox-neutrino/libstb-hal.git
synced 2025-08-27 23:43:00 +02:00
libeplayer3: rename files
This commit is contained in:
62
libeplayer3/writer/ac3.cpp
Normal file
62
libeplayer3/writer/ac3.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/uio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
class WriterAC3 : public Writer
|
||||
{
|
||||
public:
|
||||
bool Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket *packet, int64_t &pts);
|
||||
WriterAC3();
|
||||
};
|
||||
|
||||
bool WriterAC3::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];
|
||||
struct iovec iov[2];
|
||||
|
||||
iov[0].iov_base = PesHeader;
|
||||
iov[0].iov_len = InsertPesHeader(PesHeader, packet->size, PRIVATE_STREAM_1_PES_START_CODE, pts, 0);
|
||||
iov[1].iov_base = packet->data;
|
||||
iov[1].iov_len = packet->size;
|
||||
|
||||
return writev(fd, iov, 2) > -1;
|
||||
}
|
||||
|
||||
WriterAC3::WriterAC3()
|
||||
{
|
||||
Register(this, AV_CODEC_ID_AC3, AUDIO_ENCODING_AC3);
|
||||
Register(this, AV_CODEC_ID_EAC3, AUDIO_ENCODING_AC3);
|
||||
}
|
||||
|
||||
static WriterAC3 writer_ac3 __attribute__ ((init_priority (300)));
|
122
libeplayer3/writer/divx.cpp
Normal file
122
libeplayer3/writer/divx.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
/* ***************************** */
|
||||
/* 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 <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 "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
class WriterDIVX : public Writer
|
||||
{
|
||||
private:
|
||||
bool initialHeader;
|
||||
public:
|
||||
bool Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket *packet, int64_t &pts);
|
||||
void Init();
|
||||
WriterDIVX();
|
||||
};
|
||||
|
||||
void WriterDIVX::Init()
|
||||
{
|
||||
initialHeader = true;
|
||||
}
|
||||
|
||||
bool WriterDIVX::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 char FakeHeaders[64]; // 64bytes should be enough to make the fake headers
|
||||
unsigned int FakeHeaderLength;
|
||||
unsigned char Version = 5;
|
||||
unsigned int FakeStartCode = (Version << 8) | PES_VERSION_FAKE_START_CODE;
|
||||
unsigned int usecPerFrame = 41708; /* Hellmaster1024: default value */
|
||||
BitPacker_t ld = { FakeHeaders, 0, 32 };
|
||||
|
||||
usecPerFrame = 1000000 / av_q2d(stream->r_frame_rate);
|
||||
|
||||
memset(FakeHeaders, 0, sizeof(FakeHeaders));
|
||||
|
||||
/* Create info record for frame parser */
|
||||
/* divx4 & 5
|
||||
VOS
|
||||
PutBits(&ld, 0x0, 8);
|
||||
PutBits(&ld, 0x0, 8);
|
||||
*/
|
||||
PutBits(&ld, 0x1b0, 32); // startcode
|
||||
PutBits(&ld, 0, 8); // profile = reserved
|
||||
PutBits(&ld, 0x1b2, 32); // startcode (user data)
|
||||
PutBits(&ld, 0x53545443, 32); // STTC - an embedded ST timecode from an avi file
|
||||
PutBits(&ld, usecPerFrame, 32);
|
||||
// microseconds per frame
|
||||
FlushBits(&ld);
|
||||
|
||||
FakeHeaderLength = (ld.Ptr - (FakeHeaders));
|
||||
|
||||
struct iovec iov[4];
|
||||
int ic = 0;
|
||||
iov[ic].iov_base = PesHeader;
|
||||
iov[ic++].iov_len = InsertPesHeader(PesHeader, packet->size, MPEG_VIDEO_PES_START_CODE, pts, FakeStartCode);
|
||||
iov[ic].iov_base = FakeHeaders;
|
||||
iov[ic++].iov_len = FakeHeaderLength;
|
||||
|
||||
if (initialHeader) {
|
||||
iov[ic].iov_base = stream->codec->extradata;
|
||||
iov[ic++].iov_len = stream->codec->extradata_size;
|
||||
|
||||
initialHeader = false;
|
||||
}
|
||||
iov[ic].iov_base = packet->data;
|
||||
iov[ic++].iov_len = packet->size;
|
||||
|
||||
return writev(fd, iov, ic) > -1;
|
||||
}
|
||||
|
||||
WriterDIVX::WriterDIVX()
|
||||
{
|
||||
Register(this, AV_CODEC_ID_MPEG4, VIDEO_ENCODING_MPEG4P2);
|
||||
Register(this, AV_CODEC_ID_MSMPEG4V1, VIDEO_ENCODING_MPEG4P2);
|
||||
Register(this, AV_CODEC_ID_MSMPEG4V2, VIDEO_ENCODING_MPEG4P2);
|
||||
Register(this, AV_CODEC_ID_MSMPEG4V3, VIDEO_ENCODING_MPEG4P2);
|
||||
}
|
||||
|
||||
static WriterDIVX writer_divx __attribute__ ((init_priority (300)));
|
82
libeplayer3/writer/dts.cpp
Normal file
82
libeplayer3/writer/dts.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/uio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
#define PES_AUDIO_PRIVATE_HEADER_SIZE 16 // consider maximum private header size.
|
||||
#define PES_AUDIO_HEADER_SIZE (32 + PES_AUDIO_PRIVATE_HEADER_SIZE)
|
||||
|
||||
class WriterDTS : public Writer
|
||||
{
|
||||
public:
|
||||
bool Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket *packet, int64_t &pts);
|
||||
WriterDTS();
|
||||
};
|
||||
|
||||
bool WriterDTS::Write(int fd, AVFormatContext * /* avfc */, AVStream * /* stream */, AVPacket *packet, int64_t &pts)
|
||||
{
|
||||
if (fd < 0 || !packet)
|
||||
return false;
|
||||
|
||||
unsigned char PesHeader[PES_AUDIO_HEADER_SIZE];
|
||||
|
||||
// #define DO_BYTESWAP
|
||||
#ifdef DO_BYTESWAP
|
||||
unsigned char Data[packet->size];
|
||||
memcpy(Data, packet->data, packet->size);
|
||||
|
||||
/* 16-bit byte swap all data before injecting it */
|
||||
for (i = 0; i < packet->size; i += 2) {
|
||||
unsigned char Tmp = Data[i];
|
||||
Data[i] = Data[i + 1];
|
||||
Data[i + 1] = Tmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct iovec iov[2];
|
||||
|
||||
iov[0].iov_base = PesHeader;
|
||||
iov[0].iov_len = InsertPesHeader(PesHeader, packet->size, MPEG_AUDIO_PES_START_CODE /*PRIVATE_STREAM_1_PES_START_CODE */ , pts, 0);
|
||||
#ifdef DO_BYTESPWAP
|
||||
iov[1].iov_base = Data;
|
||||
#else
|
||||
iov[1].iov_base = packet->data;
|
||||
#endif
|
||||
iov[1].iov_len = packet->size;
|
||||
|
||||
return writev(fd, iov, 2) > -1;
|
||||
}
|
||||
|
||||
WriterDTS::WriterDTS()
|
||||
{
|
||||
Register(this, AV_CODEC_ID_DTS, AUDIO_ENCODING_DTS);
|
||||
}
|
||||
|
||||
static WriterDTS writer_dts __attribute__ ((init_priority (300)));
|
61
libeplayer3/writer/flac.cpp
Normal file
61
libeplayer3/writer/flac.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/uio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "pes.h"
|
||||
#include "misc.h"
|
||||
#include "writer.h"
|
||||
|
||||
class WriterFLAC : public Writer
|
||||
{
|
||||
public:
|
||||
bool Write(int fd, AVFormatContext * /* avfc */, AVStream *stream, AVPacket *packet, int64_t &pts);
|
||||
WriterFLAC();
|
||||
};
|
||||
|
||||
bool WriterFLAC::Write(int fd, AVFormatContext * /* avfc */, AVStream * /* stream */, AVPacket *packet, int64_t &pts)
|
||||
{
|
||||
if (fd < 0 || !packet)
|
||||
return -1;
|
||||
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
struct iovec iov[2];
|
||||
|
||||
iov[0].iov_base = PesHeader;
|
||||
iov[0].iov_len = InsertPesHeader(PesHeader, packet->size, MPEG_AUDIO_PES_START_CODE, pts, 0);
|
||||
iov[1].iov_base = packet->data;
|
||||
iov[1].iov_len = packet->size;
|
||||
|
||||
return writev(fd, iov, 2) > -1;
|
||||
}
|
||||
|
||||
WriterFLAC::WriterFLAC()
|
||||
{
|
||||
Register(this, AV_CODEC_ID_FLAC, AUDIO_ENCODING_LPCM);
|
||||
}
|
||||
|
||||
static WriterFLAC writer_flac __attribute__ ((init_priority (300)));
|
73
libeplayer3/writer/h263.cpp
Normal file
73
libeplayer3/writer/h263.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* crow 2010
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
class WriterH263 : public Writer
|
||||
{
|
||||
public:
|
||||
bool Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket *packet, int64_t &pts);
|
||||
WriterH263();
|
||||
};
|
||||
|
||||
bool WriterH263::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];
|
||||
|
||||
int HeaderLength = InsertPesHeader(PesHeader, packet->size, H263_VIDEO_PES_START_CODE, pts, 0);
|
||||
|
||||
int PrivateHeaderLength = InsertVideoPrivateDataHeader(&PesHeader[HeaderLength], packet->size);
|
||||
|
||||
int PesLength = PesHeader[PES_LENGTH_BYTE_0] + (PesHeader[PES_LENGTH_BYTE_1] << 8) + PrivateHeaderLength;
|
||||
|
||||
PesHeader[PES_LENGTH_BYTE_0] = PesLength & 0xff;
|
||||
PesHeader[PES_LENGTH_BYTE_1] = (PesLength >> 8) & 0xff;
|
||||
PesHeader[PES_HEADER_DATA_LENGTH_BYTE] += PrivateHeaderLength;
|
||||
PesHeader[PES_FLAGS_BYTE] |= PES_EXTENSION_DATA_PRESENT;
|
||||
|
||||
HeaderLength += PrivateHeaderLength;
|
||||
|
||||
struct iovec iov[2];
|
||||
iov[0].iov_base = PesHeader;
|
||||
iov[0].iov_len = HeaderLength;
|
||||
iov[1].iov_base = packet->data;
|
||||
iov[1].iov_len = packet->size;
|
||||
return writev(fd, iov, 2) > -1;
|
||||
}
|
||||
|
||||
WriterH263::WriterH263()
|
||||
{
|
||||
Register(this, AV_CODEC_ID_H263, VIDEO_ENCODING_H263);
|
||||
Register(this, AV_CODEC_ID_H263P, VIDEO_ENCODING_H263);
|
||||
Register(this, AV_CODEC_ID_H263I, VIDEO_ENCODING_H263);
|
||||
Register(this, AV_CODEC_ID_FLV1, VIDEO_ENCODING_FLV1);
|
||||
}
|
||||
|
||||
static WriterH263 writer_h263 __attribute__ ((init_priority (300)));
|
276
libeplayer3/writer/h264.cpp
Normal file
276
libeplayer3/writer/h264.cpp
Normal file
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/uio.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
#define NALU_TYPE_PLAYER2_CONTAINER_PARAMETERS 24
|
||||
#define CONTAINER_PARAMETERS_VERSION 0x00
|
||||
|
||||
typedef struct avcC_s {
|
||||
unsigned char Version; /* configurationVersion */
|
||||
unsigned char Profile; /* AVCProfileIndication */
|
||||
unsigned char Compatibility; /* profile_compatibility */
|
||||
unsigned char Level; /* AVCLevelIndication */
|
||||
unsigned char NalLengthMinusOne; /* held in bottom two bits */
|
||||
unsigned char NumParamSets; /* held in bottom 5 bits */
|
||||
unsigned char Params[1]; /* {length,params}{length,params}...sequence then picture */
|
||||
} avcC_t;
|
||||
|
||||
const unsigned char Head[] = { 0, 0, 0, 1 };
|
||||
|
||||
class WriterH264 : public Writer
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
unsigned int TimeScale;
|
||||
int len = 0;
|
||||
int ic = 0;
|
||||
struct iovec iov[128];
|
||||
|
||||
TimeDelta = 1000.0 * av_q2d(stream->r_frame_rate); /* rational to double */
|
||||
TimeScale = (TimeDelta < 23970) ? 1001 : 1000; /* fixme: revise this */
|
||||
VideoPts = pts;
|
||||
|
||||
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 = 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 = 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 = (void *) "";
|
||||
iov[ic++].iov_len = 1;
|
||||
iov[0].iov_len =
|
||||
InsertPesHeader(PesHeader, PacketLength, MPEG_VIDEO_PES_START_CODE, pts, FakeStartCode);
|
||||
return writev(fd, iov, ic) > -1;
|
||||
}
|
||||
|
||||
if (initialHeader) {
|
||||
avcC_t *avcCHeader = (avcC_t *) stream->codec->extradata;
|
||||
unsigned int i;
|
||||
unsigned int ParamSets;
|
||||
unsigned int ParamOffset;
|
||||
unsigned int InitialHeaderLength = 0;
|
||||
unsigned int ParametersLength;
|
||||
|
||||
if (avcCHeader == NULL) {
|
||||
fprintf(stderr, "stream->codec->extradata == NULL\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (avcCHeader->Version != 1)
|
||||
fprintf(stderr, "Error unknown avcC version (%x). Expect problems.\n", avcCHeader->Version);
|
||||
|
||||
ParametersLength = 0;
|
||||
|
||||
unsigned char HeaderData[19];
|
||||
HeaderData[ParametersLength++] = 0x00; // Start code
|
||||
HeaderData[ParametersLength++] = 0x00;
|
||||
HeaderData[ParametersLength++] = 0x01;
|
||||
HeaderData[ParametersLength++] =
|
||||
NALU_TYPE_PLAYER2_CONTAINER_PARAMETERS;
|
||||
// Container message version - changes when/if we vary the format of the message
|
||||
HeaderData[ParametersLength++] = CONTAINER_PARAMETERS_VERSION;
|
||||
HeaderData[ParametersLength++] = 0xff; // Field separator
|
||||
|
||||
if (TimeDelta == 0xffffffff)
|
||||
TimeDelta = (TimeScale > 1000) ? 1001 : 1;
|
||||
|
||||
HeaderData[ParametersLength++] = (TimeScale >> 24) & 0xff; // Output the timescale
|
||||
HeaderData[ParametersLength++] = (TimeScale >> 16) & 0xff;
|
||||
HeaderData[ParametersLength++] = 0xff;
|
||||
HeaderData[ParametersLength++] = (TimeScale >> 8) & 0xff;
|
||||
HeaderData[ParametersLength++] = TimeScale & 0xff;
|
||||
HeaderData[ParametersLength++] = 0xff;
|
||||
|
||||
HeaderData[ParametersLength++] = (TimeDelta >> 24) & 0xff; // Output frame period
|
||||
HeaderData[ParametersLength++] = (TimeDelta >> 16) & 0xff;
|
||||
HeaderData[ParametersLength++] = 0xff;
|
||||
HeaderData[ParametersLength++] = (TimeDelta >> 8) & 0xff;
|
||||
HeaderData[ParametersLength++] = TimeDelta & 0xff;
|
||||
HeaderData[ParametersLength++] = 0xff;
|
||||
HeaderData[ParametersLength++] = 0x80; // Rsbp trailing bits
|
||||
|
||||
assert(ParametersLength <= sizeof(HeaderData));
|
||||
|
||||
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_base = HeaderData;
|
||||
iov[ic++].iov_len = ParametersLength;
|
||||
len = writev(fd, iov, ic);
|
||||
if (len < 0)
|
||||
return false;
|
||||
|
||||
NalLengthBytes = (avcCHeader->NalLengthMinusOne & 0x03) + 1;
|
||||
ParamSets = avcCHeader->NumParamSets & 0x1f;
|
||||
|
||||
ParamOffset = 0;
|
||||
ic = 0;
|
||||
iov[ic++].iov_base = PesHeader;
|
||||
for (i = 0; i < ParamSets; i++) {
|
||||
unsigned int PsLength =
|
||||
(avcCHeader->Params[ParamOffset] << 8) +
|
||||
avcCHeader->Params[ParamOffset + 1];
|
||||
|
||||
iov[ic].iov_base = (char *) Head;
|
||||
iov[ic++].iov_len = sizeof(Head);
|
||||
InitialHeaderLength += sizeof(Head);
|
||||
iov[ic].iov_base = &avcCHeader->Params[ParamOffset + 2];
|
||||
iov[ic++].iov_len = PsLength;
|
||||
InitialHeaderLength += PsLength;
|
||||
ParamOffset += PsLength + 2;
|
||||
}
|
||||
|
||||
ParamSets = avcCHeader->Params[ParamOffset];
|
||||
|
||||
ParamOffset++;
|
||||
for (i = 0; i < ParamSets; i++) {
|
||||
unsigned int PsLength =
|
||||
(avcCHeader->Params[ParamOffset] << 8) +
|
||||
avcCHeader->Params[ParamOffset + 1];
|
||||
|
||||
iov[ic].iov_base = (char *) Head;
|
||||
iov[ic++].iov_len = sizeof(Head);
|
||||
InitialHeaderLength += sizeof(Head);
|
||||
iov[ic].iov_base = &avcCHeader->Params[ParamOffset + 2];
|
||||
iov[ic++].iov_len = PsLength;
|
||||
InitialHeaderLength += PsLength;
|
||||
ParamOffset += PsLength + 2;
|
||||
}
|
||||
|
||||
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 false;
|
||||
len += l;
|
||||
|
||||
initialHeader = 0;
|
||||
}
|
||||
|
||||
unsigned int SampleSize = packet->size;
|
||||
unsigned int NalStart = 0;
|
||||
unsigned int VideoPosition = 0;
|
||||
|
||||
do {
|
||||
unsigned int NalLength;
|
||||
unsigned char NalData[4];
|
||||
int NalPresent = 1;
|
||||
|
||||
memcpy(NalData, packet->data + VideoPosition, NalLengthBytes);
|
||||
VideoPosition += NalLengthBytes;
|
||||
NalStart += NalLengthBytes;
|
||||
switch (NalLengthBytes) {
|
||||
case 1:
|
||||
NalLength = (NalData[0]);
|
||||
break;
|
||||
case 2:
|
||||
NalLength = (NalData[0] << 8) | (NalData[1]);
|
||||
break;
|
||||
case 3:
|
||||
NalLength = (NalData[0] << 16) | (NalData[1] << 8) | (NalData[2]);
|
||||
break;
|
||||
default:
|
||||
NalLength = (NalData[0] << 24) | (NalData[1] << 16) | (NalData[2] << 8) | (NalData[3]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (NalStart + NalLength > SampleSize) {
|
||||
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;
|
||||
ic = 0;
|
||||
iov[ic++].iov_base = PesHeader;
|
||||
|
||||
if (NalPresent) {
|
||||
NalPresent = 0;
|
||||
iov[ic].iov_base = (char *) Head;
|
||||
iov[ic++].iov_len = sizeof(Head);
|
||||
}
|
||||
|
||||
iov[ic].iov_base = packet->data + VideoPosition;
|
||||
iov[ic++].iov_len = NalLength;
|
||||
VideoPosition += NalLength;
|
||||
|
||||
iov[0].iov_len =
|
||||
InsertPesHeader(PesHeader, NalLength,
|
||||
MPEG_VIDEO_PES_START_CODE, VideoPts, 0);
|
||||
ssize_t l = writev(fd, iov, ic);
|
||||
if (l < 0)
|
||||
return false;
|
||||
len += l;
|
||||
|
||||
VideoPts = INVALID_PTS_VALUE;
|
||||
}
|
||||
} while (NalStart < SampleSize);
|
||||
|
||||
return len > -1;
|
||||
}
|
||||
|
||||
WriterH264::WriterH264()
|
||||
{
|
||||
Register(this, AV_CODEC_ID_H264, VIDEO_ENCODING_H264);
|
||||
}
|
||||
|
||||
static WriterH264 writerh264 __attribute__ ((init_priority (300)));
|
89
libeplayer3/writer/misc.cpp
Normal file
89
libeplayer3/writer/misc.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* LinuxDVB Output handling.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
void PutBits(BitPacker_t * ld, unsigned int code, unsigned int length)
|
||||
{
|
||||
unsigned int bit_buf;
|
||||
unsigned int bit_left;
|
||||
|
||||
bit_buf = ld->BitBuffer;
|
||||
bit_left = ld->Remaining;
|
||||
|
||||
#ifdef DEBUG_PUTBITS
|
||||
if (ld->debug)
|
||||
dprintf("code = %d, length = %d, bit_buf = 0x%x, bit_left = %d\n",
|
||||
code, length, bit_buf, bit_left);
|
||||
#endif /* DEBUG_PUTBITS */
|
||||
|
||||
if (length < bit_left) {
|
||||
/* fits into current buffer */
|
||||
bit_buf = (bit_buf << length) | code;
|
||||
bit_left -= length;
|
||||
} else {
|
||||
/* doesn't fit */
|
||||
bit_buf <<= bit_left;
|
||||
bit_buf |= code >> (length - bit_left);
|
||||
ld->Ptr[0] = (char) (bit_buf >> 24);
|
||||
ld->Ptr[1] = (char) (bit_buf >> 16);
|
||||
ld->Ptr[2] = (char) (bit_buf >> 8);
|
||||
ld->Ptr[3] = (char) bit_buf;
|
||||
ld->Ptr += 4;
|
||||
length -= bit_left;
|
||||
bit_buf = code & ((1 << length) - 1);
|
||||
bit_left = 32 - length;
|
||||
bit_buf = code;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PUTBITS
|
||||
if (ld->debug)
|
||||
dprintf("bit_left = %d, bit_buf = 0x%x\n", bit_left, bit_buf);
|
||||
#endif /* DEBUG_PUTBITS */
|
||||
|
||||
/* writeback */
|
||||
ld->BitBuffer = bit_buf;
|
||||
ld->Remaining = bit_left;
|
||||
}
|
||||
|
||||
void FlushBits(BitPacker_t * ld)
|
||||
{
|
||||
ld->BitBuffer <<= ld->Remaining;
|
||||
while (ld->Remaining < 32) {
|
||||
#ifdef DEBUG_PUTBITS
|
||||
if (ld->debug)
|
||||
dprintf("flushing 0x%2.2x\n", ld->BitBuffer >> 24);
|
||||
#endif /* DEBUG_PUTBITS */
|
||||
*ld->Ptr++ = ld->BitBuffer >> 24;
|
||||
ld->BitBuffer <<= 8;
|
||||
ld->Remaining += 8;
|
||||
}
|
||||
ld->Remaining = 32;
|
||||
ld->BitBuffer = 0;
|
||||
}
|
63
libeplayer3/writer/mp3.cpp
Normal file
63
libeplayer3/writer/mp3.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/uio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
class WriterMP3 : public Writer
|
||||
{
|
||||
public:
|
||||
bool Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket *packet, int64_t &pts);
|
||||
WriterMP3();
|
||||
};
|
||||
|
||||
bool WriterMP3::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];
|
||||
struct iovec iov[2];
|
||||
|
||||
iov[0].iov_base = PesHeader;
|
||||
iov[0].iov_len = InsertPesHeader(PesHeader, packet->size, MPEG_AUDIO_PES_START_CODE, pts, 0);
|
||||
iov[1].iov_base = packet->data;
|
||||
iov[1].iov_len = packet->size;
|
||||
|
||||
return writev(fd, iov, 2) > -1;
|
||||
}
|
||||
|
||||
WriterMP3::WriterMP3()
|
||||
{
|
||||
Register(this, AV_CODEC_ID_MP3, AUDIO_ENCODING_MP3);
|
||||
Register(this, AV_CODEC_ID_MP2, AUDIO_ENCODING_MPEG2);
|
||||
// Register(this, AV_CODEC_ID_VORBIS, AUDIO_ENCODING_VORBIS);
|
||||
}
|
||||
|
||||
static WriterMP3 writer_mp3 __attribute__ ((init_priority (300)));
|
75
libeplayer3/writer/mpeg2.cpp
Normal file
75
libeplayer3/writer/mpeg2.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/uio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
class WriterMPEG2 : public Writer
|
||||
{
|
||||
public:
|
||||
bool Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket *packet, int64_t &pts);
|
||||
WriterMPEG2();
|
||||
};
|
||||
|
||||
bool WriterMPEG2::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];
|
||||
|
||||
int64_t _pts = pts;
|
||||
|
||||
for (int Position = 0; Position < packet->size; ) {
|
||||
int PacketLength = std::min(packet->size - Position, MAX_PES_PACKET_SIZE);
|
||||
struct iovec iov[2];
|
||||
iov[0].iov_base = PesHeader;
|
||||
iov[0].iov_len = InsertPesHeader(PesHeader, PacketLength, 0xe0, _pts, 0);
|
||||
iov[1].iov_base = packet->data + Position;
|
||||
iov[1].iov_len = PacketLength;
|
||||
|
||||
ssize_t l = writev(fd, iov, 2);
|
||||
if (l < 0) {
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
Position += PacketLength;
|
||||
_pts = INVALID_PTS_VALUE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
WriterMPEG2::WriterMPEG2()
|
||||
{
|
||||
Register(this, AV_CODEC_ID_MPEG2TS, VIDEO_ENCODING_AUTO);
|
||||
}
|
||||
|
||||
static WriterMPEG2 writer_mpeg2 __attribute__ ((init_priority (300)));
|
371
libeplayer3/writer/pcm.cpp
Normal file
371
libeplayer3/writer/pcm.cpp
Normal file
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/uio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libavutil/avutil.h>
|
||||
#include <libavutil/time.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libswresample/swresample.h>
|
||||
#include <libavutil/opt.h>
|
||||
}
|
||||
|
||||
// reference: search for TypeLpcmDVDAudio in player/frame_parser/frame_parser_audio_lpcm.cpp
|
||||
static const unsigned char clpcm_prv[14] = {
|
||||
0xA0, //sub_stream_id
|
||||
0, 0, //resvd and UPC_EAN_ISRC stuff, unused
|
||||
0x0A, //private header length
|
||||
0, 9, //first_access_unit_pointer
|
||||
0x00, //emph,rsvd,stereo,downmix
|
||||
0x0F, //quantisation word length 1,2
|
||||
0x0F, //audio sampling freqency 1,2
|
||||
0, //resvd, multi channel type
|
||||
0, //bit shift on channel GR2, assignment
|
||||
0x80, //dynamic range control
|
||||
0, 0 //resvd for copyright management
|
||||
};
|
||||
|
||||
class WriterPCM : public Writer
|
||||
{
|
||||
private:
|
||||
unsigned int SubFrameLen;
|
||||
unsigned int SubFramesPerPES;
|
||||
unsigned char lpcm_prv[14];
|
||||
unsigned char breakBuffer[8192];
|
||||
unsigned int breakBufferFillSize;
|
||||
int uNoOfChannels;
|
||||
int uSampleRate;
|
||||
int uBitsPerSample;
|
||||
|
||||
SwrContext *swr;
|
||||
AVFrame *decoded_frame;
|
||||
int out_sample_rate;
|
||||
int out_channels;
|
||||
uint64_t out_channel_layout;
|
||||
bool initialHeader;
|
||||
bool restart_audio_resampling;
|
||||
|
||||
public:
|
||||
bool Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket *packet, int64_t &pts);
|
||||
bool prepareClipPlay();
|
||||
int writePCM(int fd, int64_t Pts, uint8_t *data, unsigned int size);
|
||||
void Init();
|
||||
WriterPCM();
|
||||
};
|
||||
|
||||
bool WriterPCM::prepareClipPlay()
|
||||
{
|
||||
SubFrameLen = 0;
|
||||
SubFramesPerPES = 0;
|
||||
breakBufferFillSize = 0;
|
||||
|
||||
memcpy(lpcm_prv, clpcm_prv, sizeof(lpcm_prv));
|
||||
|
||||
// figure out size of subframe and set up sample rate
|
||||
switch (uSampleRate) {
|
||||
case 48000:
|
||||
SubFrameLen = 40;
|
||||
break;
|
||||
case 96000:
|
||||
lpcm_prv[8] |= 0x10;
|
||||
SubFrameLen = 80;
|
||||
break;
|
||||
case 192000:
|
||||
lpcm_prv[8] |= 0x20;
|
||||
SubFrameLen = 160;
|
||||
break;
|
||||
case 44100:
|
||||
lpcm_prv[8] |= 0x80;
|
||||
SubFrameLen = 40;
|
||||
break;
|
||||
case 88200:
|
||||
lpcm_prv[8] |= 0x90;
|
||||
SubFrameLen = 80;
|
||||
break;
|
||||
case 176400:
|
||||
lpcm_prv[8] |= 0xA0;
|
||||
SubFrameLen = 160;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
SubFrameLen *= uNoOfChannels;
|
||||
SubFrameLen *= (uBitsPerSample / 8);
|
||||
|
||||
//rewrite PES size to have as many complete subframes per PES as we can
|
||||
// FIXME: PES header size was hardcoded to 18 in earlier code. Actual size returned by InsertPesHeader is 14.
|
||||
SubFramesPerPES = ((2048 - 18) - sizeof(lpcm_prv)) / SubFrameLen;
|
||||
SubFrameLen *= SubFramesPerPES;
|
||||
|
||||
//set number of channels
|
||||
lpcm_prv[10] = uNoOfChannels - 1;
|
||||
|
||||
switch (uBitsPerSample) {
|
||||
case 24:
|
||||
lpcm_prv[7] |= 0x20;
|
||||
case 16:
|
||||
break;
|
||||
default:
|
||||
printf("inappropriate bits per sample (%d) - must be 16 or 24\n", uBitsPerSample);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int WriterPCM::writePCM(int fd, int64_t Pts, uint8_t *data, unsigned int size)
|
||||
{
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
|
||||
if (initialHeader) {
|
||||
initialHeader = false;
|
||||
prepareClipPlay();
|
||||
}
|
||||
|
||||
unsigned int n;
|
||||
unsigned char *injectBuffer = (unsigned char *) malloc(SubFrameLen);
|
||||
unsigned int pos;
|
||||
|
||||
for (pos = 0; pos < size;) {
|
||||
//printf("PCM %s - Position=%d\n", __FUNCTION__, pos);
|
||||
if ((size - pos) < SubFrameLen) {
|
||||
breakBufferFillSize = size - pos;
|
||||
memcpy(breakBuffer, &data[pos],
|
||||
sizeof(unsigned char) * breakBufferFillSize);
|
||||
//printf("PCM %s - Unplayed=%d\n", __FUNCTION__, breakBufferFillSize);
|
||||
break;
|
||||
}
|
||||
//get first PES's worth
|
||||
if (breakBufferFillSize > 0) {
|
||||
memcpy(injectBuffer, breakBuffer, sizeof(unsigned char) * breakBufferFillSize);
|
||||
memcpy(&injectBuffer[breakBufferFillSize], &data[pos], sizeof(unsigned char) * (SubFrameLen - breakBufferFillSize));
|
||||
pos += (SubFrameLen - breakBufferFillSize);
|
||||
breakBufferFillSize = 0;
|
||||
} else {
|
||||
memcpy(injectBuffer, &data[pos], sizeof(unsigned char) * SubFrameLen);
|
||||
pos += SubFrameLen;
|
||||
}
|
||||
|
||||
struct iovec iov[3];
|
||||
iov[0].iov_base = PesHeader;
|
||||
iov[1].iov_base = lpcm_prv;
|
||||
iov[1].iov_len = sizeof(lpcm_prv);
|
||||
|
||||
iov[2].iov_base = injectBuffer;
|
||||
iov[2].iov_len = SubFrameLen;
|
||||
|
||||
//write the PCM data
|
||||
if (uBitsPerSample == 16) {
|
||||
for (n = 0; n < SubFrameLen; n += 2) {
|
||||
unsigned char tmp;
|
||||
tmp = injectBuffer[n];
|
||||
injectBuffer[n] = injectBuffer[n + 1];
|
||||
injectBuffer[n + 1] = tmp;
|
||||
}
|
||||
} else {
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11
|
||||
// A1c A1b A1a-B1c B1b B1a-A2c A2b A2a-B2c B2b B2a
|
||||
// to A1a A1b B1a B1b.A2a A2b B2a B2b-A1c B1c A2c B2c
|
||||
for (n = 0; n < SubFrameLen; n += 12) {
|
||||
unsigned char t, *p = &injectBuffer[n];
|
||||
t = p[0];
|
||||
p[0] = p[2];
|
||||
p[2] = p[5];
|
||||
p[5] = p[7];
|
||||
p[7] = p[11];
|
||||
p[11] = p[9];
|
||||
p[9] = p[3];
|
||||
p[3] = p[4];
|
||||
p[4] = p[8];
|
||||
p[8] = t;
|
||||
}
|
||||
}
|
||||
|
||||
//increment err... subframe count?
|
||||
lpcm_prv[1] = ((lpcm_prv[1] + SubFramesPerPES) & 0x1F);
|
||||
|
||||
iov[0].iov_len = InsertPesHeader(PesHeader, iov[1].iov_len + iov[2].iov_len, PCM_PES_START_CODE, Pts, 0);
|
||||
int len = writev(fd, iov, 3);
|
||||
if (len < 0)
|
||||
break;
|
||||
}
|
||||
free(injectBuffer);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void WriterPCM::Init()
|
||||
{
|
||||
initialHeader = true;
|
||||
restart_audio_resampling = true;
|
||||
}
|
||||
|
||||
extern int64_t calcPts(AVFormatContext *, AVStream *, int64_t);
|
||||
|
||||
bool WriterPCM::Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket *packet, int64_t &pts)
|
||||
{
|
||||
if (fd < 0)
|
||||
return false;
|
||||
|
||||
if (!packet) {
|
||||
fprintf(stderr, "%s %s %d\n", __FILE__, __func__, __LINE__);
|
||||
restart_audio_resampling = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
AVCodecContext *c = stream->codec;
|
||||
unsigned int packet_size = packet->size;
|
||||
|
||||
if (restart_audio_resampling) {
|
||||
fprintf(stderr, "%s %s %d\n", __FILE__, __func__, __LINE__);
|
||||
restart_audio_resampling = false;
|
||||
initialHeader = true;
|
||||
|
||||
if (swr) {
|
||||
swr_free(&swr);
|
||||
swr = NULL; //FIXME: Needed?
|
||||
}
|
||||
if (decoded_frame) {
|
||||
av_frame_free(&decoded_frame);
|
||||
decoded_frame = NULL; //FIXME: Needed?
|
||||
}
|
||||
|
||||
AVCodec *codec = avcodec_find_decoder(c->codec_id);
|
||||
|
||||
if (!codec || avcodec_open2(c, codec, NULL))
|
||||
fprintf(stderr, "%s %d: avcodec_open2 failed\n", __func__, __LINE__);
|
||||
}
|
||||
|
||||
while (packet_size > 0) {
|
||||
int got_frame = 0;
|
||||
if (decoded_frame)
|
||||
av_frame_unref(decoded_frame);
|
||||
else if (!(decoded_frame = av_frame_alloc())) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int len = avcodec_decode_audio4(c, decoded_frame, &got_frame, packet);
|
||||
if (len < 0) {
|
||||
fprintf(stderr, "%s %s %d\n", __FILE__, __func__, __LINE__);
|
||||
restart_audio_resampling = true;
|
||||
break;
|
||||
}
|
||||
|
||||
packet_size -= len;
|
||||
|
||||
if (!got_frame)
|
||||
continue;
|
||||
|
||||
int e;
|
||||
if (!swr) {
|
||||
int rates[] = { 48000, 96000, 192000, 44100, 88200, 176400, 0 };
|
||||
int *rate = rates;
|
||||
int in_rate = c->sample_rate;
|
||||
while (*rate && ((*rate / in_rate) * in_rate != *rate) && (in_rate / *rate) * *rate != in_rate)
|
||||
rate++;
|
||||
out_sample_rate = *rate ? *rate : 44100;
|
||||
swr = swr_alloc();
|
||||
out_channels = c->channels;
|
||||
if (c->channel_layout == 0) {
|
||||
// FIXME -- need to guess, looks pretty much like a bug in the FFMPEG WMA decoder
|
||||
c->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
}
|
||||
|
||||
out_channel_layout = c->channel_layout;
|
||||
// player2 won't play mono
|
||||
if (out_channel_layout == AV_CH_LAYOUT_MONO) {
|
||||
out_channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
out_channels = 2;
|
||||
}
|
||||
|
||||
av_opt_set_int(swr, "in_channel_layout", c->channel_layout, 0);
|
||||
av_opt_set_int(swr, "out_channel_layout", out_channel_layout, 0);
|
||||
av_opt_set_int(swr, "in_sample_rate", c->sample_rate, 0);
|
||||
av_opt_set_int(swr, "out_sample_rate", out_sample_rate, 0);
|
||||
av_opt_set_int(swr, "in_sample_fmt", c->sample_fmt, 0);
|
||||
av_opt_set_int(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
|
||||
|
||||
e = swr_init(swr);
|
||||
if (e < 0) {
|
||||
fprintf(stderr,
|
||||
"swr_init: %d (icl=%d ocl=%d isr=%d osr=%d isf=%d osf=%d\n",
|
||||
-e, (int) c->channel_layout,
|
||||
(int) out_channel_layout, c->sample_rate, out_sample_rate, c->sample_fmt, AV_SAMPLE_FMT_S16);
|
||||
swr_free(&swr);
|
||||
swr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *output = NULL;
|
||||
int in_samples = decoded_frame->nb_samples;
|
||||
int out_samples = av_rescale_rnd(swr_get_delay(swr, c->sample_rate) + in_samples, out_sample_rate, c->sample_rate, AV_ROUND_UP);
|
||||
e = av_samples_alloc(&output, NULL, out_channels, out_samples, AV_SAMPLE_FMT_S16, 1);
|
||||
if (e < 0) {
|
||||
fprintf(stderr, "av_samples_alloc: %d\n", -e);
|
||||
continue;
|
||||
}
|
||||
// FIXME. PTS calculation is probably broken.
|
||||
int64_t pts;
|
||||
int64_t next_in_pts = av_rescale(av_frame_get_best_effort_timestamp(decoded_frame),
|
||||
stream->time_base.num * (int64_t) out_sample_rate * c->sample_rate,
|
||||
stream->time_base.den);
|
||||
int64_t next_out_pts = av_rescale(swr_next_pts(swr, next_in_pts),
|
||||
stream->time_base.den,
|
||||
stream->time_base.num * (int64_t) out_sample_rate * c->sample_rate);
|
||||
pts = calcPts(avfc, stream, next_out_pts);
|
||||
out_samples = swr_convert(swr, &output, out_samples, (const uint8_t **) &decoded_frame->data[0], in_samples);
|
||||
|
||||
uSampleRate = out_sample_rate;
|
||||
uNoOfChannels = av_get_channel_layout_nb_channels(out_channel_layout);
|
||||
uBitsPerSample = 16;
|
||||
|
||||
writePCM(fd, pts, output, out_samples * sizeof(short) * out_channels);
|
||||
|
||||
av_freep(&output);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
WriterPCM::WriterPCM()
|
||||
{
|
||||
swr = NULL;
|
||||
decoded_frame = NULL;
|
||||
out_sample_rate = 44100;
|
||||
out_channels = 2;
|
||||
out_channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
restart_audio_resampling = true;
|
||||
|
||||
Register(this, AV_CODEC_ID_PCM_S16LE/*FIXME*/, AUDIO_ENCODING_LPCMA);
|
||||
}
|
||||
|
||||
static WriterPCM writer_pcm __attribute__ ((init_priority (300)));
|
154
libeplayer3/writer/pes.cpp
Normal file
154
libeplayer3/writer/pes.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
/* ***************************** */
|
||||
/* 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 <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 "player.h"
|
||||
#include "output.h"
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Functions */
|
||||
/* ***************************** */
|
||||
|
||||
int InsertVideoPrivateDataHeader(unsigned char *data, int payload_size)
|
||||
{
|
||||
BitPacker_t ld2 = { data, 0, 32 };
|
||||
int i;
|
||||
|
||||
PutBits(&ld2, PES_PRIVATE_DATA_FLAG, 8);
|
||||
PutBits(&ld2, payload_size & 0xff, 8);
|
||||
PutBits(&ld2, (payload_size >> 8) & 0xff, 8);
|
||||
PutBits(&ld2, (payload_size >> 16) & 0xff, 8);
|
||||
|
||||
for (i = 4; i < (PES_PRIVATE_DATA_LENGTH + 1); i++)
|
||||
PutBits(&ld2, 0, 8);
|
||||
|
||||
FlushBits(&ld2);
|
||||
|
||||
return PES_PRIVATE_DATA_LENGTH + 1;
|
||||
|
||||
}
|
||||
|
||||
int InsertPesHeader(unsigned char *data, int size, unsigned char stream_id,
|
||||
unsigned long long int pts, int pic_start_code)
|
||||
{
|
||||
BitPacker_t ld2 = { data, 0, 32 };
|
||||
|
||||
if (size > MAX_PES_PACKET_SIZE)
|
||||
size = 0; // unbounded
|
||||
|
||||
PutBits(&ld2, 0x0, 8);
|
||||
PutBits(&ld2, 0x0, 8);
|
||||
PutBits(&ld2, 0x1, 8); // Start Code
|
||||
PutBits(&ld2, stream_id, 8); // Stream_id = Audio Stream
|
||||
//4
|
||||
PutBits(&ld2, size + 3 + (pts != INVALID_PTS_VALUE ? 5 : 0) + (pic_start_code ? (5) : 0), 16); // PES_packet_length
|
||||
//6 = 4+2
|
||||
PutBits(&ld2, 0x2, 2); // 10
|
||||
PutBits(&ld2, 0x0, 2); // PES_Scrambling_control
|
||||
PutBits(&ld2, 0x0, 1); // PES_Priority
|
||||
PutBits(&ld2, 0x0, 1); // data_alignment_indicator
|
||||
PutBits(&ld2, 0x0, 1); // Copyright
|
||||
PutBits(&ld2, 0x0, 1); // Original or Copy
|
||||
//7 = 6+1
|
||||
|
||||
if (pts != INVALID_PTS_VALUE)
|
||||
PutBits(&ld2, 0x2, 2);
|
||||
else
|
||||
PutBits(&ld2, 0x0, 2); // PTS_DTS flag
|
||||
|
||||
PutBits(&ld2, 0x0, 1); // ESCR_flag
|
||||
PutBits(&ld2, 0x0, 1); // ES_rate_flag
|
||||
PutBits(&ld2, 0x0, 1); // DSM_trick_mode_flag
|
||||
PutBits(&ld2, 0x0, 1); // additional_copy_ingo_flag
|
||||
PutBits(&ld2, 0x0, 1); // PES_CRC_flag
|
||||
PutBits(&ld2, 0x0, 1); // PES_extension_flag
|
||||
//8 = 7+1
|
||||
|
||||
if (pts != INVALID_PTS_VALUE)
|
||||
PutBits(&ld2, 0x5, 8);
|
||||
else
|
||||
PutBits(&ld2, 0x0, 8); // PES_header_data_length
|
||||
//9 = 8+1
|
||||
|
||||
if (pts != INVALID_PTS_VALUE) {
|
||||
PutBits(&ld2, 0x2, 4);
|
||||
PutBits(&ld2, (pts >> 30) & 0x7, 3);
|
||||
PutBits(&ld2, 0x1, 1);
|
||||
PutBits(&ld2, (pts >> 15) & 0x7fff, 15);
|
||||
PutBits(&ld2, 0x1, 1);
|
||||
PutBits(&ld2, pts & 0x7fff, 15);
|
||||
PutBits(&ld2, 0x1, 1);
|
||||
}
|
||||
//14 = 9+5
|
||||
|
||||
if (pic_start_code) {
|
||||
PutBits(&ld2, 0x0, 8);
|
||||
PutBits(&ld2, 0x0, 8);
|
||||
PutBits(&ld2, 0x1, 8); // Start Code
|
||||
PutBits(&ld2, pic_start_code & 0xff, 8); // 00, for picture start
|
||||
PutBits(&ld2, (pic_start_code >> 8) & 0xff, 8); // For any extra information (like in mpeg4p2, the pic_start_code)
|
||||
//14 + 4 = 18
|
||||
}
|
||||
|
||||
FlushBits(&ld2);
|
||||
|
||||
return (ld2.Ptr - data);
|
||||
|
||||
}
|
187
libeplayer3/writer/vc1.cpp
Normal file
187
libeplayer3/writer/vc1.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/uio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
#define WMV3_PRIVATE_DATA_LENGTH 4
|
||||
|
||||
#define METADATA_STRUCT_A_START 12
|
||||
#define METADATA_STRUCT_B_START 24
|
||||
#define METADATA_STRUCT_B_FRAMERATE_START 32
|
||||
#define METADATA_STRUCT_C_START 8
|
||||
|
||||
|
||||
#define VC1_SEQUENCE_LAYER_METADATA_START_CODE 0x80
|
||||
#define VC1_FRAME_START_CODE 0x0d
|
||||
|
||||
class WriterVC1 : public Writer
|
||||
{
|
||||
private:
|
||||
bool initialHeader;
|
||||
unsigned char FrameHeaderSeen;
|
||||
double frameRate;
|
||||
public:
|
||||
bool Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket *packet, int64_t &pts);
|
||||
void Init();
|
||||
WriterVC1();
|
||||
};
|
||||
|
||||
void WriterVC1::Init()
|
||||
{
|
||||
initialHeader = true;
|
||||
}
|
||||
|
||||
bool WriterVC1::Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket *packet, int64_t &pts)
|
||||
{
|
||||
if (fd < 0 || !packet)
|
||||
return false;
|
||||
|
||||
if (initialHeader) {
|
||||
initialHeader = false;
|
||||
FrameHeaderSeen = false;
|
||||
|
||||
const unsigned char SequenceLayerStartCode[] =
|
||||
{ 0x00, 0x00, 0x01, VC1_SEQUENCE_LAYER_METADATA_START_CODE };
|
||||
|
||||
|
||||
const unsigned char Metadata[] = {
|
||||
0x00, 0x00, 0x00, 0xc5,
|
||||
0x04, 0x00, 0x00, 0x00,
|
||||
0xc0, 0x00, 0x00, 0x00, /* Struct C set for for advanced profile */
|
||||
0x00, 0x00, 0x00, 0x00, /* Struct A */
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x0c, 0x00, 0x00, 0x00,
|
||||
0x60, 0x00, 0x00, 0x00, /* Struct B */
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
unsigned char PesPayload[128];
|
||||
unsigned char *PesPtr;
|
||||
unsigned int usecPerFrame = ((10000000.0 / av_q2d(stream->r_frame_rate)));
|
||||
struct iovec iov[2];
|
||||
|
||||
|
||||
memset(PesPayload, 0, sizeof(PesPayload));
|
||||
|
||||
PesPtr = PesPayload;
|
||||
|
||||
memcpy(PesPtr, SequenceLayerStartCode, sizeof(SequenceLayerStartCode));
|
||||
PesPtr += sizeof(SequenceLayerStartCode);
|
||||
|
||||
memcpy(PesPtr, Metadata, sizeof(Metadata));
|
||||
PesPtr += METADATA_STRUCT_C_START;
|
||||
PesPtr += WMV3_PRIVATE_DATA_LENGTH;
|
||||
|
||||
/* Metadata Header Struct A */
|
||||
*PesPtr++ = (stream->codec->height >> 0) & 0xff;
|
||||
*PesPtr++ = (stream->codec->height >> 8) & 0xff;
|
||||
*PesPtr++ = (stream->codec->height >> 16) & 0xff;
|
||||
*PesPtr++ = stream->codec->height >> 24;
|
||||
*PesPtr++ = (stream->codec->width >> 0) & 0xff;
|
||||
*PesPtr++ = (stream->codec->width >> 8) & 0xff;
|
||||
*PesPtr++ = (stream->codec->width >> 16) & 0xff;
|
||||
*PesPtr++ = stream->codec->width >> 24;
|
||||
|
||||
PesPtr += 12; /* Skip flag word and Struct B first 8 bytes */
|
||||
|
||||
*PesPtr++ = (usecPerFrame >> 0) & 0xff;
|
||||
*PesPtr++ = (usecPerFrame >> 8) & 0xff;
|
||||
*PesPtr++ = (usecPerFrame >> 16) & 0xff;
|
||||
*PesPtr++ = usecPerFrame >> 24;
|
||||
|
||||
iov[0].iov_base = PesHeader;
|
||||
iov[1].iov_base = PesPayload;
|
||||
iov[1].iov_len = PesPtr - PesPayload;
|
||||
iov[0].iov_len = InsertPesHeader(PesHeader, iov[1].iov_len, VC1_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0);
|
||||
if (writev(fd, iov, 2) < 0)
|
||||
return false;
|
||||
|
||||
/* For VC1 the codec private data is a standard vc1 sequence header so we just copy it to the output */
|
||||
iov[0].iov_base = PesHeader;
|
||||
iov[1].iov_base = stream->codec->extradata;
|
||||
iov[1].iov_len = stream->codec->extradata_size;
|
||||
iov[0].iov_len = InsertPesHeader(PesHeader, iov[1].iov_len, VC1_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0);
|
||||
if (writev(fd, iov, 2) < 0)
|
||||
return false;
|
||||
|
||||
initialHeader = false;
|
||||
}
|
||||
|
||||
int64_t _pts = pts;
|
||||
|
||||
if (packet->size > 0) {
|
||||
int Position = 0;
|
||||
unsigned char insertSampleHeader = 1;
|
||||
|
||||
while (Position < packet->size) {
|
||||
int PacketLength = std::min(packet->size - Position, MAX_PES_PACKET_SIZE);
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
int HeaderLength = InsertPesHeader(PesHeader, PacketLength, VC1_VIDEO_PES_START_CODE, _pts, 0);
|
||||
|
||||
if (insertSampleHeader) {
|
||||
const unsigned char Vc1FrameStartCode[] = { 0, 0, 1, VC1_FRAME_START_CODE };
|
||||
|
||||
if (!FrameHeaderSeen && (packet->size > 3) && (memcmp(packet->data, Vc1FrameStartCode, 4) == 0))
|
||||
FrameHeaderSeen = true;
|
||||
if (!FrameHeaderSeen) {
|
||||
memcpy(&PesHeader[HeaderLength], Vc1FrameStartCode, sizeof(Vc1FrameStartCode));
|
||||
HeaderLength += sizeof(Vc1FrameStartCode);
|
||||
}
|
||||
insertSampleHeader = 0;
|
||||
}
|
||||
|
||||
struct iovec iov[2];
|
||||
iov[0].iov_base = PesHeader;
|
||||
iov[0].iov_len = HeaderLength;
|
||||
iov[1].iov_base = packet->data + Position;
|
||||
iov[1].iov_len = PacketLength;
|
||||
|
||||
ssize_t l = writev(fd, iov, 2);
|
||||
if (l < 0)
|
||||
return false;
|
||||
|
||||
Position += PacketLength;
|
||||
_pts = INVALID_PTS_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
WriterVC1::WriterVC1()
|
||||
{
|
||||
Register(this, AV_CODEC_ID_VC1, VIDEO_ENCODING_VC1);
|
||||
}
|
||||
|
||||
static WriterVC1 writer_vc1 __attribute__ ((init_priority (300)));
|
169
libeplayer3/writer/wmv.cpp
Normal file
169
libeplayer3/writer/wmv.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/uio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define WMV3_PRIVATE_DATA_LENGTH 4
|
||||
|
||||
static const unsigned char Metadata[] = {
|
||||
0x00, 0x00, 0x00, 0xc5,
|
||||
0x04, 0x00, 0x00, 0x00,
|
||||
#define METADATA_STRUCT_C_START 8
|
||||
0xc0, 0x00, 0x00, 0x00, /* Struct C set for for advanced profile */
|
||||
#define METADATA_STRUCT_A_START 12
|
||||
0x00, 0x00, 0x00, 0x00, /* Struct A */
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x0c, 0x00, 0x00, 0x00,
|
||||
#define METADATA_STRUCT_B_START 24
|
||||
0x60, 0x00, 0x00, 0x00, /* Struct B */
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
#define METADATA_STRUCT_B_FRAMERATE_START 32
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
class WriterWMV : public Writer
|
||||
{
|
||||
private:
|
||||
bool initialHeader;
|
||||
public:
|
||||
bool Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket *packet, int64_t &pts);
|
||||
void Init();
|
||||
WriterWMV();
|
||||
};
|
||||
|
||||
void WriterWMV::Init()
|
||||
{
|
||||
initialHeader = 1;
|
||||
}
|
||||
|
||||
bool WriterWMV::Write(int fd, AVFormatContext * /* avfc */, AVStream *stream, AVPacket *packet, int64_t &pts)
|
||||
{
|
||||
if (fd < 0 || !packet)
|
||||
return false;
|
||||
|
||||
if (initialHeader) {
|
||||
#define PES_MIN_HEADER_SIZE 9
|
||||
unsigned char PesPacket[PES_MIN_HEADER_SIZE + 128];
|
||||
unsigned char *PesPtr;
|
||||
unsigned int MetadataLength;
|
||||
unsigned int usecPerFrame = ((10000000.0 / av_q2d(stream->r_frame_rate)));
|
||||
|
||||
PesPtr = &PesPacket[PES_MIN_HEADER_SIZE];
|
||||
|
||||
memcpy(PesPtr, Metadata, sizeof(Metadata));
|
||||
PesPtr += METADATA_STRUCT_C_START;
|
||||
|
||||
unsigned char privateData[WMV3_PRIVATE_DATA_LENGTH] = { 0 };
|
||||
memcpy(privateData, stream->codec->extradata, stream->codec->extradata_size > WMV3_PRIVATE_DATA_LENGTH ? WMV3_PRIVATE_DATA_LENGTH : stream->codec->extradata_size);
|
||||
|
||||
memcpy(PesPtr, privateData, WMV3_PRIVATE_DATA_LENGTH);
|
||||
PesPtr += WMV3_PRIVATE_DATA_LENGTH;
|
||||
|
||||
/* Metadata Header Struct A */
|
||||
*PesPtr++ = (stream->codec->height >> 0) & 0xff;
|
||||
*PesPtr++ = (stream->codec->height >> 8) & 0xff;
|
||||
*PesPtr++ = (stream->codec->height >> 16) & 0xff;
|
||||
*PesPtr++ = stream->codec->height >> 24;
|
||||
*PesPtr++ = (stream->codec->width >> 0) & 0xff;
|
||||
*PesPtr++ = (stream->codec->width >> 8) & 0xff;
|
||||
*PesPtr++ = (stream->codec->width >> 16) & 0xff;
|
||||
*PesPtr++ = stream->codec->width >> 24;
|
||||
|
||||
PesPtr += 12; /* Skip flag word and Struct B first 8 bytes */
|
||||
|
||||
*PesPtr++ = (usecPerFrame >> 0) & 0xff;
|
||||
*PesPtr++ = (usecPerFrame >> 8) & 0xff;
|
||||
*PesPtr++ = (usecPerFrame >> 16) & 0xff;
|
||||
*PesPtr++ = usecPerFrame >> 24;
|
||||
|
||||
MetadataLength = PesPtr - &PesPacket[PES_MIN_HEADER_SIZE];
|
||||
|
||||
int HeaderLength = InsertPesHeader(PesPacket, MetadataLength, VC1_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0);
|
||||
|
||||
if (write(fd, PesPacket, HeaderLength + MetadataLength) < 0)
|
||||
return false;
|
||||
|
||||
initialHeader = false;
|
||||
}
|
||||
|
||||
if (packet->size > 0 && packet->data) {
|
||||
int Position = 0;
|
||||
bool insertSampleHeader = true;
|
||||
|
||||
uint64_t _pts = pts;
|
||||
|
||||
while (Position < packet->size) {
|
||||
|
||||
int PacketLength = std::min(packet->size - Position, MAX_PES_PACKET_SIZE);
|
||||
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE] = { 0 };
|
||||
int HeaderLength = InsertPesHeader(PesHeader, PacketLength, VC1_VIDEO_PES_START_CODE, _pts, 0);
|
||||
|
||||
if (insertSampleHeader) {
|
||||
unsigned int PesLength;
|
||||
unsigned int PrivateHeaderLength;
|
||||
|
||||
PrivateHeaderLength = InsertVideoPrivateDataHeader(&PesHeader[HeaderLength], packet->size);
|
||||
/* Update PesLength */
|
||||
PesLength = PesHeader[PES_LENGTH_BYTE_0] + (PesHeader[PES_LENGTH_BYTE_1] << 8) + PrivateHeaderLength;
|
||||
PesHeader[PES_LENGTH_BYTE_0] = PesLength & 0xff;
|
||||
PesHeader[PES_LENGTH_BYTE_1] = (PesLength >> 8) & 0xff;
|
||||
PesHeader[PES_HEADER_DATA_LENGTH_BYTE] += PrivateHeaderLength;
|
||||
PesHeader[PES_FLAGS_BYTE] |= PES_EXTENSION_DATA_PRESENT;
|
||||
|
||||
HeaderLength += PrivateHeaderLength;
|
||||
insertSampleHeader = false;
|
||||
}
|
||||
|
||||
uint8_t PacketStart[packet->size + HeaderLength];
|
||||
memcpy(PacketStart, PesHeader, HeaderLength);
|
||||
memcpy(PacketStart + HeaderLength, packet->data + Position, PacketLength);
|
||||
if (write(fd, PacketStart, PacketLength + HeaderLength) < 0)
|
||||
return false;
|
||||
|
||||
Position += PacketLength;
|
||||
_pts = INVALID_PTS_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
WriterWMV::WriterWMV()
|
||||
{
|
||||
Register(this, AV_CODEC_ID_WMV1, VIDEO_ENCODING_WMV);
|
||||
Register(this, AV_CODEC_ID_WMV2, VIDEO_ENCODING_WMV);
|
||||
Register(this, AV_CODEC_ID_WMV3, VIDEO_ENCODING_WMV);
|
||||
}
|
||||
|
||||
static WriterWMV writer_wmv __attribute__ ((init_priority (300)));
|
115
libeplayer3/writer/writer.cpp
Normal file
115
libeplayer3/writer/writer.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#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 <sys/uio.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
// This does suck ... the original idea was to just link the object files and let them register themselves.
|
||||
// Alas, that didn't work as expected.
|
||||
|
||||
#include "divx.cpp"
|
||||
#include "h263.cpp"
|
||||
#include "h264.cpp"
|
||||
#include "mp3.cpp"
|
||||
#include "vc1.cpp"
|
||||
#include "wmv.cpp"
|
||||
#include "ac3.cpp"
|
||||
#include "dts.cpp"
|
||||
#include "flac.cpp"
|
||||
#include "mpeg2.cpp"
|
||||
#include "pcm.cpp"
|
||||
|
||||
static std::map<enum AVCodecID,Writer *>writers __attribute__ ((init_priority (200)));
|
||||
static std::map<enum AVCodecID,video_encoding_t>vencoding __attribute__ ((init_priority (200)));
|
||||
static std::map<enum AVCodecID,audio_encoding_t>aencoding __attribute__ ((init_priority (200)));
|
||||
|
||||
void Writer::Register(Writer *w, enum AVCodecID id, video_encoding_t encoding)
|
||||
{
|
||||
writers[id] = w;
|
||||
vencoding[id] = encoding;
|
||||
}
|
||||
|
||||
void Writer::Register(Writer *w, enum AVCodecID id, audio_encoding_t encoding)
|
||||
{
|
||||
writers[id] = w;
|
||||
aencoding[id] = encoding;
|
||||
}
|
||||
|
||||
bool Writer::Write(int /* fd */, AVFormatContext * /* avfc */, AVStream * /*stream*/, AVPacket * /* packet */, int64_t & /* pts */)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static Writer writer __attribute__ ((init_priority (300)));
|
||||
|
||||
Writer *Writer::GetWriter(enum AVCodecID id, enum AVMediaType codec_type)
|
||||
{
|
||||
fprintf(stderr, "%s %s %d\n", __FILE__,__func__,__LINE__);
|
||||
std::map<enum AVCodecID,Writer*>::iterator it = writers.find(id);
|
||||
if (it != writers.end())
|
||||
return it->second;
|
||||
fprintf(stderr, "%s %s %d: no writer found\n", __FILE__,__func__,__LINE__);
|
||||
switch (codec_type) {
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
if (id == AV_CODEC_ID_INJECTPCM) // should not happen
|
||||
break;
|
||||
fprintf(stderr, "%s %s %d: returning injectpcm\n", __FILE__,__func__,__LINE__);
|
||||
return GetWriter(AV_CODEC_ID_INJECTPCM, codec_type);
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
if (id == AV_CODEC_ID_MPEG2TS) // should not happen
|
||||
break;
|
||||
fprintf(stderr, "%s %s %d: returning mpeg2video\n", __FILE__,__func__,__LINE__);
|
||||
return GetWriter(AV_CODEC_ID_MPEG2TS, codec_type);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "%s %s %d: returning dummy writer\n", __FILE__,__func__,__LINE__);
|
||||
return &writer;
|
||||
}
|
||||
|
||||
video_encoding_t Writer::GetVideoEncoding(enum AVCodecID id)
|
||||
{
|
||||
std::map<enum AVCodecID,video_encoding_t>::iterator it = vencoding.find(id);
|
||||
if (it != vencoding.end())
|
||||
return it->second;
|
||||
return VIDEO_ENCODING_AUTO;
|
||||
}
|
||||
|
||||
audio_encoding_t Writer::GetAudioEncoding(enum AVCodecID id)
|
||||
{
|
||||
std::map<enum AVCodecID,audio_encoding_t>::iterator it = aencoding.find(id);
|
||||
if (it != aencoding.end())
|
||||
return it->second;
|
||||
return AUDIO_ENCODING_LPCMA;
|
||||
}
|
Reference in New Issue
Block a user