libeplayer3: cleanups

This commit is contained in:
martii
2014-04-07 23:00:03 +02:00
parent 82984ebd1e
commit 42efb5c739
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 AM_CPPFLAGS += -ggdb
libeplayer3_la_SOURCES = \ libeplayer3_la_SOURCES = \
container/container_ffmpeg.cpp \ input.cpp output.cpp manager.cpp player.cpp \
manager/manager.cpp output/output.cpp \ writer/writer.cpp writer/wmv.cpp writer/ac3.cpp writer/divx.cpp writer/pes.cpp \
playback/playback.cpp output/writer/writer.cpp output/writer/wmv.cpp \ writer/dts.cpp writer/mpeg2.cpp writer/mp3.cpp writer/misc.cpp writer/h264.cpp \
output/writer/ac3.cpp output/writer/divx.cpp output/writer/pes.cpp \ writer/h263.cpp writer/vc1.cpp writer/flac.cpp writer/pcm.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
LIBEPLAYER3_LIBS = libeplayer3.la -lpthread -lavformat -lavcodec -lavutil -lswresample -lm LIBEPLAYER3_LIBS = libeplayer3.la -lpthread -lavformat -lavcodec -lavutil -lswresample -lm

View File

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

View File

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

View File

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

View File

@@ -19,10 +19,6 @@
* *
*/ */
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
@@ -65,22 +61,22 @@ Input::~Input()
int64_t calcPts(AVFormatContext *avfc, AVStream * stream, int64_t pts) int64_t calcPts(AVFormatContext *avfc, AVStream * stream, int64_t pts)
{ {
if (!avfc || !stream) { if (!avfc || !stream) {
fprintf(stderr, "player / stream null\n"); fprintf(stderr, "player / stream null\n");
return INVALID_PTS_VALUE; return INVALID_PTS_VALUE;
} }
if (pts == AV_NOPTS_VALUE) if (pts == AV_NOPTS_VALUE)
pts = INVALID_PTS_VALUE; pts = INVALID_PTS_VALUE;
else if (avfc->start_time == AV_NOPTS_VALUE) else if (avfc->start_time == AV_NOPTS_VALUE)
pts = 90000.0 * (double) pts * av_q2d(stream->time_base); pts = 90000.0 * (double) pts * av_q2d(stream->time_base);
else else
pts = 90000.0 * (double) pts * av_q2d(stream->time_base) - 90000.0 * avfc->start_time / AV_TIME_BASE; pts = 90000.0 * (double) pts * av_q2d(stream->time_base) - 90000.0 * avfc->start_time / AV_TIME_BASE;
if (pts & 0x8000000000000000ull) if (pts & 0x8000000000000000ull)
pts = INVALID_PTS_VALUE; pts = INVALID_PTS_VALUE;
return pts; return pts;
} }
// from neutrino-mp/lib/libdvbsubtitle/dvbsub.cpp // 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() bool Input::Play()
{ {
char threadname[17]; char threadname[17];
strncpy(threadname, __func__, sizeof(threadname)); strncpy(threadname, __func__, sizeof(threadname));
threadname[16] = 0; threadname[16] = 0;
prctl(PR_SET_NAME, (unsigned long) &threadname); 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) { while (player->isCreationPhase) {
fprintf(stderr, "Thread waiting for end of init phase...\n"); fprintf(stderr, "Thread waiting for end of init phase...\n");
usleep(1000); 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;
} }
fprintf(stderr, "Running!\n");
int seek_target_flag = 0;
int64_t seek_target = INT64_MIN;
if (seek_sec_rel != 0.0) { while (player->isPlaying && !player->abortRequested) {
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();
if (bofcount == 1) { //IF MOVIE IS PAUSED, WAIT
showtime = av_gettime(); if (player->isPaused) {
usleep(100000); fprintf(stderr, "paused\n");
continue; 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;
} }
} 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 seek_target_flag = 0;
int res; int64_t seek_target = INT64_MIN;
if (seek_target < 0)
seek_target = 0;
res = avformat_seek_file(avfc, -1, INT64_MIN, seek_target, INT64_MAX, seek_target_flag);
if (res < 0 && player->isBackWard) if (seek_sec_rel != 0.0) {
bofcount = 1; if (avfc->iformat->flags & AVFMT_TS_DISCONT) {
seek_target = INT64_MIN; float br = (avfc->bit_rate) ? avfc->bit_rate / 8.0 : 180000.0;
restart_audio_resampling = true; 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 if (bofcount == 1) {
unsigned int i; showtime = av_gettime();
for (i = 0; i < avfc->nb_streams; i++) usleep(100000);
if (avfc->streams[i]->codec && avfc->streams[i]->codec->codec) continue;
avcodec_flush_buffers(avfc->streams[i]->codec); }
}
AVPacket packet; if (avfc->iformat->flags & AVFMT_TS_DISCONT) {
av_init_packet(&packet); off_t pos = avio_tell(avfc->pb);
int av_res = av_read_frame(avfc, &packet); if (pos > 0) {
if (av_res == AVERROR(EAGAIN)) { float br;
av_free_packet(&packet); if (avfc->bit_rate)
continue; br = avfc->bit_rate / 8.0;
} else
if (av_res) { // av_read_frame failed br = 180000.0;
fprintf(stderr, "no data ->end of file reached ?\n"); seek_target = pos + player->Speed * 8 * br;
av_free_packet(&packet); seek_target_flag = AVSEEK_FLAG_BYTE;
break; // while }
} } else {
long long int pts; seek_target = ((((currentVideoPts > 0) ? currentVideoPts : currentAudioPts) / 90000.0) + player->Speed * 8) * AV_TIME_BASE;;
}
player->readCount += packet.size; showtime = av_gettime() + 300000; //jump back every 300ms
} else {
int pid = avfc->streams[packet.stream_index]->id; bofcount = 0;
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); if (seek_target > INT64_MIN) {
} /* while */ 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) if (res < 0 && player->isBackWard)
player->output.Clear(); 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; player->abortPlayback = 1;
hasPlayThreadStarted = 0; hasPlayThreadStarted = 0;
return true; return true;
} }
/* **************************** */
/* Container part for ffmpeg */
/* **************************** */
/*static*/ int interrupt_cb(void *arg) /*static*/ int interrupt_cb(void *arg)
{ {
Player *player = (Player *) arg; Player *player = (Player *) arg;
return player->abortPlayback | player->abortRequested; return player->abortPlayback | player->abortRequested;
} }
static void log_callback(void *ptr __attribute__ ((unused)), int lvl __attribute__ ((unused)), const char *format, va_list ap) 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(); AVFormatContext *subavfc = avformat_alloc_context();
if (avformat_open_input(&subavfc, subfile, av_find_input_format(format), 0)) { if (avformat_open_input(&subavfc, subfile, av_find_input_format(format), 0)) {
avformat_free_context(subavfc); avformat_free_context(subavfc);
return false; return false;
} }
avformat_find_stream_info(subavfc, NULL); avformat_find_stream_info(subavfc, NULL);
if (subavfc->nb_streams != 1) { if (subavfc->nb_streams != 1) {
avformat_free_context(subavfc); avformat_free_context(subavfc);
return false; return false;
} }
AVCodecContext *c = subavfc->streams[0]->codec; AVCodecContext *c = subavfc->streams[0]->codec;
AVCodec *codec = avcodec_find_decoder(c->codec_id); AVCodec *codec = avcodec_find_decoder(c->codec_id);
if (!codec) { if (!codec) {
avformat_free_context(subavfc); avformat_free_context(subavfc);
return false; return false;
} }
// fprintf(stderr, "codec=%s\n", avcodec_get_name(c->codec_id)); // fprintf(stderr, "codec=%s\n", avcodec_get_name(c->codec_id));
if (avcodec_open2(c, codec, NULL) < 0) { if (avcodec_open2(c, codec, NULL) < 0) {
fprintf(stderr, "%s %d: avcodec_open\n", __FILE__, __LINE__); fprintf(stderr, "%s %d: avcodec_open\n", __FILE__, __LINE__);
avformat_free_context(subavfc); avformat_free_context(subavfc);
return false; return false;
} }
AVPacket avpkt; AVPacket avpkt;
av_init_packet(&avpkt); av_init_packet(&avpkt);
if (c->subtitle_header) if (c->subtitle_header)
fprintf(stderr, "%s\n", 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; AVSubtitle sub;
memset(&sub, 0, sizeof(sub)); memset(&sub, 0, sizeof(sub));
int got_sub = 0; int got_sub = 0;
avcodec_decode_subtitle2(c, &sub, &got_sub, &avpkt); avcodec_decode_subtitle2(c, &sub, &got_sub, &avpkt);
if (got_sub) if (got_sub)
dvbsub_ass_write(c, &sub, pid); dvbsub_ass_write(c, &sub, pid);
av_free_packet(&avpkt); av_free_packet(&avpkt);
} }
avformat_close_input(&subavfc); avformat_close_input(&subavfc);
avformat_free_context(subavfc); avformat_free_context(subavfc);
Track track; Track track;
track.Name = format; track.Name = format;
@@ -366,92 +356,92 @@ bool Input::ReadSubtitles(const char *filename) {
bool Input::Init(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) { if (filename == NULL) {
fprintf(stderr, "filename NULL\n"); fprintf(stderr, "filename NULL\n");
return false;
}
return false; if (isContainerRunning) {
} fprintf(stderr, "ups already running?\n");
return false;
}
isContainerRunning = true;
if (isContainerRunning) { /* initialize ffmpeg */
fprintf(stderr, "ups already running?\n"); avcodec_register_all();
return false; av_register_all();
}
isContainerRunning = true;
/* initialize ffmpeg */ avformat_network_init();
avcodec_register_all();
av_register_all();
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; if ((err = avformat_open_input(&avfc, filename, NULL, 0)) != 0) {
player->abortPlayback = 0; char error[512];
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) { fprintf(stderr, "avformat_open_input failed %d (%s)\n", err, filename);
char error[512]; av_strerror(err, error, 512);
fprintf(stderr, "Cause: %s\n", error);
fprintf(stderr, "avformat_open_input failed %d (%s)\n", err, filename); isContainerRunning = false;
av_strerror(err, error, 512); return false;
fprintf(stderr, "Cause: %s\n", error); }
isContainerRunning = false; avfc->iformat->flags |= AVFMT_SEEK_TO_PTS;
return false; avfc->flags = AVFMT_FLAG_GENPTS;
} if (player->noprobe) {
avfc->max_analyze_duration = 1;
avfc->probesize = 8192;
}
avfc->iformat->flags |= AVFMT_SEEK_TO_PTS; if (avformat_find_stream_info(avfc, NULL) < 0) {
avfc->flags = AVFMT_FLAG_GENPTS; fprintf(stderr, "Error avformat_find_stream_info\n");
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");
#ifdef this_is_ok #ifdef this_is_ok
/* crow reports that sometimes this returns an error /* crow reports that sometimes this returns an error
* but the file is played back well. so remove this * but the file is played back well. so remove this
* until other works are done and we can prove this. * until other works are done and we can prove this.
*/ */
avformat_close_input(&avfc); avformat_close_input(&avfc);
isContainerRunning = false; isContainerRunning = false;
return false; return false;
#endif #endif
} }
terminating = false; terminating = false;
int res = UpdateTracks();
if (!videoTrack && !audioTrack) { bool res = UpdateTracks();
avformat_close_input(&avfc);
isContainerRunning = false;
return false;
}
if (videoTrack) if (!videoTrack && !audioTrack) {
player->output.SwitchVideo(videoTrack->stream); avformat_close_input(&avfc);
if (audioTrack) isContainerRunning = false;
player->output.SwitchAudio(audioTrack->stream); return false;
}
ReadSubtitles(filename);
return res; if (videoTrack)
player->output.SwitchVideo(videoTrack->stream);
if (audioTrack)
player->output.SwitchAudio(audioTrack->stream);
ReadSubtitles(filename);
return res;
} }
bool Input::UpdateTracks() bool Input::UpdateTracks()
{ {
if (terminating) if (terminating)
return true; return true;
std::vector<Chapter> chapters; std::vector<Chapter> chapters;
for (unsigned int i = 0; i < avfc->nb_chapters; i++) { for (unsigned int i = 0; i < avfc->nb_chapters; i++) {
@@ -462,139 +452,110 @@ bool Input::UpdateTracks()
if (!ch) if (!ch)
continue; continue;
Chapter chapter; 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.start = (double) ch->start * av_q2d(ch->time_base) * 1000.0;
chapter.end = (double) ch->end * av_q2d(ch->time_base) * 1000.0; chapter.end = (double) ch->end * av_q2d(ch->time_base) * 1000.0;
chapters.push_back(chapter); chapters.push_back(chapter);
} }
player->SetChapters(chapters); 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++) { if (!stream->id)
Track track; stream->id = n + 1;
AVStream *stream = avfc->streams[n];
if (!stream->id) Track track;
stream->id = n + 1;
track.avfc = avfc;
track.stream = stream;
switch (stream->codec->codec_type) {
case AVMEDIA_TYPE_VIDEO:
track.Name = "und";
track.avfc = avfc; 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; 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); switch (stream->codec->codec_type) {
if (!videoTrack) case AVMEDIA_TYPE_VIDEO: {
videoTrack = player->manager.getVideoTrack(track.pid); player->manager.addVideoTrack(track);
break; if (!videoTrack)
case AVMEDIA_TYPE_AUDIO: videoTrack = player->manager.getVideoTrack(track.pid);
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;
break; 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++; case AVMEDIA_TYPE_AUDIO: {
} while (t); switch(stream->codec->codec_id) {
} else { case AUDIO_ENCODING_MPEG2:
if (!stream->codec->codec) { track.ac3flags = 9;
stream->codec->codec = avcodec_find_decoder(stream->codec->codec_id); break;
if (!stream->codec->codec) case AV_CODEC_ID_MP3:
fprintf(stderr, "avcodec_find_decoder failed for subtitle track %d\n", n); track.ac3flags = 4;
else if (avcodec_open2(stream->codec, stream->codec->codec, NULL)) { break;
fprintf(stderr, "avcodec_open2 failed for subtitle track %d\n", n); case AV_CODEC_ID_AC3:
stream->codec->codec = NULL; 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: {
if (stream->codec->codec) if (stream->codec->codec_id == AV_CODEC_ID_DVB_TELETEXT) {
player->manager.addSubtitleTrack(track); 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() bool Input::Stop()
@@ -622,11 +583,11 @@ bool Input::Stop()
bool Input::Seek(float sec, bool absolute) bool Input::Seek(float sec, bool absolute)
{ {
if (absolute) if (absolute)
seek_sec_abs = sec, seek_sec_rel = 0.0; seek_sec_abs = sec, seek_sec_rel = 0.0;
else else
seek_sec_abs = -1.0, seek_sec_rel = sec; seek_sec_abs = -1.0, seek_sec_rel = sec;
return true; return true;
} }
bool Input::GetDuration(double &duration) bool Input::GetDuration(double &duration)

View File

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

View File

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

View File

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

View File

@@ -19,10 +19,6 @@
* *
*/ */
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@@ -64,51 +60,50 @@ bool WriterDIVX::Write(int fd, AVFormatContext * /* avfc */, AVStream *stream, A
if (fd < 0 || !packet) if (fd < 0 || !packet)
return false; return false;
unsigned char PesHeader[PES_MAX_HEADER_SIZE]; unsigned char PesHeader[PES_MAX_HEADER_SIZE];
unsigned char FakeHeaders[64]; // 64bytes should be enough to make the fake headers unsigned char FakeHeaders[64]; // 64bytes should be enough to make the fake headers
unsigned int FakeHeaderLength; unsigned int FakeHeaderLength;
unsigned char Version = 5; unsigned char Version = 5;
unsigned int FakeStartCode = (Version << 8) | PES_VERSION_FAKE_START_CODE; unsigned int FakeStartCode = (Version << 8) | PES_VERSION_FAKE_START_CODE;
unsigned int usecPerFrame = 41708; /* Hellmaster1024: default value */ unsigned int usecPerFrame = 41708; /* Hellmaster1024: default value */
BitPacker_t ld = { FakeHeaders, 0, 32 }; 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 */ /* Create info record for frame parser */
/* divx4 & 5 /* divx4 & 5
VOS VOS
PutBits(&ld, 0x0, 8); PutBits(&ld, 0x0, 8);
PutBits(&ld, 0x0, 8); PutBits(&ld, 0x0, 8);
*/ */
PutBits(&ld, 0x1b0, 32); // startcode PutBits(&ld, 0x1b0, 32); // startcode
PutBits(&ld, 0, 8); // profile = reserved PutBits(&ld, 0, 8); // profile = reserved
PutBits(&ld, 0x1b2, 32); // startcode (user data) PutBits(&ld, 0x1b2, 32); // startcode (user data)
PutBits(&ld, 0x53545443, 32); // STTC - an embedded ST timecode from an avi file PutBits(&ld, 0x53545443, 32); // STTC - an embedded ST timecode from an avi file
PutBits(&ld, usecPerFrame, 32); PutBits(&ld, usecPerFrame, 32);
// microseconds per frame // microseconds per frame
FlushBits(&ld); FlushBits(&ld);
FakeHeaderLength = (ld.Ptr - (FakeHeaders)); FakeHeaderLength = (ld.Ptr - (FakeHeaders));
struct iovec iov[4]; struct iovec iov[4];
int ic = 0; int ic = 0;
iov[ic].iov_base = PesHeader; iov[ic].iov_base = PesHeader;
iov[ic++].iov_len = InsertPesHeader(PesHeader, packet->size, MPEG_VIDEO_PES_START_CODE, pts, FakeStartCode); iov[ic++].iov_len = InsertPesHeader(PesHeader, packet->size, MPEG_VIDEO_PES_START_CODE, pts, FakeStartCode);
iov[ic].iov_base = FakeHeaders; iov[ic].iov_base = FakeHeaders;
iov[ic++].iov_len = FakeHeaderLength; iov[ic++].iov_len = FakeHeaderLength;
if (initialHeader) { if (initialHeader) {
iov[ic].iov_base = stream->codec->extradata; iov[ic].iov_base = stream->codec->extradata;
iov[ic++].iov_len = stream->codec->extradata_size; iov[ic++].iov_len = stream->codec->extradata_size;
initialHeader = false;
}
iov[ic].iov_base = packet->data;
iov[ic++].iov_len = packet->size;
initialHeader = false; return writev(fd, iov, ic) > -1;
}
iov[ic].iov_base = packet->data;
iov[ic++].iov_len = packet->size;
return writev(fd, iov, ic) > -1;
} }
WriterDIVX::WriterDIVX() WriterDIVX::WriterDIVX()

View File

@@ -31,7 +31,7 @@
#include "writer.h" #include "writer.h"
#define PES_AUDIO_PRIVATE_HEADER_SIZE 16 // consider maximum private header size. #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 class WriterDTS : public Writer
{ {
@@ -45,33 +45,33 @@ bool WriterDTS::Write(int fd, AVFormatContext * /* avfc */, AVStream * /* stream
if (fd < 0 || !packet) if (fd < 0 || !packet)
return false; return false;
unsigned char PesHeader[PES_AUDIO_HEADER_SIZE]; unsigned char PesHeader[PES_AUDIO_HEADER_SIZE];
// #define DO_BYTESWAP // #define DO_BYTESWAP
#ifdef DO_BYTESWAP #ifdef DO_BYTESWAP
unsigned char Data[packet->size]; unsigned char Data[packet->size];
memcpy(Data, packet->data, packet->size); memcpy(Data, packet->data, packet->size);
/* 16-bit byte swap all data before injecting it */ /* 16-bit byte swap all data before injecting it */
for (i = 0; i < packet->size; i += 2) { for (i = 0; i < packet->size; i += 2) {
unsigned char Tmp = Data[i]; unsigned char Tmp = Data[i];
Data[i] = Data[i + 1]; Data[i] = Data[i + 1];
Data[i + 1] = Tmp; Data[i + 1] = Tmp;
} }
#endif #endif
struct iovec iov[2]; struct iovec iov[2];
iov[0].iov_base = PesHeader; 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_len = InsertPesHeader(PesHeader, packet->size, MPEG_AUDIO_PES_START_CODE /*PRIVATE_STREAM_1_PES_START_CODE */ , pts, 0);
#ifdef DO_BYTESPWAP #ifdef DO_BYTESPWAP
iov[1].iov_base = Data; iov[1].iov_base = Data;
#else #else
iov[1].iov_base = packet->data; iov[1].iov_base = packet->data;
#endif #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() WriterDTS::WriterDTS()

View File

@@ -42,15 +42,15 @@ bool WriterFLAC::Write(int fd, AVFormatContext * /* avfc */, AVStream * /* strea
if (fd < 0 || !packet) if (fd < 0 || !packet)
return -1; return -1;
unsigned char PesHeader[PES_MAX_HEADER_SIZE]; unsigned char PesHeader[PES_MAX_HEADER_SIZE];
struct iovec iov[2]; struct iovec iov[2];
iov[0].iov_base = PesHeader; iov[0].iov_base = PesHeader;
iov[0].iov_len = InsertPesHeader(PesHeader, packet->size, MPEG_AUDIO_PES_START_CODE, pts, 0); iov[0].iov_len = InsertPesHeader(PesHeader, packet->size, MPEG_AUDIO_PES_START_CODE, pts, 0);
iov[1].iov_base = packet->data; iov[1].iov_base = packet->data;
iov[1].iov_len = packet->size; iov[1].iov_len = packet->size;
return writev(fd, iov, 2) > -1; return writev(fd, iov, 2) > -1;
} }
WriterFLAC::WriterFLAC() WriterFLAC::WriterFLAC()

View File

@@ -39,27 +39,27 @@ bool WriterH263::Write(int fd, AVFormatContext * /* avfc */, AVStream * /* strea
{ {
if (fd < 0 || !packet) if (fd < 0 || !packet)
return false; 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_0] = PesLength & 0xff;
PesHeader[PES_LENGTH_BYTE_1] = (PesLength >> 8) & 0xff; PesHeader[PES_LENGTH_BYTE_1] = (PesLength >> 8) & 0xff;
PesHeader[PES_HEADER_DATA_LENGTH_BYTE] += PrivateHeaderLength; PesHeader[PES_HEADER_DATA_LENGTH_BYTE] += PrivateHeaderLength;
PesHeader[PES_FLAGS_BYTE] |= PES_EXTENSION_DATA_PRESENT; PesHeader[PES_FLAGS_BYTE] |= PES_EXTENSION_DATA_PRESENT;
HeaderLength += PrivateHeaderLength; HeaderLength += PrivateHeaderLength;
struct iovec iov[2]; struct iovec iov[2];
iov[0].iov_base = PesHeader; iov[0].iov_base = PesHeader;
iov[0].iov_len = HeaderLength; iov[0].iov_len = HeaderLength;
iov[1].iov_base = packet->data; iov[1].iov_base = packet->data;
iov[1].iov_len = packet->size; iov[1].iov_len = packet->size;
return writev(fd, iov, 2) > -1; return writev(fd, iov, 2) > -1;
} }
WriterH263::WriterH263() WriterH263::WriterH263()

View File

@@ -31,17 +31,17 @@
#include "pes.h" #include "pes.h"
#include "writer.h" #include "writer.h"
#define NALU_TYPE_PLAYER2_CONTAINER_PARAMETERS 24 #define NALU_TYPE_PLAYER2_CONTAINER_PARAMETERS 24
#define CONTAINER_PARAMETERS_VERSION 0x00 #define CONTAINER_PARAMETERS_VERSION 0x00
typedef struct avcC_s { typedef struct avcC_s {
unsigned char Version; /* configurationVersion */ unsigned char Version; // configurationVersion
unsigned char Profile; /* AVCProfileIndication */ unsigned char Profile; // AVCProfileIndication
unsigned char Compatibility; /* profile_compatibility */ unsigned char Compatibility; // profile_compatibility
unsigned char Level; /* AVCLevelIndication */ unsigned char Level; // AVCLevelIndication
unsigned char NalLengthMinusOne; /* held in bottom two bits */ unsigned char NalLengthMinusOne; // held in bottom two bits
unsigned char NumParamSets; /* held in bottom 5 bits */ unsigned char NumParamSets; // held in bottom 5 bits
unsigned char Params[1]; /* {length,params}{length,params}...sequence then picture */ unsigned char Params[1]; // {length,params}{length,params}...sequence then picture
} avcC_t; } avcC_t;
const unsigned char Head[] = { 0, 0, 0, 1 }; 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) if (fd < 0 || !packet)
return false; return false;
unsigned char PesHeader[PES_MAX_HEADER_SIZE]; unsigned char PesHeader[PES_MAX_HEADER_SIZE];
unsigned long long int VideoPts; unsigned long long int VideoPts;
unsigned int TimeDelta; unsigned int TimeDelta;
unsigned int TimeScale; unsigned int TimeScale;
int len = 0; int len = 0;
int ic = 0; int ic = 0;
struct iovec iov[128]; struct iovec iov[128];
TimeDelta = 1000.0 * av_q2d(stream->r_frame_rate); /* rational to double */ TimeDelta = 1000.0 * av_q2d(stream->r_frame_rate); /* rational to double */
TimeScale = (TimeDelta < 23970) ? 1001 : 1000; /* fixme: revise this */ TimeScale = (TimeDelta < 23970) ? 1001 : 1000; /* fixme: revise this */
VideoPts = pts; 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) { if (initialHeader) {
initialHeader = false; avcC_t *avcCHeader = (avcC_t *) stream->codec->extradata;
iov[ic].iov_base = stream->codec->extradata; unsigned int i;
iov[ic++].iov_len = stream->codec->extradata_size; unsigned int ParamSets;
PacketLength += stream->codec->extradata_size; unsigned int ParamOffset;
} unsigned int InitialHeaderLength = 0;
iov[ic].iov_base = packet->data; unsigned int ParametersLength;
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) { if (avcCHeader == NULL) {
avcC_t *avcCHeader = (avcC_t *) stream->codec->extradata; fprintf(stderr, "stream->codec->extradata == NULL\n");
unsigned int i; return false;
unsigned int ParamSets; }
unsigned int ParamOffset;
unsigned int InitialHeaderLength = 0;
unsigned int ParametersLength;
if (avcCHeader == NULL) { if (avcCHeader->Version != 1)
fprintf(stderr, "stream->codec->extradata == NULL\n"); fprintf(stderr, "Error unknown avcC version (%x). Expect problems.\n", avcCHeader->Version);
return false;
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) unsigned int SampleSize = packet->size;
fprintf(stderr, "Error unknown avcC version (%x). Expect problems.\n", avcCHeader->Version); 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]; memcpy(NalData, packet->data + VideoPosition, NalLengthBytes);
HeaderData[ParametersLength++] = 0x00; // Start code VideoPosition += NalLengthBytes;
HeaderData[ParametersLength++] = 0x00; NalStart += NalLengthBytes;
HeaderData[ParametersLength++] = 0x01; switch (NalLengthBytes) {
HeaderData[ParametersLength++] = case 1:
NALU_TYPE_PLAYER2_CONTAINER_PARAMETERS; NalLength = (NalData[0]);
// Container message version - changes when/if we vary the format of the message break;
HeaderData[ParametersLength++] = CONTAINER_PARAMETERS_VERSION; case 2:
HeaderData[ParametersLength++] = 0xff; // Field separator 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) if (NalStart + NalLength > SampleSize) {
TimeDelta = (TimeScale > 1000) ? 1001 : 1; 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 if (NalPresent) {
HeaderData[ParametersLength++] = (TimeScale >> 16) & 0xff; NalPresent = 0;
HeaderData[ParametersLength++] = 0xff; iov[ic].iov_base = (char *) Head;
HeaderData[ParametersLength++] = (TimeScale >> 8) & 0xff; iov[ic++].iov_len = sizeof(Head);
HeaderData[ParametersLength++] = TimeScale & 0xff; }
HeaderData[ParametersLength++] = 0xff;
HeaderData[ParametersLength++] = (TimeDelta >> 24) & 0xff; // Output frame period iov[ic].iov_base = packet->data + VideoPosition;
HeaderData[ParametersLength++] = (TimeDelta >> 16) & 0xff; iov[ic++].iov_len = NalLength;
HeaderData[ParametersLength++] = 0xff; VideoPosition += NalLength;
HeaderData[ParametersLength++] = (TimeDelta >> 8) & 0xff;
HeaderData[ParametersLength++] = TimeDelta & 0xff;
HeaderData[ParametersLength++] = 0xff;
HeaderData[ParametersLength++] = 0x80; // Rsbp trailing bits
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; VideoPts = INVALID_PTS_VALUE;
iov[ic].iov_base = PesHeader; }
iov[ic++].iov_len = InsertPesHeader(PesHeader, ParametersLength, MPEG_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0); } while (NalStart < SampleSize);
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; return len > -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() WriterH264::WriterH264()

View File

@@ -24,66 +24,65 @@
#include <sys/types.h> #include <sys/types.h>
#include <memory.h> #include <memory.h>
#include <asm/types.h> #include <asm/types.h>
#include <pthread.h>
#include <errno.h> #include <errno.h>
#include "misc.h" #include "misc.h"
void PutBits(BitPacker_t * ld, unsigned int code, unsigned int length) void PutBits(BitPacker_t * ld, unsigned int code, unsigned int length)
{ {
unsigned int bit_buf; unsigned int bit_buf;
unsigned int bit_left; unsigned int bit_left;
bit_buf = ld->BitBuffer; bit_buf = ld->BitBuffer;
bit_left = ld->Remaining; bit_left = ld->Remaining;
#ifdef DEBUG_PUTBITS #ifdef DEBUG_PUTBITS
if (ld->debug) if (ld->debug)
dprintf("code = %d, length = %d, bit_buf = 0x%x, bit_left = %d\n", dprintf("code = %d, length = %d, bit_buf = 0x%x, bit_left = %d\n",
code, length, bit_buf, bit_left); code, length, bit_buf, bit_left);
#endif /* DEBUG_PUTBITS */ #endif /* DEBUG_PUTBITS */
if (length < bit_left) { if (length < bit_left) {
/* fits into current buffer */ /* fits into current buffer */
bit_buf = (bit_buf << length) | code; bit_buf = (bit_buf << length) | code;
bit_left -= length; bit_left -= length;
} else { } else {
/* doesn't fit */ /* doesn't fit */
bit_buf <<= bit_left; bit_buf <<= bit_left;
bit_buf |= code >> (length - bit_left); bit_buf |= code >> (length - bit_left);
ld->Ptr[0] = (char) (bit_buf >> 24); ld->Ptr[0] = (char) (bit_buf >> 24);
ld->Ptr[1] = (char) (bit_buf >> 16); ld->Ptr[1] = (char) (bit_buf >> 16);
ld->Ptr[2] = (char) (bit_buf >> 8); ld->Ptr[2] = (char) (bit_buf >> 8);
ld->Ptr[3] = (char) bit_buf; ld->Ptr[3] = (char) bit_buf;
ld->Ptr += 4; ld->Ptr += 4;
length -= bit_left; length -= bit_left;
bit_buf = code & ((1 << length) - 1); bit_buf = code & ((1 << length) - 1);
bit_left = 32 - length; bit_left = 32 - length;
bit_buf = code; bit_buf = code;
} }
#ifdef DEBUG_PUTBITS #ifdef DEBUG_PUTBITS
if (ld->debug) if (ld->debug)
dprintf("bit_left = %d, bit_buf = 0x%x\n", bit_left, bit_buf); dprintf("bit_left = %d, bit_buf = 0x%x\n", bit_left, bit_buf);
#endif /* DEBUG_PUTBITS */ #endif /* DEBUG_PUTBITS */
/* writeback */ /* writeback */
ld->BitBuffer = bit_buf; ld->BitBuffer = bit_buf;
ld->Remaining = bit_left; ld->Remaining = bit_left;
} }
void FlushBits(BitPacker_t * ld) void FlushBits(BitPacker_t * ld)
{ {
ld->BitBuffer <<= ld->Remaining; ld->BitBuffer <<= ld->Remaining;
while (ld->Remaining < 32) { while (ld->Remaining < 32) {
#ifdef DEBUG_PUTBITS #ifdef DEBUG_PUTBITS
if (ld->debug) if (ld->debug)
dprintf("flushing 0x%2.2x\n", ld->BitBuffer >> 24); dprintf("flushing 0x%2.2x\n", ld->BitBuffer >> 24);
#endif /* DEBUG_PUTBITS */ #endif /* DEBUG_PUTBITS */
*ld->Ptr++ = ld->BitBuffer >> 24; *ld->Ptr++ = ld->BitBuffer >> 24;
ld->BitBuffer <<= 8; ld->BitBuffer <<= 8;
ld->Remaining += 8; ld->Remaining += 8;
} }
ld->Remaining = 32; ld->Remaining = 32;
ld->BitBuffer = 0; ld->BitBuffer = 0;
} }

View File

@@ -42,15 +42,15 @@ bool WriterMP3::Write(int fd, AVFormatContext * /* avfc */, AVStream * /* stream
if (fd < 0 || !packet) if (fd < 0 || !packet)
return false; return false;
unsigned char PesHeader[PES_MAX_HEADER_SIZE]; unsigned char PesHeader[PES_MAX_HEADER_SIZE];
struct iovec iov[2]; struct iovec iov[2];
iov[0].iov_base = PesHeader; iov[0].iov_base = PesHeader;
iov[0].iov_len = InsertPesHeader(PesHeader, packet->size, MPEG_AUDIO_PES_START_CODE, pts, 0); iov[0].iov_len = InsertPesHeader(PesHeader, packet->size, MPEG_AUDIO_PES_START_CODE, pts, 0);
iov[1].iov_base = packet->data; iov[1].iov_base = packet->data;
iov[1].iov_len = packet->size; iov[1].iov_len = packet->size;
return writev(fd, iov, 2) > -1; return writev(fd, iov, 2) > -1;
} }
WriterMP3::WriterMP3() WriterMP3::WriterMP3()

View File

@@ -83,150 +83,149 @@ class WriterPCM : public Writer
bool WriterPCM::prepareClipPlay() bool WriterPCM::prepareClipPlay()
{ {
SubFrameLen = 0; SubFrameLen = 0;
SubFramesPerPES = 0; SubFramesPerPES = 0;
breakBufferFillSize = 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 // figure out size of subframe and set up sample rate
switch (uSampleRate) { switch (uSampleRate) {
case 48000: case 48000:
SubFrameLen = 40; SubFrameLen = 40;
break; break;
case 96000: case 96000:
lpcm_prv[8] |= 0x10; lpcm_prv[8] |= 0x10;
SubFrameLen = 80; SubFrameLen = 80;
break; break;
case 192000: case 192000:
lpcm_prv[8] |= 0x20; lpcm_prv[8] |= 0x20;
SubFrameLen = 160; SubFrameLen = 160;
break; break;
case 44100: case 44100:
lpcm_prv[8] |= 0x80; lpcm_prv[8] |= 0x80;
SubFrameLen = 40; SubFrameLen = 40;
break; break;
case 88200: case 88200:
lpcm_prv[8] |= 0x90; lpcm_prv[8] |= 0x90;
SubFrameLen = 80; SubFrameLen = 80;
break; break;
case 176400: case 176400:
lpcm_prv[8] |= 0xA0; lpcm_prv[8] |= 0xA0;
SubFrameLen = 160; SubFrameLen = 160;
break; break;
default: default:
break; break;
} }
SubFrameLen *= uNoOfChannels; SubFrameLen *= uNoOfChannels;
SubFrameLen *= (uBitsPerSample / 8); SubFrameLen *= (uBitsPerSample / 8);
//rewrite PES size to have as many complete subframes per PES as we can //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. // 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; SubFramesPerPES = ((2048 - 18) - sizeof(lpcm_prv)) / SubFrameLen;
SubFrameLen *= SubFramesPerPES; SubFrameLen *= SubFramesPerPES;
//set number of channels //set number of channels
lpcm_prv[10] = uNoOfChannels - 1; lpcm_prv[10] = uNoOfChannels - 1;
switch (uBitsPerSample) { switch (uBitsPerSample) {
case 24: case 24:
lpcm_prv[7] |= 0x20; lpcm_prv[7] |= 0x20;
case 16: case 16:
break; break;
default: default:
printf("inappropriate bits per sample (%d) - must be 16 or 24\n", uBitsPerSample); printf("inappropriate bits per sample (%d) - must be 16 or 24\n", uBitsPerSample);
return false; return false;
} }
return true; return true;
} }
int WriterPCM::writePCM(int fd, int64_t Pts, uint8_t *data, unsigned int size) 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) { if (initialHeader) {
initialHeader = false; initialHeader = false;
prepareClipPlay(); prepareClipPlay();
} }
unsigned int n; unsigned int n;
unsigned char *injectBuffer = (unsigned char *) malloc(SubFrameLen); unsigned char *injectBuffer = (unsigned char *) malloc(SubFrameLen);
unsigned int pos; unsigned int pos;
for (pos = 0; pos < size;) { for (pos = 0; pos < size;) {
//printf("PCM %s - Position=%d\n", __FUNCTION__, pos); //printf("PCM %s - Position=%d\n", __FUNCTION__, pos);
if ((size - pos) < SubFrameLen) { if ((size - pos) < SubFrameLen) {
breakBufferFillSize = size - pos; breakBufferFillSize = size - pos;
memcpy(breakBuffer, &data[pos], memcpy(breakBuffer, &data[pos], sizeof(unsigned char) * breakBufferFillSize);
sizeof(unsigned char) * breakBufferFillSize); //printf("PCM %s - Unplayed=%d\n", __FUNCTION__, breakBufferFillSize);
//printf("PCM %s - Unplayed=%d\n", __FUNCTION__, breakBufferFillSize); break;
break; }
} //get first PES's worth
//get first PES's worth if (breakBufferFillSize > 0) {
if (breakBufferFillSize > 0) { memcpy(injectBuffer, breakBuffer, sizeof(unsigned char) * breakBufferFillSize);
memcpy(injectBuffer, breakBuffer, sizeof(unsigned char) * breakBufferFillSize); memcpy(&injectBuffer[breakBufferFillSize], &data[pos], sizeof(unsigned char) * (SubFrameLen - breakBufferFillSize));
memcpy(&injectBuffer[breakBufferFillSize], &data[pos], sizeof(unsigned char) * (SubFrameLen - breakBufferFillSize)); pos += (SubFrameLen - breakBufferFillSize);
pos += (SubFrameLen - breakBufferFillSize); breakBufferFillSize = 0;
breakBufferFillSize = 0; } else {
} else { memcpy(injectBuffer, &data[pos], sizeof(unsigned char) * SubFrameLen);
memcpy(injectBuffer, &data[pos], sizeof(unsigned char) * SubFrameLen); pos += 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]; return size;
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() void WriterPCM::Init()
{ {
initialHeader = true; initialHeader = true;
restart_audio_resampling = true; restart_audio_resampling = true;
} }
extern int64_t calcPts(AVFormatContext *, AVStream *, int64_t); extern int64_t calcPts(AVFormatContext *, AVStream *, int64_t);
@@ -237,7 +236,6 @@ bool WriterPCM::Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket
return false; return false;
if (!packet) { if (!packet) {
fprintf(stderr, "%s %s %d\n", __FILE__, __func__, __LINE__);
restart_audio_resampling = true; restart_audio_resampling = true;
return true; return true;
} }
@@ -246,18 +244,13 @@ fprintf(stderr, "%s %s %d\n", __FILE__, __func__, __LINE__);
unsigned int packet_size = packet->size; unsigned int packet_size = packet->size;
if (restart_audio_resampling) { if (restart_audio_resampling) {
fprintf(stderr, "%s %s %d\n", __FILE__, __func__, __LINE__);
restart_audio_resampling = false; restart_audio_resampling = false;
initialHeader = true; initialHeader = true;
if (swr) { if (swr)
swr_free(&swr); swr_free(&swr);
swr = NULL; //FIXME: Needed? if (decoded_frame)
}
if (decoded_frame) {
av_frame_free(&decoded_frame); av_frame_free(&decoded_frame);
decoded_frame = NULL; //FIXME: Needed?
}
AVCodec *codec = avcodec_find_decoder(c->codec_id); 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); int len = avcodec_decode_audio4(c, decoded_frame, &got_frame, packet);
if (len < 0) { if (len < 0) {
fprintf(stderr, "%s %s %d\n", __FILE__, __func__, __LINE__);
restart_audio_resampling = true; restart_audio_resampling = true;
break; break;
} }
@@ -317,12 +309,10 @@ fprintf(stderr, "%s %s %d\n", __FILE__, __func__, __LINE__);
e = swr_init(swr); e = swr_init(swr);
if (e < 0) { if (e < 0) {
fprintf(stderr, fprintf(stderr, "swr_init: %d (icl=%d ocl=%d isr=%d osr=%d isf=%d osf=%d\n",
"swr_init: %d (icl=%d ocl=%d isr=%d osr=%d isf=%d osf=%d\n",
-e, (int) c->channel_layout, -e, (int) c->channel_layout,
(int) out_channel_layout, c->sample_rate, out_sample_rate, c->sample_fmt, AV_SAMPLE_FMT_S16); (int) out_channel_layout, c->sample_rate, out_sample_rate, c->sample_fmt, AV_SAMPLE_FMT_S16);
swr_free(&swr); swr_free(&swr);
swr = NULL;
} }
} }
@@ -365,7 +355,7 @@ WriterPCM::WriterPCM()
out_channel_layout = AV_CH_LAYOUT_STEREO; out_channel_layout = AV_CH_LAYOUT_STEREO;
restart_audio_resampling = true; 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))); static WriterPCM writer_pcm __attribute__ ((init_priority (300)));

View File

@@ -27,44 +27,11 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h>
#include <sys/types.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 <memory.h>
#include <asm/types.h> #include <asm/types.h>
#include <pthread.h>
#include <errno.h>
#include "player.h"
#include "output.h"
#include "misc.h" #include "misc.h"
#include "pes.h" #include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* Functions */
/* ***************************** */
int InsertVideoPrivateDataHeader(unsigned char *data, int payload_size) 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) if (fd < 0 || !packet)
return false; return false;
if (initialHeader) { if (initialHeader) {
initialHeader = false; initialHeader = false;
FrameHeaderSeen = false; FrameHeaderSeen = false;
@@ -74,15 +74,15 @@ bool WriterVC1::Write(int fd, AVFormatContext *avfc, AVStream *stream, AVPacket
const unsigned char Metadata[] = { const unsigned char Metadata[] = {
0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0xc5,
0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0xc0, 0x00, 0x00, 0x00, /* Struct C set for for advanced profile */ 0xc0, 0x00, 0x00, 0x00, /* Struct C set for for advanced profile */
0x00, 0x00, 0x00, 0x00, /* Struct A */ 0x00, 0x00, 0x00, 0x00, /* Struct A */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x60, 0x00, 0x00, 0x00, /* Struct B */ 0x60, 0x00, 0x00, 0x00, /* Struct B */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00
}; };
unsigned char PesHeader[PES_MAX_HEADER_SIZE]; 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)); memcpy(&PesHeader[HeaderLength], Vc1FrameStartCode, sizeof(Vc1FrameStartCode));
HeaderLength += sizeof(Vc1FrameStartCode); HeaderLength += sizeof(Vc1FrameStartCode);
} }
insertSampleHeader = 0; insertSampleHeader = 0;
} }
struct iovec iov[2]; struct iovec iov[2];

View File

@@ -33,22 +33,22 @@
#include <algorithm> #include <algorithm>
#define WMV3_PRIVATE_DATA_LENGTH 4 #define WMV3_PRIVATE_DATA_LENGTH 4
static const unsigned char Metadata[] = { static const unsigned char Metadata[] = {
0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0xc5,
0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
#define METADATA_STRUCT_C_START 8 #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 #define METADATA_STRUCT_A_START 12
0x00, 0x00, 0x00, 0x00, /* Struct A */ 0x00, 0x00, 0x00, 0x00, /* Struct A */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
#define METADATA_STRUCT_B_START 24 #define METADATA_STRUCT_B_START 24
0x60, 0x00, 0x00, 0x00, /* Struct B */ 0x60, 0x00, 0x00, 0x00, /* Struct B */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#define METADATA_STRUCT_B_FRAMERATE_START 32 #define METADATA_STRUCT_B_FRAMERATE_START 32
0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00
}; };
class WriterWMV : public Writer class WriterWMV : public Writer
@@ -63,7 +63,7 @@ class WriterWMV : public Writer
void WriterWMV::Init() void WriterWMV::Init()
{ {
initialHeader = 1; initialHeader = 1;
} }
bool WriterWMV::Write(int fd, AVFormatContext * /* avfc */, AVStream *stream, AVPacket *packet, int64_t &pts) 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) if (fd < 0 || !packet)
return false; return false;
if (initialHeader) { if (initialHeader) {
#define PES_MIN_HEADER_SIZE 9 #define PES_MIN_HEADER_SIZE 9
unsigned char PesPacket[PES_MIN_HEADER_SIZE + 128]; unsigned char PesPacket[PES_MIN_HEADER_SIZE + 128];
unsigned char *PesPtr; unsigned char *PesPtr;
unsigned int MetadataLength; unsigned int MetadataLength;
unsigned int usecPerFrame = ((10000000.0 / av_q2d(stream->r_frame_rate))); 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)); memcpy(PesPtr, Metadata, sizeof(Metadata));
PesPtr += METADATA_STRUCT_C_START; PesPtr += METADATA_STRUCT_C_START;
unsigned char privateData[WMV3_PRIVATE_DATA_LENGTH] = { 0 }; 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(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); memcpy(PesPtr, privateData, WMV3_PRIVATE_DATA_LENGTH);
PesPtr += WMV3_PRIVATE_DATA_LENGTH; PesPtr += WMV3_PRIVATE_DATA_LENGTH;
/* Metadata Header Struct A */ /* Metadata Header Struct A */
*PesPtr++ = (stream->codec->height >> 0) & 0xff; *PesPtr++ = (stream->codec->height >> 0) & 0xff;
*PesPtr++ = (stream->codec->height >> 8) & 0xff; *PesPtr++ = (stream->codec->height >> 8) & 0xff;
*PesPtr++ = (stream->codec->height >> 16) & 0xff; *PesPtr++ = (stream->codec->height >> 16) & 0xff;
*PesPtr++ = stream->codec->height >> 24; *PesPtr++ = stream->codec->height >> 24;
*PesPtr++ = (stream->codec->width >> 0) & 0xff; *PesPtr++ = (stream->codec->width >> 0) & 0xff;
*PesPtr++ = (stream->codec->width >> 8) & 0xff; *PesPtr++ = (stream->codec->width >> 8) & 0xff;
*PesPtr++ = (stream->codec->width >> 16) & 0xff; *PesPtr++ = (stream->codec->width >> 16) & 0xff;
*PesPtr++ = stream->codec->width >> 24; *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 >> 0) & 0xff;
*PesPtr++ = (usecPerFrame >> 8) & 0xff; *PesPtr++ = (usecPerFrame >> 8) & 0xff;
*PesPtr++ = (usecPerFrame >> 16) & 0xff; *PesPtr++ = (usecPerFrame >> 16) & 0xff;
*PesPtr++ = usecPerFrame >> 24; *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) if (write(fd, PesPacket, HeaderLength + MetadataLength) < 0)
return false; return false;
initialHeader = 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; 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() WriterWMV::WriterWMV()