mirror of
https://github.com/tuxbox-neutrino/libstb-hal.git
synced 2025-08-26 23:13:16 +02:00
libeplayer3: cleanups
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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>
|
||||||
|
@@ -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)
|
||||||
|
@@ -17,10 +17,6 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ***************************** */
|
|
||||||
/* Includes */
|
|
||||||
/* ***************************** */
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "manager.h"
|
#include "manager.h"
|
||||||
|
@@ -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);
|
||||||
|
@@ -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)
|
||||||
|
@@ -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()
|
||||||
|
@@ -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()
|
||||||
|
@@ -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()
|
||||||
|
@@ -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()
|
||||||
|
@@ -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()
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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()
|
||||||
|
@@ -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)));
|
||||||
|
@@ -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)
|
||||||
{
|
{
|
||||||
|
@@ -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];
|
||||||
|
@@ -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()
|
||||||
|
Reference in New Issue
Block a user