libeplayer3: cleanups

This commit is contained in:
martii
2014-04-07 23:00:03 +02:00
parent 5448fb35bf
commit fcd1dc8399
19 changed files with 1080 additions and 1212 deletions

View File

@@ -8,13 +8,10 @@ AM_CPPFLAGS += -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
AM_CPPFLAGS += -ggdb
libeplayer3_la_SOURCES = \
container/container_ffmpeg.cpp \
manager/manager.cpp output/output.cpp \
playback/playback.cpp output/writer/writer.cpp output/writer/wmv.cpp \
output/writer/ac3.cpp output/writer/divx.cpp output/writer/pes.cpp \
output/writer/dts.cpp output/writer/mpeg2.cpp output/writer/mp3.cpp output/writer/misc.cpp \
output/writer/h264.cpp output/writer/h263.cpp output/writer/vc1.cpp \
output/writer/flac.cpp output/writer/pcm.cpp
input.cpp output.cpp manager.cpp player.cpp \
writer/writer.cpp writer/wmv.cpp writer/ac3.cpp writer/divx.cpp writer/pes.cpp \
writer/dts.cpp writer/mpeg2.cpp writer/mp3.cpp writer/misc.cpp writer/h264.cpp \
writer/h263.cpp writer/vc1.cpp writer/flac.cpp writer/pcm.cpp
LIBEPLAYER3_LIBS = libeplayer3.la -lpthread -lavformat -lavcodec -lavutil -lswresample -lm

View File

@@ -58,7 +58,6 @@ class Input
bool SwitchVideo(Track *track);
bool GetMetadata(std::vector<std::string> &keys, std::vector<std::string> &values);
bool GetReadCount(uint64_t &readcount);
};
#endif

View File

@@ -26,9 +26,9 @@ extern "C" {
struct Chapter
{
std::string title;
double start;
double end;
std::string title;
double start;
double end;
};
class Player {

View File

@@ -1,5 +1,5 @@
#ifndef WRITER_H_
#define WRITER_H_
#ifndef __WRITER_H__
#define __WRITER_H__
#include <stdio.h>
#include <stdint.h>

View File

@@ -19,10 +19,6 @@
*
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@@ -65,22 +61,22 @@ Input::~Input()
int64_t calcPts(AVFormatContext *avfc, AVStream * stream, int64_t pts)
{
if (!avfc || !stream) {
fprintf(stderr, "player / stream null\n");
return INVALID_PTS_VALUE;
}
if (!avfc || !stream) {
fprintf(stderr, "player / stream null\n");
return INVALID_PTS_VALUE;
}
if (pts == AV_NOPTS_VALUE)
pts = INVALID_PTS_VALUE;
else if (avfc->start_time == AV_NOPTS_VALUE)
pts = 90000.0 * (double) pts * av_q2d(stream->time_base);
else
pts = 90000.0 * (double) pts * av_q2d(stream->time_base) - 90000.0 * avfc->start_time / AV_TIME_BASE;
if (pts == AV_NOPTS_VALUE)
pts = INVALID_PTS_VALUE;
else if (avfc->start_time == AV_NOPTS_VALUE)
pts = 90000.0 * (double) pts * av_q2d(stream->time_base);
else
pts = 90000.0 * (double) pts * av_q2d(stream->time_base) - 90000.0 * avfc->start_time / AV_TIME_BASE;
if (pts & 0x8000000000000000ull)
pts = INVALID_PTS_VALUE;
if (pts & 0x8000000000000000ull)
pts = INVALID_PTS_VALUE;
return pts;
return pts;
}
// from neutrino-mp/lib/libdvbsubtitle/dvbsub.cpp
@@ -92,200 +88,194 @@ extern "C" void teletext_write(int pid, uint8_t *data, int size);
bool Input::Play()
{
char threadname[17];
strncpy(threadname, __func__, sizeof(threadname));
threadname[16] = 0;
prctl(PR_SET_NAME, (unsigned long) &threadname);
char threadname[17];
strncpy(threadname, __func__, sizeof(threadname));
threadname[16] = 0;
prctl(PR_SET_NAME, (unsigned long) &threadname);
hasPlayThreadStarted = 1;
hasPlayThreadStarted = 1;
int64_t currentVideoPts = 0, currentAudioPts = 0, showtime = 0, bofcount = 0;
int64_t currentVideoPts = 0, currentAudioPts = 0, showtime = 0, bofcount = 0;
bool restart_audio_resampling = false;
while (player->isCreationPhase) {
fprintf(stderr, "Thread waiting for end of init phase...\n");
usleep(1000);
}
fprintf(stderr, "Running!\n");
bool restart_audio_resampling = false;
while (player->isPlaying && !player->abortRequested) {
//IF MOVIE IS PAUSED, WAIT
if (player->isPaused) {
fprintf(stderr, "paused\n");
usleep(100000);
continue;
while (player->isCreationPhase) {
fprintf(stderr, "Thread waiting for end of init phase...\n");
usleep(1000);
}
fprintf(stderr, "Running!\n");
int seek_target_flag = 0;
int64_t seek_target = INT64_MIN;
if (seek_sec_rel != 0.0) {
if (avfc->iformat->flags & AVFMT_TS_DISCONT) {
float br = (avfc->bit_rate) ? avfc->bit_rate / 8.0 : 180000.0;
seek_target_flag = AVSEEK_FLAG_BYTE;
seek_target = avio_tell(avfc->pb) + seek_sec_rel * br;
} else {
seek_target = ((((currentVideoPts > 0) ? currentVideoPts : currentAudioPts) / 90000.0) + seek_sec_rel) * AV_TIME_BASE;
}
seek_sec_rel = 0.0;
} else if (seek_sec_abs >= 0.0) {
if (avfc->iformat->flags & AVFMT_TS_DISCONT) {
float br = (avfc->bit_rate) ? avfc->bit_rate / 8.0 : 180000.0;
seek_target_flag = AVSEEK_FLAG_BYTE;
seek_target = seek_sec_abs * br;
} else {
seek_target = seek_sec_abs * AV_TIME_BASE;
}
seek_sec_abs = -1.0;
} else if (player->isBackWard && av_gettime() >= showtime) {
player->output.ClearVideo();
while (player->isPlaying && !player->abortRequested) {
if (bofcount == 1) {
showtime = av_gettime();
usleep(100000);
continue;
}
if (avfc->iformat->flags & AVFMT_TS_DISCONT) {
off_t pos = avio_tell(avfc->pb);
if (pos > 0) {
float br;
if (avfc->bit_rate)
br = avfc->bit_rate / 8.0;
else
br = 180000.0;
seek_target = pos + player->Speed * 8 * br;
seek_target_flag = AVSEEK_FLAG_BYTE;
//IF MOVIE IS PAUSED, WAIT
if (player->isPaused) {
fprintf(stderr, "paused\n");
usleep(100000);
continue;
}
} else {
seek_target = ((((currentVideoPts > 0) ? currentVideoPts : currentAudioPts) / 90000.0) + player->Speed * 8) * AV_TIME_BASE;;
}
showtime = av_gettime() + 300000; //jump back every 300ms
} else {
bofcount = 0;
}
if (seek_target > INT64_MIN) {
int res;
if (seek_target < 0)
seek_target = 0;
res = avformat_seek_file(avfc, -1, INT64_MIN, seek_target, INT64_MAX, seek_target_flag);
int seek_target_flag = 0;
int64_t seek_target = INT64_MIN;
if (res < 0 && player->isBackWard)
bofcount = 1;
seek_target = INT64_MIN;
restart_audio_resampling = true;
if (seek_sec_rel != 0.0) {
if (avfc->iformat->flags & AVFMT_TS_DISCONT) {
float br = (avfc->bit_rate) ? avfc->bit_rate / 8.0 : 180000.0;
seek_target_flag = AVSEEK_FLAG_BYTE;
seek_target = avio_tell(avfc->pb) + seek_sec_rel * br;
} else {
seek_target = ((((currentVideoPts > 0) ? currentVideoPts : currentAudioPts) / 90000.0) + seek_sec_rel) * AV_TIME_BASE;
}
seek_sec_rel = 0.0;
} else if (seek_sec_abs >= 0.0) {
if (avfc->iformat->flags & AVFMT_TS_DISCONT) {
float br = (avfc->bit_rate) ? avfc->bit_rate / 8.0 : 180000.0;
seek_target_flag = AVSEEK_FLAG_BYTE;
seek_target = seek_sec_abs * br;
} else {
seek_target = seek_sec_abs * AV_TIME_BASE;
}
seek_sec_abs = -1.0;
} else if (player->isBackWard && av_gettime() >= showtime) {
player->output.ClearVideo();
// flush streams
unsigned int i;
for (i = 0; i < avfc->nb_streams; i++)
if (avfc->streams[i]->codec && avfc->streams[i]->codec->codec)
avcodec_flush_buffers(avfc->streams[i]->codec);
}
if (bofcount == 1) {
showtime = av_gettime();
usleep(100000);
continue;
}
AVPacket packet;
av_init_packet(&packet);
if (avfc->iformat->flags & AVFMT_TS_DISCONT) {
off_t pos = avio_tell(avfc->pb);
int av_res = av_read_frame(avfc, &packet);
if (av_res == AVERROR(EAGAIN)) {
av_free_packet(&packet);
continue;
}
if (av_res) { // av_read_frame failed
fprintf(stderr, "no data ->end of file reached ?\n");
av_free_packet(&packet);
break; // while
}
long long int pts;
player->readCount += packet.size;
int pid = avfc->streams[packet.stream_index]->id;
Track *_videoTrack = videoTrack;
Track *_audioTrack = audioTrack;
Track *_subtitleTrack = subtitleTrack;
Track *_teletextTrack = teletextTrack;
if (_videoTrack && (_videoTrack->pid == pid)) {
currentVideoPts = pts = calcPts(avfc, _videoTrack->stream, packet.pts);
if (!player->output.Write(avfc, _videoTrack->stream, &packet, currentVideoPts))
;//fprintf(stderr, "writing data to video device failed\n");
} else if (_audioTrack && (_audioTrack->pid == pid)) {
if (restart_audio_resampling) {
restart_audio_resampling = false;
player->output.Write(avfc, _audioTrack->stream, NULL, currentAudioPts);
}
if (!player->isBackWard) {
currentAudioPts = pts = calcPts(avfc, _audioTrack->stream, packet.pts);
if (!player->output.Write(avfc, _audioTrack->stream, &packet, currentAudioPts))
;//fprintf(stderr, "writing data to audio device failed\n");
}
} else if (_subtitleTrack && (_subtitleTrack->pid == pid)) {
float duration = 3.0;
pts = calcPts(avfc, _subtitleTrack->stream, packet.pts);
if (duration > 0.0) {
/* is there a decoder ? */
if (((AVStream *) _subtitleTrack->stream)->codec->codec) {
AVSubtitle sub;
memset(&sub, 0, sizeof(sub));
int got_sub_ptr;
if (avcodec_decode_subtitle2(((AVStream *) _subtitleTrack->stream)->codec, &sub, &got_sub_ptr, &packet) < 0) {
fprintf(stderr, "error decoding subtitle\n");
}
if (got_sub_ptr && sub.num_rects > 0) {
switch (sub.rects[0]->type) {
case SUBTITLE_TEXT: // FIXME?
case SUBTITLE_ASS:
dvbsub_ass_write(((AVStream *) _subtitleTrack->stream)->codec, &sub, pid);
break;
case SUBTITLE_BITMAP:
dvbsub_write(&sub, pts);
// avsubtitle_free() will be called by handler
break;
default:
break;
}
}
if (pos > 0) {
float br;
if (avfc->bit_rate)
br = avfc->bit_rate / 8.0;
else
br = 180000.0;
seek_target = pos + player->Speed * 8 * br;
seek_target_flag = AVSEEK_FLAG_BYTE;
}
} else {
seek_target = ((((currentVideoPts > 0) ? currentVideoPts : currentAudioPts) / 90000.0) + player->Speed * 8) * AV_TIME_BASE;;
}
showtime = av_gettime() + 300000; //jump back every 300ms
} else {
bofcount = 0;
}
} /* duration */
} else if (_teletextTrack && (_teletextTrack->pid == pid)) {
teletext_write(pid, packet.data, packet.size);
}
av_free_packet(&packet);
} /* while */
if (seek_target > INT64_MIN) {
int res;
if (seek_target < 0)
seek_target = 0;
res = avformat_seek_file(avfc, -1, INT64_MIN, seek_target, INT64_MAX, seek_target_flag);
if (player && player->abortRequested)
player->output.Clear();
if (res < 0 && player->isBackWard)
bofcount = 1;
seek_target = INT64_MIN;
restart_audio_resampling = true;
dvbsub_ass_clear();
// flush streams
unsigned int i;
for (i = 0; i < avfc->nb_streams; i++)
if (avfc->streams[i]->codec && avfc->streams[i]->codec->codec)
avcodec_flush_buffers(avfc->streams[i]->codec);
}
AVPacket packet;
av_init_packet(&packet);
int av_res = av_read_frame(avfc, &packet);
if (av_res == AVERROR(EAGAIN)) {
av_free_packet(&packet);
continue;
}
if (av_res) { // av_read_frame failed
fprintf(stderr, "no data ->end of file reached ?\n");
av_free_packet(&packet);
break; // while
}
int64_t pts;
player->readCount += packet.size;
int pid = avfc->streams[packet.stream_index]->id;
Track *_videoTrack = videoTrack;
Track *_audioTrack = audioTrack;
Track *_subtitleTrack = subtitleTrack;
Track *_teletextTrack = teletextTrack;
if (_videoTrack && (_videoTrack->pid == pid)) {
currentVideoPts = pts = calcPts(avfc, _videoTrack->stream, packet.pts);
if (!player->output.Write(avfc, _videoTrack->stream, &packet, currentVideoPts))
fprintf(stderr, "writing data to video device failed\n");
} else if (_audioTrack && (_audioTrack->pid == pid)) {
if (restart_audio_resampling) {
restart_audio_resampling = false;
player->output.Write(avfc, _audioTrack->stream, NULL, currentAudioPts);
}
if (!player->isBackWard) {
currentAudioPts = pts = calcPts(avfc, _audioTrack->stream, packet.pts);
if (!player->output.Write(avfc, _audioTrack->stream, &packet, currentAudioPts))
fprintf(stderr, "writing data to audio device failed\n");
}
} else if (_subtitleTrack && (_subtitleTrack->pid == pid)) {
float duration = 3.0;
pts = calcPts(avfc, _subtitleTrack->stream, packet.pts);
if (duration > 0.0) {
/* is there a decoder ? */
if (((AVStream *) _subtitleTrack->stream)->codec->codec) {
AVSubtitle sub;
memset(&sub, 0, sizeof(sub));
int got_sub_ptr;
if (avcodec_decode_subtitle2(((AVStream *) _subtitleTrack->stream)->codec, &sub, &got_sub_ptr, &packet) < 0) {
fprintf(stderr, "error decoding subtitle\n");
}
if (got_sub_ptr && sub.num_rects > 0) {
switch (sub.rects[0]->type) {
case SUBTITLE_TEXT: // FIXME?
case SUBTITLE_ASS:
dvbsub_ass_write(((AVStream *) _subtitleTrack->stream)->codec, &sub, pid);
break;
case SUBTITLE_BITMAP:
dvbsub_write(&sub, pts);
// avsubtitle_free() will be called by handler
break;
default:
break;
}
}
}
} /* duration */
} else if (_teletextTrack && (_teletextTrack->pid == pid)) {
teletext_write(pid, packet.data, packet.size);
}
av_free_packet(&packet);
} /* while */
if (player && player->abortRequested)
player->output.Clear();
dvbsub_ass_clear();
player->abortPlayback = 1;
hasPlayThreadStarted = 0;
hasPlayThreadStarted = 0;
return true;
}
/* **************************** */
/* Container part for ffmpeg */
/* **************************** */
/*static*/ int interrupt_cb(void *arg)
{
Player *player = (Player *) arg;
return player->abortPlayback | player->abortRequested;
Player *player = (Player *) arg;
return player->abortPlayback | player->abortRequested;
}
static void log_callback(void *ptr __attribute__ ((unused)), int lvl __attribute__ ((unused)), const char *format, va_list ap)
@@ -305,45 +295,45 @@ bool Input::ReadSubtitle(const char *filename, const char *format, int pid)
AVFormatContext *subavfc = avformat_alloc_context();
if (avformat_open_input(&subavfc, subfile, av_find_input_format(format), 0)) {
avformat_free_context(subavfc);
avformat_free_context(subavfc);
return false;
}
avformat_find_stream_info(subavfc, NULL);
}
avformat_find_stream_info(subavfc, NULL);
if (subavfc->nb_streams != 1) {
avformat_free_context(subavfc);
avformat_free_context(subavfc);
return false;
}
AVCodecContext *c = subavfc->streams[0]->codec;
AVCodec *codec = avcodec_find_decoder(c->codec_id);
AVCodecContext *c = subavfc->streams[0]->codec;
AVCodec *codec = avcodec_find_decoder(c->codec_id);
if (!codec) {
avformat_free_context(subavfc);
avformat_free_context(subavfc);
return false;
}
// fprintf(stderr, "codec=%s\n", avcodec_get_name(c->codec_id));
if (avcodec_open2(c, codec, NULL) < 0) {
// fprintf(stderr, "codec=%s\n", avcodec_get_name(c->codec_id));
if (avcodec_open2(c, codec, NULL) < 0) {
fprintf(stderr, "%s %d: avcodec_open\n", __FILE__, __LINE__);
avformat_free_context(subavfc);
avformat_free_context(subavfc);
return false;
}
AVPacket avpkt;
av_init_packet(&avpkt);
AVPacket avpkt;
av_init_packet(&avpkt);
if (c->subtitle_header)
fprintf(stderr, "%s\n", c->subtitle_header);
if (c->subtitle_header)
fprintf(stderr, "%s\n", c->subtitle_header);
while (av_read_frame(subavfc, &avpkt) > -1) {
while (av_read_frame(subavfc, &avpkt) > -1) {
AVSubtitle sub;
memset(&sub, 0, sizeof(sub));
int got_sub = 0;
avcodec_decode_subtitle2(c, &sub, &got_sub, &avpkt);
if (got_sub)
memset(&sub, 0, sizeof(sub));
int got_sub = 0;
avcodec_decode_subtitle2(c, &sub, &got_sub, &avpkt);
if (got_sub)
dvbsub_ass_write(c, &sub, pid);
av_free_packet(&avpkt);
}
avformat_close_input(&subavfc);
avformat_free_context(subavfc);
av_free_packet(&avpkt);
}
avformat_close_input(&subavfc);
avformat_free_context(subavfc);
Track track;
track.Name = format;
@@ -366,92 +356,92 @@ bool Input::ReadSubtitles(const char *filename) {
bool Input::Init(const char *filename)
{
int err;
int err;
av_log_set_callback(log_callback);
av_log_set_callback(log_callback);
if (filename == NULL) {
fprintf(stderr, "filename NULL\n");
if (filename == NULL) {
fprintf(stderr, "filename NULL\n");
return false;
}
return false;
}
if (isContainerRunning) {
fprintf(stderr, "ups already running?\n");
return false;
}
isContainerRunning = true;
if (isContainerRunning) {
fprintf(stderr, "ups already running?\n");
return false;
}
isContainerRunning = true;
/* initialize ffmpeg */
avcodec_register_all();
av_register_all();
/* initialize ffmpeg */
avcodec_register_all();
av_register_all();
avformat_network_init();
avformat_network_init();
player->abortRequested = 0;
player->abortPlayback = 0;
videoTrack = NULL;
audioTrack = NULL;
subtitleTrack = NULL;
teletextTrack = NULL;
avfc = avformat_alloc_context();
avfc->interrupt_callback.callback = interrupt_cb;
avfc->interrupt_callback.opaque = (void *) &player;
player->abortRequested = 0;
player->abortPlayback = 0;
videoTrack = NULL;
audioTrack = NULL;
subtitleTrack = NULL;
teletextTrack = NULL;
avfc = avformat_alloc_context();
avfc->interrupt_callback.callback = interrupt_cb;
avfc->interrupt_callback.opaque = (void *) &player;
if ((err = avformat_open_input(&avfc, filename, NULL, 0)) != 0) {
char error[512];
if ((err = avformat_open_input(&avfc, filename, NULL, 0)) != 0) {
char error[512];
fprintf(stderr, "avformat_open_input failed %d (%s)\n", err, filename);
av_strerror(err, error, 512);
fprintf(stderr, "Cause: %s\n", error);
fprintf(stderr, "avformat_open_input failed %d (%s)\n", err, filename);
av_strerror(err, error, 512);
fprintf(stderr, "Cause: %s\n", error);
isContainerRunning = false;
return false;
}
isContainerRunning = false;
return false;
}
avfc->iformat->flags |= AVFMT_SEEK_TO_PTS;
avfc->flags = AVFMT_FLAG_GENPTS;
if (player->noprobe) {
avfc->max_analyze_duration = 1;
avfc->probesize = 8192;
}
avfc->iformat->flags |= AVFMT_SEEK_TO_PTS;
avfc->flags = AVFMT_FLAG_GENPTS;
if (player->noprobe) {
avfc->max_analyze_duration = 1;
avfc->probesize = 8192;
}
if (avformat_find_stream_info(avfc, NULL) < 0) {
fprintf(stderr, "Error avformat_find_stream_info\n");
if (avformat_find_stream_info(avfc, NULL) < 0) {
fprintf(stderr, "Error avformat_find_stream_info\n");
#ifdef this_is_ok
/* crow reports that sometimes this returns an error
* but the file is played back well. so remove this
* until other works are done and we can prove this.
*/
avformat_close_input(&avfc);
isContainerRunning = false;
return false;
/* crow reports that sometimes this returns an error
* but the file is played back well. so remove this
* until other works are done and we can prove this.
*/
avformat_close_input(&avfc);
isContainerRunning = false;
return false;
#endif
}
}
terminating = false;
int res = UpdateTracks();
terminating = false;
if (!videoTrack && !audioTrack) {
avformat_close_input(&avfc);
isContainerRunning = false;
return false;
}
bool res = UpdateTracks();
if (videoTrack)
player->output.SwitchVideo(videoTrack->stream);
if (audioTrack)
player->output.SwitchAudio(audioTrack->stream);
ReadSubtitles(filename);
if (!videoTrack && !audioTrack) {
avformat_close_input(&avfc);
isContainerRunning = false;
return false;
}
return res;
if (videoTrack)
player->output.SwitchVideo(videoTrack->stream);
if (audioTrack)
player->output.SwitchAudio(audioTrack->stream);
ReadSubtitles(filename);
return res;
}
bool Input::UpdateTracks()
{
if (terminating)
return true;
if (terminating)
return true;
std::vector<Chapter> chapters;
for (unsigned int i = 0; i < avfc->nb_chapters; i++) {
@@ -462,139 +452,110 @@ bool Input::UpdateTracks()
if (!ch)
continue;
Chapter chapter;
chapter.title = title ? title->value : "unknown";
chapter.title = title ? title->value : "?";
chapter.start = (double) ch->start * av_q2d(ch->time_base) * 1000.0;
chapter.end = (double) ch->end * av_q2d(ch->time_base) * 1000.0;
chapters.push_back(chapter);
}
player->SetChapters(chapters);
player->manager.initTrackUpdate();
player->manager.initTrackUpdate();
av_dump_format(avfc, 0, player->url.c_str(), 0);
av_dump_format(avfc, 0, player->url.c_str(), 0);
unsigned int n;
for (unsigned int n = 0; n < avfc->nb_streams; n++) {
AVStream *stream = avfc->streams[n];
for (n = 0; n < avfc->nb_streams; n++) {
Track track;
AVStream *stream = avfc->streams[n];
if (!stream->id)
stream->id = n + 1;
if (!stream->id)
stream->id = n + 1;
track.avfc = avfc;
track.stream = stream;
switch (stream->codec->codec_type) {
case AVMEDIA_TYPE_VIDEO:
track.Name = "und";
Track track;
track.avfc = avfc;
track.stream = stream;
AVDictionaryEntry *lang = av_dict_get(stream->metadata, "language", NULL, 0);
track.Name = lang ? lang->value : "?";
track.pid = stream->id;
if (stream->duration == AV_NOPTS_VALUE)
track.duration = (double) avfc->duration / 1000.0;
else
track.duration = (double) stream->duration * av_q2d(stream->time_base) * 1000.0;
if (stream->duration == AV_NOPTS_VALUE) {
track.duration = (double) avfc->duration / 1000.0;
} else {
track.duration = (double) stream->duration * av_q2d(stream->time_base) * 1000.0;
}
player->manager.addVideoTrack(track);
if (!videoTrack)
videoTrack = player->manager.getVideoTrack(track.pid);
break;
case AVMEDIA_TYPE_AUDIO:
AVDictionaryEntry *lang;
lang = av_dict_get(stream->metadata, "language", NULL, 0);
track.Name = lang ? lang->value : "und";
track.pid = stream->id;
track.duration = (double) stream->duration * av_q2d(stream->time_base) * 1000.0;
if (stream->duration == AV_NOPTS_VALUE) {
track.duration = (double) avfc->duration / 1000.0;
} else {
track.duration = (double) stream->duration * av_q2d(stream->time_base) * 1000.0;
}
switch(stream->codec->codec_id) {
case AUDIO_ENCODING_MPEG2:
track.ac3flags = 9;
switch (stream->codec->codec_type) {
case AVMEDIA_TYPE_VIDEO: {
player->manager.addVideoTrack(track);
if (!videoTrack)
videoTrack = player->manager.getVideoTrack(track.pid);
break;
case AV_CODEC_ID_MP3:
track.ac3flags = 4;
break;
case AV_CODEC_ID_AC3:
track.ac3flags = 1;
break;
case AV_CODEC_ID_EAC3:
track.ac3flags = 7;
break;
case AV_CODEC_ID_DTS:
track.ac3flags = 6;
break;
case AV_CODEC_ID_AAC:
track.ac3flags = 5;
break;
default:
track.ac3flags = 0;
}
player->manager.addAudioTrack(track);
if (!audioTrack)
audioTrack = player->manager.getAudioTrack(track.pid);
break;
case AVMEDIA_TYPE_SUBTITLE:
{
AVDictionaryEntry *lang;
lang = av_dict_get(stream->metadata, "language", NULL, 0);
track.Name = lang ? lang->value : "und";
track.pid = stream->id;
track.duration = (double) stream->duration * av_q2d(stream->time_base) * 1000.0;
if (stream->codec->codec_id == AV_CODEC_ID_DVB_TELETEXT) {
int i = 0;
AVDictionaryEntry *t = NULL;
do {
char tmp[30];
snprintf(tmp, sizeof(tmp), "teletext_%d", i);
t = av_dict_get(stream->metadata, tmp, NULL, 0);
if (t) {
char lang[strlen(t->value)];
if (5 == sscanf(t->value, "%d %s %d %d %d", &track.pid, lang, &track.type, &track.mag, &track.page)) {
track.Name = lang;
player->manager.addTeletextTrack(track);
}
}
i++;
} while (t);
} else {
if (!stream->codec->codec) {
stream->codec->codec = avcodec_find_decoder(stream->codec->codec_id);
if (!stream->codec->codec)
fprintf(stderr, "avcodec_find_decoder failed for subtitle track %d\n", n);
else if (avcodec_open2(stream->codec, stream->codec->codec, NULL)) {
fprintf(stderr, "avcodec_open2 failed for subtitle track %d\n", n);
stream->codec->codec = NULL;
case AVMEDIA_TYPE_AUDIO: {
switch(stream->codec->codec_id) {
case AUDIO_ENCODING_MPEG2:
track.ac3flags = 9;
break;
case AV_CODEC_ID_MP3:
track.ac3flags = 4;
break;
case AV_CODEC_ID_AC3:
track.ac3flags = 1;
break;
case AV_CODEC_ID_EAC3:
track.ac3flags = 7;
break;
case AV_CODEC_ID_DTS:
track.ac3flags = 6;
break;
case AV_CODEC_ID_AAC:
track.ac3flags = 5;
break;
default:
track.ac3flags = 0;
}
player->manager.addAudioTrack(track);
if (!audioTrack)
audioTrack = player->manager.getAudioTrack(track.pid);
break;
}
}
if (stream->codec->codec)
player->manager.addSubtitleTrack(track);
}
case AVMEDIA_TYPE_SUBTITLE: {
if (stream->codec->codec_id == AV_CODEC_ID_DVB_TELETEXT) {
int i = 0;
AVDictionaryEntry *t = NULL;
do {
char tmp[30];
snprintf(tmp, sizeof(tmp), "teletext_%d", i);
t = av_dict_get(stream->metadata, tmp, NULL, 0);
if (t) {
char lang[strlen(t->value)];
if (5 == sscanf(t->value, "%d %s %d %d %d", &track.pid, lang, &track.type, &track.mag, &track.page)) {
track.Name = lang;
player->manager.addTeletextTrack(track);
}
}
i++;
} while (t);
} else {
if (!stream->codec->codec) {
stream->codec->codec = avcodec_find_decoder(stream->codec->codec_id);
if (!stream->codec->codec)
fprintf(stderr, "avcodec_find_decoder failed for subtitle track %d\n", n);
else if (avcodec_open2(stream->codec, stream->codec->codec, NULL)) {
fprintf(stderr, "avcodec_open2 failed for subtitle track %d\n", n);
stream->codec->codec = NULL;
}
}
if (stream->codec->codec)
player->manager.addSubtitleTrack(track);
}
break;
}
default:
fprintf(stderr, "not handled or unknown codec_type %d\n", stream->codec->codec_type);
break;
}
break;
}
default:
fprintf(stderr, "not handled or unknown codec_type %d\n", stream->codec->codec_type);
break;
}
} /* for */
return true;
return true;
}
bool Input::Stop()
@@ -622,11 +583,11 @@ bool Input::Stop()
bool Input::Seek(float sec, bool absolute)
{
if (absolute)
seek_sec_abs = sec, seek_sec_rel = 0.0;
else
seek_sec_abs = -1.0, seek_sec_rel = sec;
return true;
if (absolute)
seek_sec_abs = sec, seek_sec_rel = 0.0;
else
seek_sec_abs = -1.0, seek_sec_rel = sec;
return true;
}
bool Input::GetDuration(double &duration)

View File

@@ -17,10 +17,6 @@
*
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdlib.h>
#include <string.h>
#include "manager.h"

View File

@@ -17,10 +17,6 @@
*
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -59,7 +55,6 @@
Output::Output()
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
videofd = audiofd = -1;
videoWriter = audioWriter = NULL;
videoStream = audioStream = NULL;
@@ -67,13 +62,11 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
Output::~Output()
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
Close();
}
bool Output::Open()
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
OpenThreads::ScopedLock<OpenThreads::Mutex> v_lock(videoMutex);
OpenThreads::ScopedLock<OpenThreads::Mutex> a_lock(audioMutex);
@@ -106,7 +99,6 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool Output::Close()
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
Stop();
OpenThreads::ScopedLock<OpenThreads::Mutex> v_lock(videoMutex);
@@ -126,7 +118,6 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool Output::Play()
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool ret = true;
OpenThreads::ScopedLock<OpenThreads::Mutex> v_lock(videoMutex);
@@ -151,7 +142,6 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool Output::Stop()
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool ret = true;
OpenThreads::ScopedLock<OpenThreads::Mutex> v_lock(videoMutex);
@@ -171,14 +161,13 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
dioctl(audiofd, AUDIO_SET_SPEED, DVB_SPEED_NORMAL_PLAY);
if (dioctl(audiofd, AUDIO_STOP, NULL))
ret = false;
}
}
return ret;
}
bool Output::Pause()
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool ret = true;
OpenThreads::ScopedLock<OpenThreads::Mutex> v_lock(videoMutex);
@@ -192,14 +181,13 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
if (audiofd > -1) {
if (dioctl(audiofd, AUDIO_PAUSE, NULL))
ret = false;
}
}
return ret;
}
bool Output::Continue()
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool ret = true;
OpenThreads::ScopedLock<OpenThreads::Mutex> v_lock(videoMutex);
@@ -213,14 +201,13 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
if (audiofd > -1) {
if (dioctl(audiofd, AUDIO_CONTINUE, NULL))
ret = false;
}
}
return ret;
}
bool Output::Mute(bool b)
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
OpenThreads::ScopedLock<OpenThreads::Mutex> a_lock(audioMutex);
//AUDIO_SET_MUTE has no effect with new player
@@ -233,7 +220,6 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool Output::Flush()
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool ret = true;
OpenThreads::ScopedLock<OpenThreads::Mutex> v_lock(videoMutex);
@@ -250,7 +236,6 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool Output::FastForward(int speed)
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
OpenThreads::ScopedLock<OpenThreads::Mutex> v_lock(videoMutex);
if (videofd > -1 && dioctl(videofd, VIDEO_FAST_FORWARD, speed))
@@ -261,7 +246,6 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool Output::SlowMotion(int speed)
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
OpenThreads::ScopedLock<OpenThreads::Mutex> v_lock(videoMutex);
if (videofd > -1 && dioctl(videofd, VIDEO_SLOWMOTION, speed))
@@ -272,7 +256,6 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool Output::AVSync(bool b)
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
OpenThreads::ScopedLock<OpenThreads::Mutex> a_lock(audioMutex);
if (audiofd > -1 && dioctl(audiofd, AUDIO_SET_AV_SYNC, b))
return false;
@@ -282,7 +265,6 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool Output::ClearAudio()
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
OpenThreads::ScopedLock<OpenThreads::Mutex> a_lock(audioMutex);
if (audiofd > -1 && dioctl(audiofd, AUDIO_CLEAR_BUFFER, NULL))
return false;
@@ -292,7 +274,6 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool Output::ClearVideo()
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
OpenThreads::ScopedLock<OpenThreads::Mutex> v_lock(videoMutex);
if (videofd > -1 && dioctl(videofd, VIDEO_CLEAR_BUFFER, NULL))
return false;
@@ -302,7 +283,6 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool Output::Clear()
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool aret = ClearAudio();
bool vret = ClearVideo();
return aret && vret;
@@ -310,7 +290,6 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool Output::GetPts(int64_t &pts)
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
pts = 0;
return ((videofd > -1 && !dioctl(videofd, VIDEO_GET_PTS, (void *) &pts)) ||
(audiofd > -1 && !dioctl(audiofd, AUDIO_GET_PTS, (void *) &pts)));
@@ -318,7 +297,6 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool Output::GetFrameCount(int64_t &framecount)
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
dvb_play_info_t playInfo;
if ((videofd > -1 && dioctl(videofd, VIDEO_GET_PLAY_INFO, (void *) &playInfo)) ||
@@ -331,7 +309,6 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool Output::SwitchAudio(AVStream *stream)
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
OpenThreads::ScopedLock<OpenThreads::Mutex> a_lock(audioMutex);
if (stream == audioStream)
return true;
@@ -353,7 +330,6 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool Output::SwitchVideo(AVStream *stream)
{
fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
OpenThreads::ScopedLock<OpenThreads::Mutex> v_lock(videoMutex);
if (stream == videoStream)
return true;
@@ -375,7 +351,6 @@ fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
bool Output::Write(AVFormatContext *avfc, AVStream *stream, AVPacket *packet, int64_t &Pts)
{
//fprintf(stderr, "%s %d %s\n", __FILE__,__LINE__,__func__);
switch (stream->codec->codec_type) {
case AVMEDIA_TYPE_VIDEO: {
OpenThreads::ScopedLock<OpenThreads::Mutex> v_lock(videoMutex);

View File

@@ -3,10 +3,6 @@
* duckbox 2010
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -29,9 +25,9 @@ static pthread_t supervisorThread;
Player::Player()
{
input.player = this;
output.player = this;
manager.player = this;
input.player = this;
output.player = this;
manager.player = this;
hasThreadStarted = 0;
}
@@ -51,69 +47,69 @@ void *Player::SupervisorThread(void *arg)
bool Player::Open(const char *Url)
{
if (isPlaying)
if (isPlaying)
Stop(); // shouldn't happen. Most definitely a bug
fprintf(stderr, "URL=%s\n", Url);
fprintf(stderr, "URL=%s\n", Url);
if (isPlaying) { // shouldn't happen
fprintf(stderr, "playback already running\n");
if (isPlaying) { // shouldn't happen
fprintf(stderr, "playback already running\n");
return false;
}
isHttp = 0;
if (!strncmp("file://", Url, 7) || !strncmp("myts://", Url, 7)) {
if (!strncmp("myts://", Url, 7)) {
url = "file";
url += (Url + 4);
noprobe = 1;
} else {
noprobe = 0;
url = Url;
}
} else if (strstr(Url, "://")) {
isHttp = 0;
if (!strncmp("file://", Url, 7) || !strncmp("myts://", Url, 7)) {
if (!strncmp("myts://", Url, 7)) {
url = "file";
url += (Url + 4);
noprobe = 1;
} else {
noprobe = 0;
url = Url;
}
} else if (strstr(Url, "://")) {
isHttp = 1;
if (!strncmp("mms://", Url, 6)) {
url = "mmst";
url += (Url + 3);
url = "mmst";
url += (Url + 3);
} else
url = Url;
} else {
fprintf(stderr, "Unknown stream (%s)\n", Url);
url = Url;
} else {
fprintf(stderr, "Unknown stream (%s)\n", Url);
return false;
}
manager.clearTracks();
}
manager.clearTracks();
if (!input.Init(url.c_str()))
return false;
if (!input.Init(url.c_str()))
return false;
fprintf(stderr, "exiting with value 0\n");
fprintf(stderr, "exiting with value 0\n");
return true;
return true;
}
bool Player::Close()
{
bool ret = true;
bool ret = true;
isPaused = 0;
isPlaying = 0;
isForwarding = 0;
isBackWard = 0;
isSlowMotion = 0;
Speed = 0;
url.clear();
isPaused = 0;
isPlaying = 0;
isForwarding = 0;
isBackWard = 0;
isSlowMotion = 0;
Speed = 0;
url.clear();
return ret;
return ret;
}
bool Player::Play()
{
pthread_attr_t attr;
bool ret = true;
pthread_attr_t attr;
bool ret = true;
if (!isPlaying) {
if (!isPlaying) {
AVSync = 1;
output.AVSync(true);
@@ -121,55 +117,55 @@ bool Player::Play()
ret = output.Play();
if (!ret) {
isCreationPhase = 0; // allow thread to go into next state
isCreationPhase = 0; // allow thread to go into next state
} else {
isPlaying = 1;
isPaused = 0;
isForwarding = 0;
if (isBackWard) {
isPlaying = 1;
isPaused = 0;
isForwarding = 0;
if (isBackWard) {
isBackWard = 0;
output.Mute(false);
}
isSlowMotion = 0;
Speed = 1;
if (hasThreadStarted == 0) {
int error;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if ((error = pthread_create(&supervisorThread, &attr, SupervisorThread, this))) {
fprintf(stderr, "Error creating thread, error:%d:%s\n", error, strerror(error));
ret = false;
} else {
fprintf(stderr, "Created thread\n");
}
}
isSlowMotion = 0;
Speed = 1;
fprintf(stderr, "clearing isCreationPhase!\n");
if (hasThreadStarted == 0) {
int error;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
isCreationPhase = 0; // allow thread to go into next state
if ((error = pthread_create(&supervisorThread, &attr, SupervisorThread, this))) {
fprintf(stderr, "Error creating thread, error:%d:%s\n", error, strerror(error));
ret = false;
} else {
fprintf(stderr, "Created thread\n");
}
}
fprintf(stderr, "clearing isCreationPhase!\n");
isCreationPhase = 0; // allow thread to go into next state
}
} else {
fprintf(stderr,"playback already running\n");
ret = false;
}
} else {
fprintf(stderr,"playback already running\n");
ret = false;
}
fprintf(stderr, "exiting with value %d\n", ret);
fprintf(stderr, "exiting with value %d\n", ret);
return ret;
return ret;
}
bool Player::Pause()
{
bool ret = true;
bool ret = true;
if (isPlaying && !isPaused) {
if (isPlaying && !isPaused) {
if (isSlowMotion)
output.Clear();
output.Clear();
output.Pause();
@@ -177,63 +173,62 @@ bool Player::Pause()
//isPlaying = 1;
isForwarding = 0;
if (isBackWard) {
isBackWard = 0;
output.Mute(false);
isBackWard = 0;
output.Mute(false);
}
isSlowMotion = 0;
Speed = 1;
} else {
fprintf(stderr,"playback not playing or already in pause mode\n");
ret = false;
}
isSlowMotion = 0;
Speed = 1;
} else {
fprintf(stderr,"playback not playing or already in pause mode\n");
ret = false;
}
fprintf(stderr, "exiting with value %d\n", ret);
fprintf(stderr, "exiting with value %d\n", ret);
return ret;
return ret;
}
bool Player::Continue()
{
int ret = true;
int ret = true;
if (isPlaying && (isPaused || isForwarding
|| isBackWard || isSlowMotion)) {
if (isPlaying && (isPaused || isForwarding || isBackWard || isSlowMotion)) {
if (isSlowMotion)
output.Clear();
if (isSlowMotion)
output.Clear();
output.Continue();
output.Continue();
isPaused = 0;
//isPlaying = 1;
isForwarding = 0;
if (isBackWard) {
isBackWard = 0;
output.Mute(false);
isPaused = 0;
//isPlaying = 1;
isForwarding = 0;
if (isBackWard) {
isBackWard = 0;
output.Mute(false);
}
isSlowMotion = 0;
Speed = 1;
} else {
fprintf(stderr,"continue not possible\n");
ret = false;
}
isSlowMotion = 0;
Speed = 1;
} else {
fprintf(stderr,"continue not possible\n");
ret = false;
}
return ret;
return ret;
}
bool Player::Stop()
{
bool ret = true;
int wait_time = 20;
bool ret = true;
int wait_time = 20;
if (isPlaying) {
if (isPlaying) {
isPaused = 0;
isPlaying = 0;
isForwarding = 0;
if (isBackWard) {
isBackWard = 0;
output.Mute(false);
isBackWard = 0;
output.Mute(false);
}
isSlowMotion = 0;
Speed = 0;
@@ -241,40 +236,40 @@ bool Player::Stop()
output.Stop();
input.Stop();
} else {
fprintf(stderr,"stop not possible\n");
ret = false;
}
} else {
fprintf(stderr,"stop not possible\n");
ret = false;
}
while ((hasThreadStarted == 1) && (--wait_time) > 0) {
fprintf(stderr, "Waiting for supervisor thread to terminate itself, will try another %d times\n", wait_time);
while ((hasThreadStarted == 1) && (--wait_time) > 0) {
fprintf(stderr, "Waiting for supervisor thread to terminate itself, will try another %d times\n", wait_time);
usleep(100000);
}
usleep(100000);
}
if (wait_time == 0) {
fprintf(stderr,"Timeout waiting for thread!\n");
if (wait_time == 0) {
fprintf(stderr,"Timeout waiting for thread!\n");
ret = false;
}
ret = false;
}
fprintf(stderr, "exiting with value %d\n", ret);
fprintf(stderr, "exiting with value %d\n", ret);
return ret;
return ret;
}
// FIXME
bool Player::Terminate()
{
bool ret = true;
int wait_time = 20;
bool ret = true;
int wait_time = 20;
fprintf(stderr, "\n");
fprintf(stderr, "\n");
if (isPlaying) {
if (isPlaying) {
if (!abortRequested && !output.Flush()) {
fprintf(stderr,"failed to flush output.\n");
fprintf(stderr,"failed to flush output.\n");
}
ret = input.Stop();
@@ -285,93 +280,91 @@ bool Player::Terminate()
isSlowMotion = 0;
Speed = 0;
} else {
} else {
/* fixme: konfetti: we should return an error here but this seems to be a condition which
* can happen and is not a real error, which leads to a dead neutrino. should investigate
* here later.
*/
}
}
while ((hasThreadStarted == 1) && (--wait_time) > 0) {
fprintf(stderr, "Waiting for supervisor thread to terminate itself, will try another %d times\n", wait_time);
while ((hasThreadStarted == 1) && (--wait_time) > 0) {
fprintf(stderr, "Waiting for supervisor thread to terminate itself, will try another %d times\n", wait_time);
usleep(100000);
}
usleep(100000);
}
if (wait_time == 0) {
fprintf(stderr,"Timeout waiting for thread!\n");
if (wait_time == 0) {
fprintf(stderr,"Timeout waiting for thread!\n");
ret = false;
}
ret = false;
}
fprintf(stderr, "exiting with value %d\n", ret);
fprintf(stderr, "exiting with value %d\n", ret);
return ret;
return ret;
}
bool Player::FastForward(int speed)
{
int ret = true;
int ret = true;
/* Audio only forwarding not supported */
if (isVideo && !isHttp && !isBackWard
&& (!isPaused || isPlaying)) {
/* Audio only forwarding not supported */
if (isVideo && !isHttp && !isBackWard && (!isPaused || isPlaying)) {
if ((speed <= 0) || (speed > cMaxSpeed_ff)) {
fprintf(stderr, "speed %d out of range (1 - %d) \n", speed, cMaxSpeed_ff);
return false;
if ((speed <= 0) || (speed > cMaxSpeed_ff)) {
fprintf(stderr, "speed %d out of range (1 - %d) \n", speed, cMaxSpeed_ff);
return false;
}
isForwarding = 1;
Speed = speed;
output.FastForward(speed);
} else {
fprintf(stderr,"fast forward not possible\n");
ret = false;
}
isForwarding = 1;
Speed = speed;
output.FastForward(speed);
} else {
fprintf(stderr,"fast forward not possible\n");
ret = false;
}
return ret;
return ret;
}
bool Player::FastBackward(int speed)
{
bool ret = true;
bool ret = true;
/* Audio only reverse play not supported */
if (isVideo && !isForwarding
&& (!isPaused || isPlaying)) {
/* Audio only reverse play not supported */
if (isVideo && !isForwarding && (!isPaused || isPlaying)) {
if ((speed > 0) || (speed < cMaxSpeed_fr)) {
fprintf(stderr, "speed %d out of range (0 - %d) \n", speed, cMaxSpeed_fr);
return false;
fprintf(stderr, "speed %d out of range (0 - %d) \n", speed, cMaxSpeed_fr);
return false;
}
if (speed == 0) {
isBackWard = false;
Speed = false; /* reverse end */
isBackWard = false;
Speed = false; /* reverse end */
} else {
Speed = speed;
isBackWard = true;
Speed = speed;
isBackWard = true;
}
output.Clear();
#if 0
if (output->Command(player, OUTPUT_REVERSE, NULL) < 0) {
fprintf(stderr,"OUTPUT_REVERSE failed\n");
isBackWard = 0;
Speed = 1;
ret = false;
fprintf(stderr,"OUTPUT_REVERSE failed\n");
isBackWard = 0;
Speed = 1;
ret = false;
}
#endif
} else {
fprintf(stderr,"fast backward not possible\n");
ret = false;
}
} else {
fprintf(stderr,"fast backward not possible\n");
ret = false;
}
if (isBackWard)
output.Mute(true);
if (isBackWard)
output.Mute(true);
return ret;
return ret;
}
bool Player::SlowMotion(int repeats)
@@ -381,13 +374,13 @@ bool Player::SlowMotion(int repeats)
Continue();
switch (repeats) {
case 2:
case 4:
case 8:
isSlowMotion = true;
break;
default:
repeats = 0;
case 2:
case 4:
case 8:
isSlowMotion = true;
break;
default:
repeats = 0;
}
output.SlowMotion(repeats);
@@ -399,8 +392,8 @@ bool Player::SlowMotion(int repeats)
bool Player::Seek(float pos, bool absolute)
{
output.Clear();
return input.Seek(pos, absolute);
output.Clear();
return input.Seek(pos, absolute);
}
bool Player::GetPts(int64_t &pts)
@@ -419,10 +412,10 @@ bool Player::GetFrameCount(int64_t &frameCount)
bool Player::GetDuration(double &duration)
{
duration = -1;
if (isPlaying)
return input.GetDuration(duration);
return false;
duration = -1;
if (isPlaying)
return input.GetDuration(duration);
return false;
}
bool Player::SwitchVideo(int pid)

View File

@@ -19,10 +19,6 @@
*
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -64,51 +60,50 @@ bool WriterDIVX::Write(int fd, AVFormatContext * /* avfc */, AVStream *stream, A
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 };
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);
usecPerFrame = 1000000 / av_q2d(stream->r_frame_rate);
memset(FakeHeaders, 0, sizeof(FakeHeaders));
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);
/* 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));
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;
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;
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;
initialHeader = false;
}
iov[ic].iov_base = packet->data;
iov[ic++].iov_len = packet->size;
return writev(fd, iov, ic) > -1;
return writev(fd, iov, ic) > -1;
}
WriterDIVX::WriterDIVX()

View File

@@ -31,7 +31,7 @@
#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)
#define PES_AUDIO_HEADER_SIZE (32 + PES_AUDIO_PRIVATE_HEADER_SIZE)
class WriterDTS : public Writer
{
@@ -45,33 +45,33 @@ bool WriterDTS::Write(int fd, AVFormatContext * /* avfc */, AVStream * /* stream
if (fd < 0 || !packet)
return false;
unsigned char PesHeader[PES_AUDIO_HEADER_SIZE];
unsigned char PesHeader[PES_AUDIO_HEADER_SIZE];
// #define DO_BYTESWAP
#ifdef DO_BYTESWAP
unsigned char Data[packet->size];
memcpy(Data, packet->data, packet->size);
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;
}
/* 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];
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);
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;
iov[1].iov_base = Data;
#else
iov[1].iov_base = packet->data;
iov[1].iov_base = packet->data;
#endif
iov[1].iov_len = packet->size;
iov[1].iov_len = packet->size;
return writev(fd, iov, 2) > -1;
return writev(fd, iov, 2) > -1;
}
WriterDTS::WriterDTS()

View File

@@ -42,15 +42,15 @@ bool WriterFLAC::Write(int fd, AVFormatContext * /* avfc */, AVStream * /* strea
if (fd < 0 || !packet)
return -1;
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
struct iovec iov[2];
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;
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;
return writev(fd, iov, 2) > -1;
}
WriterFLAC::WriterFLAC()

View File

@@ -39,27 +39,27 @@ bool WriterH263::Write(int fd, AVFormatContext * /* avfc */, AVStream * /* strea
{
if (fd < 0 || !packet)
return false;
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
int HeaderLength = InsertPesHeader(PesHeader, packet->size, H263_VIDEO_PES_START_CODE, pts, 0);
int HeaderLength = InsertPesHeader(PesHeader, packet->size, H263_VIDEO_PES_START_CODE, pts, 0);
int PrivateHeaderLength = InsertVideoPrivateDataHeader(&PesHeader[HeaderLength], packet->size);
int PrivateHeaderLength = InsertVideoPrivateDataHeader(&PesHeader[HeaderLength], packet->size);
int PesLength = PesHeader[PES_LENGTH_BYTE_0] + (PesHeader[PES_LENGTH_BYTE_1] << 8) + PrivateHeaderLength;
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;
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;
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;
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()

View File

@@ -31,17 +31,17 @@
#include "pes.h"
#include "writer.h"
#define NALU_TYPE_PLAYER2_CONTAINER_PARAMETERS 24
#define CONTAINER_PARAMETERS_VERSION 0x00
#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 */
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 };
@@ -68,204 +68,200 @@ bool WriterH264::Write(int fd, AVFormatContext * /* avfc */, AVStream *stream, A
{
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];
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;
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 ((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;
}
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 (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 == 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;
}
if (avcCHeader->Version != 1)
fprintf(stderr, "Error unknown avcC version (%x). Expect problems.\n", avcCHeader->Version);
unsigned int SampleSize = packet->size;
unsigned int NalStart = 0;
unsigned int VideoPosition = 0;
ParametersLength = 0;
do {
unsigned int NalLength;
unsigned char NalData[4];
int NalPresent = 1;
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
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 (TimeDelta == 0xffffffff)
TimeDelta = (TimeScale > 1000) ? 1001 : 1;
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;
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;
if (NalPresent) {
NalPresent = 0;
iov[ic].iov_base = (char *) Head;
iov[ic++].iov_len = sizeof(Head);
}
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
iov[ic].iov_base = packet->data + VideoPosition;
iov[ic++].iov_len = NalLength;
VideoPosition += NalLength;
assert(ParametersLength <= sizeof(HeaderData));
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;
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;
VideoPts = INVALID_PTS_VALUE;
}
} while (NalStart < SampleSize);
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;
return len > -1;
}
WriterH264::WriterH264()

View File

@@ -24,66 +24,65 @@
#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;
unsigned int bit_buf;
unsigned int bit_left;
bit_buf = ld->BitBuffer;
bit_left = ld->Remaining;
bit_buf = ld->BitBuffer;
bit_left = ld->Remaining;
#ifdef DEBUG_PUTBITS
if (ld->debug)
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;
}
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);
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;
/* writeback */
ld->BitBuffer = bit_buf;
ld->Remaining = bit_left;
}
void FlushBits(BitPacker_t * ld)
{
ld->BitBuffer <<= ld->Remaining;
while (ld->Remaining < 32) {
ld->BitBuffer <<= ld->Remaining;
while (ld->Remaining < 32) {
#ifdef DEBUG_PUTBITS
if (ld->debug)
dprintf("flushing 0x%2.2x\n", ld->BitBuffer >> 24);
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;
*ld->Ptr++ = ld->BitBuffer >> 24;
ld->BitBuffer <<= 8;
ld->Remaining += 8;
}
ld->Remaining = 32;
ld->BitBuffer = 0;
}

View File

@@ -42,15 +42,15 @@ bool WriterMP3::Write(int fd, AVFormatContext * /* avfc */, AVStream * /* stream
if (fd < 0 || !packet)
return false;
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
struct iovec iov[2];
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;
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;
return writev(fd, iov, 2) > -1;
}
WriterMP3::WriterMP3()

View File

@@ -83,150 +83,149 @@ class WriterPCM : public Writer
bool WriterPCM::prepareClipPlay()
{
SubFrameLen = 0;
SubFramesPerPES = 0;
breakBufferFillSize = 0;
SubFrameLen = 0;
SubFramesPerPES = 0;
breakBufferFillSize = 0;
memcpy(lpcm_prv, clpcm_prv, sizeof(lpcm_prv));
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;
}
// 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);
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;
//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;
//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;
}
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;
return true;
}
int WriterPCM::writePCM(int fd, int64_t Pts, uint8_t *data, unsigned int size)
{
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
if (initialHeader) {
initialHeader = false;
prepareClipPlay();
}
if (initialHeader) {
initialHeader = false;
prepareClipPlay();
}
unsigned int n;
unsigned char *injectBuffer = (unsigned char *) malloc(SubFrameLen);
unsigned int pos;
unsigned int n;
unsigned char *injectBuffer = (unsigned char *) malloc(SubFrameLen);
unsigned int pos;
for (pos = 0; pos < size;) {
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;
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);
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;
return size;
}
void WriterPCM::Init()
{
initialHeader = true;
restart_audio_resampling = true;
initialHeader = true;
restart_audio_resampling = true;
}
extern int64_t calcPts(AVFormatContext *, AVStream *, int64_t);
@@ -237,7 +236,6 @@ bool WriterPCM::Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket
return false;
if (!packet) {
fprintf(stderr, "%s %s %d\n", __FILE__, __func__, __LINE__);
restart_audio_resampling = true;
return true;
}
@@ -246,18 +244,13 @@ fprintf(stderr, "%s %s %d\n", __FILE__, __func__, __LINE__);
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) {
if (swr)
swr_free(&swr);
swr = NULL; //FIXME: Needed?
}
if (decoded_frame) {
if (decoded_frame)
av_frame_free(&decoded_frame);
decoded_frame = NULL; //FIXME: Needed?
}
AVCodec *codec = avcodec_find_decoder(c->codec_id);
@@ -276,7 +269,6 @@ fprintf(stderr, "%s %s %d\n", __FILE__, __func__, __LINE__);
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;
}
@@ -317,12 +309,10 @@ fprintf(stderr, "%s %s %d\n", __FILE__, __func__, __LINE__);
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",
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;
}
}
@@ -365,7 +355,7 @@ WriterPCM::WriterPCM()
out_channel_layout = AV_CH_LAYOUT_STEREO;
restart_audio_resampling = true;
Register(this, AV_CODEC_ID_PCM_S16LE/*FIXME*/, AUDIO_ENCODING_LPCMA);
Register(this, AV_CODEC_ID_INJECTPCM, AUDIO_ENCODING_LPCMA);
}
static WriterPCM writer_pcm __attribute__ ((init_priority (300)));

View File

@@ -27,44 +27,11 @@
#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)
{

View File

@@ -65,7 +65,7 @@ bool WriterVC1::Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket
if (fd < 0 || !packet)
return false;
if (initialHeader) {
if (initialHeader) {
initialHeader = false;
FrameHeaderSeen = false;
@@ -74,15 +74,15 @@ bool WriterVC1::Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket
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
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];
@@ -158,7 +158,7 @@ bool WriterVC1::Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket
memcpy(&PesHeader[HeaderLength], Vc1FrameStartCode, sizeof(Vc1FrameStartCode));
HeaderLength += sizeof(Vc1FrameStartCode);
}
insertSampleHeader = 0;
insertSampleHeader = 0;
}
struct iovec iov[2];

View File

@@ -33,22 +33,22 @@
#include <algorithm>
#define WMV3_PRIVATE_DATA_LENGTH 4
#define WMV3_PRIVATE_DATA_LENGTH 4
static const unsigned char Metadata[] = {
0x00, 0x00, 0x00, 0xc5,
0x04, 0x00, 0x00, 0x00,
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 */
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,
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,
0x60, 0x00, 0x00, 0x00, /* Struct B */
0x00, 0x00, 0x00, 0x00,
#define METADATA_STRUCT_B_FRAMERATE_START 32
0x00, 0x00, 0x00, 0x00
0x00, 0x00, 0x00, 0x00
};
class WriterWMV : public Writer
@@ -63,7 +63,7 @@ class WriterWMV : public Writer
void WriterWMV::Init()
{
initialHeader = 1;
initialHeader = 1;
}
bool WriterWMV::Write(int fd, AVFormatContext * /* avfc */, AVStream *stream, AVPacket *packet, int64_t &pts)
@@ -71,92 +71,92 @@ bool WriterWMV::Write(int fd, AVFormatContext * /* avfc */, AVStream *stream, AV
if (fd < 0 || !packet)
return false;
if (initialHeader) {
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)));
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];
PesPtr = &PesPacket[PES_MIN_HEADER_SIZE];
memcpy(PesPtr, Metadata, sizeof(Metadata));
PesPtr += METADATA_STRUCT_C_START;
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);
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;
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;
/* 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 += 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;
*PesPtr++ = (usecPerFrame >> 0) & 0xff;
*PesPtr++ = (usecPerFrame >> 8) & 0xff;
*PesPtr++ = (usecPerFrame >> 16) & 0xff;
*PesPtr++ = usecPerFrame >> 24;
MetadataLength = PesPtr - &PesPacket[PES_MIN_HEADER_SIZE];
MetadataLength = PesPtr - &PesPacket[PES_MIN_HEADER_SIZE];
int HeaderLength = InsertPesHeader(PesPacket, MetadataLength, VC1_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0);
int HeaderLength = InsertPesHeader(PesPacket, MetadataLength, VC1_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0);
if (write(fd, PesPacket, HeaderLength + MetadataLength) < 0)
return false;
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;
initialHeader = false;
}
}
return true;
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()