mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-06-13 22:04:36 -06:00
Packages moved to archive/bazaar
git-svn-id: svn://ultimatepp.org/upp/trunk@11633 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
70ee1b1b3f
commit
1718274ff1
38 changed files with 0 additions and 22088 deletions
|
|
@ -1,49 +0,0 @@
|
|||
description "Audio and video managing\377";
|
||||
|
||||
uses
|
||||
CtrlLib,
|
||||
SDL;
|
||||
|
||||
library(MSC) "avcodec.lib avformat.lib avutil.lib swscale.lib avdevice.lib avcore.lib";
|
||||
|
||||
library(GCC WIN32) "avcodec avformat avutil swscale avdevice avcore";
|
||||
|
||||
library(POSIX) "avutil avcodec avformat avdevice swscale";
|
||||
|
||||
link(MSC) /FORCE:MULTIPLE;
|
||||
|
||||
link(GCC WIN32) "-Wl,--allow-multiple-definition";
|
||||
|
||||
file
|
||||
MediaPlayer readonly separator,
|
||||
MediaPlayer.cpp,
|
||||
MediaPlayer.h,
|
||||
threads.cpp,
|
||||
mediaplayer_in.h,
|
||||
MediaPlayer.usc,
|
||||
MediaPlayer.iml,
|
||||
MediaFile readonly separator,
|
||||
MediaFile.cpp,
|
||||
MediaFile.h,
|
||||
PacketQueue.cpp,
|
||||
clock.cpp,
|
||||
VolumeCtrl readonly separator,
|
||||
VolumeCtrl.cpp,
|
||||
VolumeCtrl.h,
|
||||
VolumeCtrl.usc,
|
||||
"Utility functions" readonly separator,
|
||||
utility_file.cpp,
|
||||
utility_stream.cpp,
|
||||
utility_codec.cpp,
|
||||
utility.cpp,
|
||||
utility.h,
|
||||
ffmpeg_base.h,
|
||||
audioSystem.cpp,
|
||||
audioSystem.h,
|
||||
mt.h,
|
||||
ubuntu.cpp,
|
||||
srcdoc.tpp;
|
||||
|
||||
mainconfig
|
||||
"" = "GUI";
|
||||
|
||||
|
|
@ -1,658 +0,0 @@
|
|||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#include "MediaFile.h"
|
||||
#include "utility.h"
|
||||
|
||||
|
||||
MediaFile::MediaFile() {
|
||||
avcodec_register_all(); // Register all codecs, demux and protocols
|
||||
avdevice_register_all();
|
||||
//avfilter_register_all();
|
||||
av_register_all();
|
||||
|
||||
av_log_set_callback(AvLogCallback);
|
||||
|
||||
videoq.SetMaxSize(MAX_VIDEOQ_SIZE);
|
||||
audioq.SetMaxSize(MAX_AUDIOQ_SIZE);
|
||||
subtitleq.SetMaxSize(MAX_SUBTITLEQ_SIZE);
|
||||
|
||||
threadCount = 1;
|
||||
fileData = 0;
|
||||
|
||||
requestAbort = paused = seek_req = false;
|
||||
last_paused = seek_flags = 0;
|
||||
seek_pos = seek_rel = 0;
|
||||
showAudioFps = 25;
|
||||
rgb = false;
|
||||
forceAspect = true;
|
||||
audioFactor = 1000;
|
||||
imgRect.Clear();
|
||||
}
|
||||
|
||||
MediaFile::~MediaFile() {
|
||||
if (fileData) {
|
||||
av_close_input_file(fileData);
|
||||
fileData = NULL; /* safety */
|
||||
}
|
||||
//SDL_DestroyMutex(pictq_mutex);
|
||||
//SDL_DestroyCond(pictq_cond);
|
||||
//SDL_DestroyMutex(subpq_mutex);
|
||||
//SDL_DestroyCond(subpq_cond);
|
||||
}
|
||||
|
||||
void MediaFile::Reset() {
|
||||
numVideoStreams = numAudioStreams = 0;
|
||||
videoData.Clear();
|
||||
audioData.Clear();
|
||||
|
||||
second = 0;
|
||||
lastSecond = -1;
|
||||
|
||||
audio_disable = video_disable = false;
|
||||
seek_by_bytes = false;
|
||||
|
||||
audioq.Init();
|
||||
videoq.Init();
|
||||
subtitleq.Init();
|
||||
|
||||
memset(&flush_pkt, 0, sizeof(flush_pkt));
|
||||
av_init_packet(&flush_pkt);
|
||||
flush_pkt.data = (uint8_t *)"FLUSH";
|
||||
|
||||
//pictq_mutex = SDL_CreateMutex();
|
||||
//pictq_cond = SDL_CreateCond();
|
||||
memset(&pictq, 0, sizeof(pictq));
|
||||
pictq_size = pictq_rindex = pictq_windex = 0;
|
||||
|
||||
//subpq_mutex = SDL_CreateMutex();
|
||||
//subpq_cond = SDL_CreateCond();
|
||||
memset(&subpq, 0, sizeof(subpq));
|
||||
subpq_size = subpq_rindex = subpq_windex = 0;
|
||||
|
||||
audioStream = videoStream = subtitleStream = 0;
|
||||
idAudio = idVideo = idSubtitle = -1;
|
||||
|
||||
reformat_ctx = 0;
|
||||
|
||||
//decoderThreadId = video_tid = refresh_tid = subtitle_tid = 0;
|
||||
|
||||
subtitle_stream_changed = false;
|
||||
debug = debug_mv = 0;
|
||||
workaround_bugs = 1;
|
||||
fast = false;
|
||||
genpts = lowres = idct = 0;
|
||||
decoder_reorder_pts= -1;
|
||||
skip_frame = skip_idct = skip_loop_filter = AVDISCARD_DEFAULT;
|
||||
audio_callback_time = 0;
|
||||
audio_buf_size = 0;
|
||||
audio_buf_index = 0;
|
||||
audio_buf = 0;
|
||||
showAudio = true;
|
||||
sample_array_index = 0;
|
||||
|
||||
audio_clock = audio_diff_cum = audio_diff_avg_coef = audio_diff_threshold = 0;
|
||||
audio_diff_avg_count = 0;
|
||||
|
||||
audio_hw_buf_size = 0;
|
||||
|
||||
memset(&audio_pkt_temp, 0, sizeof(AVPacket));
|
||||
memset(&audio_pkt, 0, sizeof(AVPacket));
|
||||
|
||||
video_current_pts = 0;
|
||||
video_current_pts_time = video_current_pos = 0;
|
||||
|
||||
av_sync_type = 0;
|
||||
|
||||
frame_timer = 0;
|
||||
video_clock = 0;
|
||||
step = false;
|
||||
lastAudioShow = 0;
|
||||
|
||||
decodeThEnd = decodeThEnded = audioThEnd = videoThEnd = subtitleThEnd = true;
|
||||
}
|
||||
|
||||
int MediaFile::GetAudioId() {
|
||||
int id = GetAudio();
|
||||
for (int i = 0; i < audioData.GetCount(); ++i) {
|
||||
if (audioData[i].id == id)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void MediaFile::SetAudioId(int id) {
|
||||
if (id == -1)
|
||||
SetAudio(-1);
|
||||
else if (id < 0 || id >= audioData.GetCount())
|
||||
ASSERT(true);
|
||||
else
|
||||
SetAudio(audioData[id].id);
|
||||
}
|
||||
|
||||
int MediaFile::GetVideoId() {
|
||||
int id = GetVideo();
|
||||
for (int i = 0; i < videoData.GetCount(); ++i) {
|
||||
if (videoData[i].id == id)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void MediaFile::SetVideoId(int id) {
|
||||
if (id == -1)
|
||||
SetVideo(-1);
|
||||
else if (id < 0 || id >= videoData.GetCount())
|
||||
ASSERT(true);
|
||||
else
|
||||
SetVideo(videoData[id].id);
|
||||
}
|
||||
|
||||
void MediaFile::SetSecond(double sec) {
|
||||
if (sec < 0 || sec > GetDuration())
|
||||
return;
|
||||
|
||||
second = sec;
|
||||
lastSecond = -1;
|
||||
sec *= AV_TIME_BASE;
|
||||
if (fileData->start_time != AV_NOPTS_VALUE)
|
||||
sec += fileData->start_time;
|
||||
stream_seek(int64_t(sec), 0, false);
|
||||
}
|
||||
|
||||
int MediaFile::GetAudioOutputBufferSize() {
|
||||
return audio_buf_size - audio_buf_index;
|
||||
}
|
||||
|
||||
void MediaFile::stream_seek(int64_t pos, int64_t rel, bool seek_by_bytes)
|
||||
{
|
||||
if (!seek_req) {
|
||||
seek_pos = pos;
|
||||
seek_rel = rel;
|
||||
if (seek_by_bytes)
|
||||
seek_flags |= AVSEEK_FLAG_BYTE;
|
||||
else
|
||||
seek_flags &= ~AVSEEK_FLAG_BYTE;
|
||||
seek_req = true;
|
||||
}
|
||||
}
|
||||
|
||||
// open a given stream. Return 0 if OK
|
||||
bool MediaFile::StreamOpen(int stream_index)
|
||||
{
|
||||
SDL_AudioSpec wanted_spec, spec;
|
||||
|
||||
if (stream_index < 0 || unsigned(stream_index) >= fileData->nb_streams)
|
||||
return false;
|
||||
|
||||
AVCodecContext *avctx = fileData->streams[stream_index]->codec;
|
||||
|
||||
// prepare audio output
|
||||
if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||
if (avctx->channels > 0)
|
||||
avctx->request_channels = FFMIN(2, avctx->channels);
|
||||
else
|
||||
avctx->request_channels = 2;
|
||||
}
|
||||
|
||||
AVCodec *codec = avcodec_find_decoder(avctx->codec_id);
|
||||
avctx->debug_mv = debug_mv;
|
||||
avctx->debug = debug;
|
||||
avctx->workaround_bugs = workaround_bugs;
|
||||
avctx->lowres = lowres;
|
||||
if(lowres)
|
||||
avctx->flags |= CODEC_FLAG_EMU_EDGE;
|
||||
avctx->idct_algo= idct;
|
||||
if(fast)
|
||||
avctx->flags2 |= CODEC_FLAG2_FAST;
|
||||
avctx->skip_frame= skip_frame;
|
||||
avctx->skip_idct= skip_idct;
|
||||
avctx->skip_loop_filter= skip_loop_filter;
|
||||
|
||||
avcodec_thread_init(avctx, threadCount);
|
||||
if (!codec || avcodec_open(avctx, codec) < 0)
|
||||
return false;
|
||||
|
||||
// prepare audio output
|
||||
if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||
wanted_spec.freq = avctx->sample_rate;
|
||||
wanted_spec.format = AUDIO_S16SYS;
|
||||
wanted_spec.channels = avctx->channels;
|
||||
wanted_spec.silence = 0;
|
||||
wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
|
||||
wanted_spec.callback = sdl_audio_callback;
|
||||
wanted_spec.userdata = this;
|
||||
|
||||
if (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
|
||||
SetError(Format("SDL_OpenAudio: %s", SDL_GetError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
audio_hw_buf_size = spec.size;
|
||||
audio_src_fmt = SAMPLE_FMT_S16;
|
||||
}
|
||||
|
||||
fileData->streams[stream_index]->discard = AVDISCARD_DEFAULT;
|
||||
switch(avctx->codec_type) {
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
idAudio = stream_index;
|
||||
audioStream = fileData->streams[stream_index];
|
||||
audio_buf_size = 0;
|
||||
audio_buf_index = 0;
|
||||
|
||||
// init averaging filter
|
||||
audio_diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
|
||||
audio_diff_avg_count = 0;
|
||||
// since we do not have a precise enough audio fifo fullness,
|
||||
// we correct audio sync only if larger than this threshold
|
||||
audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / avctx->sample_rate;
|
||||
|
||||
memset(&audio_pkt, 0, sizeof(audio_pkt));
|
||||
|
||||
audioq.Init(flush_pkt, &flush_pkt);
|
||||
audioThEnd = false;
|
||||
SDL_PauseAudio(0);
|
||||
|
||||
break;
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
idVideo = stream_index;
|
||||
videoStream = fileData->streams[stream_index];
|
||||
|
||||
//frame_last_delay = 40e-3;
|
||||
frame_timer = (double)GetUSec() / 1000000.0;
|
||||
video_current_pts_time = GetUSec();
|
||||
|
||||
videoq.Init(flush_pkt, &flush_pkt);
|
||||
video_tid.Run(THISBACK(VideoThread));
|
||||
//video_tid = SDL_CreateThread(VideoThread, this);
|
||||
|
||||
break;
|
||||
case AVMEDIA_TYPE_SUBTITLE:
|
||||
idSubtitle = stream_index;
|
||||
subtitleStream = fileData->streams[stream_index];
|
||||
|
||||
subtitleq.Init(flush_pkt, &flush_pkt);
|
||||
subtitle_tid.Run(THISBACK(SubtitleThread));
|
||||
//subtitle_tid = SDL_CreateThread(SubtitleThread, this);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MediaFile::StreamClose(int stream_index)
|
||||
{
|
||||
if (stream_index < 0 || unsigned(stream_index) >= fileData->nb_streams)
|
||||
return;
|
||||
|
||||
AVCodecContext *avctx = fileData->streams[stream_index]->codec;
|
||||
|
||||
switch(avctx->codec_type) {
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
audioq.Abort();
|
||||
|
||||
SDL_CloseAudio();
|
||||
|
||||
audioq.End();
|
||||
if (reformat_ctx)
|
||||
av_audio_convert_free(reformat_ctx);
|
||||
reformat_ctx = NULL;
|
||||
break;
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
videoq.Abort();
|
||||
|
||||
// note: we also signal this mutex to make sure we deblock the video thread in all cases
|
||||
INTERLOCKED_(pictq_mutex) {
|
||||
pictq_cond.Signal();
|
||||
}
|
||||
|
||||
video_tid.Wait();
|
||||
|
||||
videoq.End();
|
||||
break;
|
||||
case AVMEDIA_TYPE_SUBTITLE:
|
||||
subtitleq.Abort();
|
||||
|
||||
// note: we also signal this mutex to make sure we deblock the video thread in all cases
|
||||
INTERLOCKED_(subpq_mutex) {
|
||||
subtitle_stream_changed = true;
|
||||
subpq_cond.Signal();
|
||||
}
|
||||
|
||||
subtitle_tid.Wait();
|
||||
|
||||
subtitleq.End();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
fileData->streams[stream_index]->discard = AVDISCARD_ALL;
|
||||
avcodec_close(avctx);
|
||||
switch(avctx->codec_type) {
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
audioStream = NULL;
|
||||
//idAudio = -1;
|
||||
break;
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
videoStream = NULL;
|
||||
//idVideo = -1;
|
||||
break;
|
||||
case AVMEDIA_TYPE_SUBTITLE:
|
||||
subtitleStream = NULL;
|
||||
//idSubtitle = -1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// THREAD
|
||||
/* decode one audio frame and returns its uncompressed size */
|
||||
int MediaFile::audio_decode_frame(double *pts_ptr)
|
||||
{
|
||||
AVPacket *pkt_temp = &audio_pkt_temp;
|
||||
AVPacket *pkt = &audio_pkt;
|
||||
AVCodecContext *dec= audioStream->codec;
|
||||
int n, len1, data_size;
|
||||
double pts;
|
||||
|
||||
for(;;) {
|
||||
// The audio packet can contain several frames
|
||||
while (pkt_temp->size > 0) {
|
||||
data_size = sizeof(audio_buf1);
|
||||
#if (((LIBAVCODEC_VERSION_MAJOR <= 52) && (LIBAVCODEC_VERSION_MINOR <= 20)) || UBUNTU_TRICK)
|
||||
len1 = avcodec_decode_audio2(dec, (int16_t *)audio_buf1, &data_size, pkt_temp->data,
|
||||
pkt_temp->size);
|
||||
#else
|
||||
len1 = avcodec_decode_audio3(dec, (int16_t *)audio_buf1, &data_size, pkt_temp);
|
||||
#endif
|
||||
|
||||
if (len1 < 0) {
|
||||
pkt_temp->size = 0; // if error, we skip the frame
|
||||
break;
|
||||
}
|
||||
pkt_temp->data += len1;
|
||||
pkt_temp->size -= len1;
|
||||
if (data_size <= 0)
|
||||
continue;
|
||||
|
||||
if (dec->sample_fmt != audio_src_fmt) {
|
||||
if (reformat_ctx)
|
||||
av_audio_convert_free(reformat_ctx);
|
||||
reformat_ctx= av_audio_convert_alloc(SAMPLE_FMT_S16, 1,
|
||||
dec->sample_fmt, 1, NULL, 0);
|
||||
if (!reformat_ctx) {
|
||||
SetError(Format("Cannot convert %s sample format to %s sample format\n",
|
||||
avcodec_get_sample_fmt_name(dec->sample_fmt),
|
||||
avcodec_get_sample_fmt_name(SAMPLE_FMT_S16)));
|
||||
break;
|
||||
}
|
||||
audio_src_fmt= dec->sample_fmt;
|
||||
}
|
||||
|
||||
if (reformat_ctx) {
|
||||
const void *ibuf[6]= {audio_buf1};
|
||||
void *obuf[6]= {audio_buf2};
|
||||
int istride[6]= {av_get_bits_per_sample_format(dec->sample_fmt)/8};
|
||||
int ostride[6]= {2};
|
||||
int len= data_size/istride[0];
|
||||
if (av_audio_convert(reformat_ctx, obuf, ostride, ibuf, istride, len)<0) {
|
||||
printf("av_audio_convert() failed\n");
|
||||
break;
|
||||
}
|
||||
audio_buf= audio_buf2;
|
||||
/* FIXME: existing code assume that data_size equals framesize*channels*2
|
||||
remove this legacy cruft */
|
||||
data_size= len*2;
|
||||
} else
|
||||
audio_buf= audio_buf1;
|
||||
|
||||
// if no pts, then compute it
|
||||
pts = audio_clock;
|
||||
*pts_ptr = pts;
|
||||
n = 2 * dec->channels;
|
||||
audio_clock += double(data_size) / double(n * dec->sample_rate);
|
||||
|
||||
return data_size;
|
||||
}
|
||||
|
||||
if (pkt->data) // free the current packet
|
||||
av_free_packet(pkt);
|
||||
|
||||
if (paused || audioq.IsAbort())
|
||||
return -1;
|
||||
|
||||
int ret = audioq.Get(pkt, decodeThEnd); // read next packet
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
if(pkt->data == flush_pkt.data){
|
||||
avcodec_flush_buffers(dec);
|
||||
continue;
|
||||
}
|
||||
|
||||
pkt_temp->data = pkt->data;
|
||||
pkt_temp->size = pkt->size;
|
||||
|
||||
if (pkt->pts != AV_NOPTS_VALUE) // if update the audio clock with the pts
|
||||
audio_clock = av_q2d(audioStream->time_base)*pkt->pts;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy samples for viewing in editor window
|
||||
void MediaFile::update_sample_display(short *samples, int samples_size) {
|
||||
int channels = audioStream->codec->channels;
|
||||
int size = samples_size / sizeof(short);
|
||||
while (size > 0) {
|
||||
int len = SAMPLE_ARRAY_SIZE - sample_array_index;
|
||||
if (len > size)
|
||||
len = size;
|
||||
memcpy(sample_array + sample_array_index, samples, len * sizeof(short));
|
||||
samples += len;
|
||||
sample_array_index += len;
|
||||
if (sample_array_index >= SAMPLE_ARRAY_SIZE)
|
||||
sample_array_index = 0;
|
||||
size -= len;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the new audio buffer size (samples can be added or deleted
|
||||
// to get better sync if video or external master clock)
|
||||
int MediaFile::synchronize_audio(short *samples, int samples_size1, double pts)
|
||||
{
|
||||
int n, samples_size;
|
||||
double ref_clock;
|
||||
|
||||
n = 2 * audioStream->codec->channels;
|
||||
samples_size = samples_size1;
|
||||
|
||||
/* if not master, then we try to remove or add samples to correct the clock */
|
||||
if (((av_sync_type == AV_SYNC_VIDEO_MASTER && videoStream) ||
|
||||
av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
|
||||
double diff, avg_diff;
|
||||
int wanted_size, min_size, max_size, nb_samples;
|
||||
|
||||
ref_clock = get_master_clock();
|
||||
diff = get_audio_clock() - ref_clock;
|
||||
|
||||
if (diff < AV_NOSYNC_THRESHOLD) {
|
||||
audio_diff_cum = diff + audio_diff_avg_coef * audio_diff_cum;
|
||||
if (audio_diff_avg_count < AUDIO_DIFF_AVG_NB)
|
||||
audio_diff_avg_count++; // not enough measures to have a correct estimate
|
||||
else {
|
||||
/* estimate the A-V difference */
|
||||
avg_diff = audio_diff_cum * (1.0 - audio_diff_avg_coef);
|
||||
|
||||
if (fabs(avg_diff) >= audio_diff_threshold) {
|
||||
wanted_size = samples_size + ((int)(diff * audioStream->codec->sample_rate) * n);
|
||||
nb_samples = samples_size / n;
|
||||
|
||||
min_size = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
|
||||
max_size = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
|
||||
if (wanted_size < min_size)
|
||||
wanted_size = min_size;
|
||||
else if (wanted_size > max_size)
|
||||
wanted_size = max_size;
|
||||
|
||||
/* add or remove samples to correction the synchro */
|
||||
if (wanted_size < samples_size) {
|
||||
/* remove samples */
|
||||
samples_size = wanted_size;
|
||||
} else if (wanted_size > samples_size) {
|
||||
uint8_t *samples_end, *q;
|
||||
int nb;
|
||||
|
||||
/* add samples */
|
||||
nb = (samples_size - wanted_size);
|
||||
samples_end = (uint8_t *)samples + samples_size - n;
|
||||
q = samples_end + n;
|
||||
while (nb > 0) {
|
||||
memcpy(q, samples_end, n);
|
||||
q += n;
|
||||
nb -= n;
|
||||
}
|
||||
samples_size = wanted_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Too big difference : may be initial PTS errors, so reset A-V filter
|
||||
audio_diff_avg_count = 0;
|
||||
audio_diff_cum = 0;
|
||||
}
|
||||
}
|
||||
return samples_size;
|
||||
}
|
||||
|
||||
// Called by VideoThread to store the just decoded frame
|
||||
bool MediaFile::queue_picture(AVFrame *frame, double pts) {
|
||||
// wait until we have space to put a new picture
|
||||
INTERLOCKED_(pictq_mutex) {
|
||||
while (pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && !videoq.IsAbort())
|
||||
pictq_cond.Wait(pictq_mutex);
|
||||
}
|
||||
|
||||
if (videoq.IsAbort())
|
||||
return false;
|
||||
|
||||
VideoPicture &vp = pictq[pictq_windex];
|
||||
|
||||
// alloc or resize hardware picture buffer
|
||||
if ((!vp.overlay && !rgb) || (!vp.surface && rgb) || vp.width != videoStream->codec->width ||
|
||||
vp.height != videoStream->codec->height) {
|
||||
SDL_Event event;
|
||||
|
||||
vp.allocated = false;
|
||||
|
||||
// the allocation must be done in the main thread to avoid locking problems
|
||||
event.type = FF_ALLOC_EVENT;
|
||||
event.user.data1 = this;
|
||||
SDL_PushEvent(&event);
|
||||
|
||||
// wait until the picture is allocated
|
||||
INTERLOCKED_(pictq_mutex) {
|
||||
while (!vp.allocated && !videoq.IsAbort())
|
||||
pictq_cond.Wait(pictq_mutex);
|
||||
}
|
||||
|
||||
if (videoq.IsAbort())
|
||||
return false;
|
||||
}
|
||||
int dwidth, dheight;
|
||||
INTERLOCKED_(mtx) {
|
||||
dwidth = imgRect.GetWidth();
|
||||
dheight = imgRect.GetHeight();
|
||||
}
|
||||
|
||||
SwsContext *context = 0;
|
||||
|
||||
// if the frame is not skipped, then display it
|
||||
if (vp.overlay) { // Conversion to YUV420P
|
||||
context = SWSGetContext(videoStream->codec->width, videoStream->codec->height,
|
||||
videoStream->codec->pix_fmt,
|
||||
videoStream->codec->width, videoStream->codec->height,
|
||||
PIX_FMT_YUV420P); // Image transformed but not scaled
|
||||
if (!context) {
|
||||
SetError("Cannot initialize the conversion context");
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_LockYUVOverlay(vp.overlay);
|
||||
|
||||
AVPicture pict;
|
||||
memset(&pict,0,sizeof(AVPicture));
|
||||
pict.data[0] = vp.overlay->pixels[0];
|
||||
pict.data[1] = vp.overlay->pixels[2];
|
||||
pict.data[2] = vp.overlay->pixels[1];
|
||||
|
||||
pict.linesize[0] = vp.overlay->pitches[0];
|
||||
pict.linesize[1] = vp.overlay->pitches[2];
|
||||
pict.linesize[2] = vp.overlay->pitches[1];
|
||||
|
||||
sws_scale(context, frame->data, frame->linesize,
|
||||
0, videoStream->codec->height, pict.data, pict.linesize);
|
||||
|
||||
SDL_UnlockYUVOverlay(vp.overlay);
|
||||
} else if (vp.surface) { // Convertion to RGB
|
||||
int pitch = vp.surface->pitch;
|
||||
PixelFormat pix_fmt_dest;
|
||||
switch (vp.surface->format->BitsPerPixel) {
|
||||
case 32: pix_fmt_dest = PIX_FMT_RGB32;
|
||||
break;
|
||||
case 24: pix_fmt_dest = PIX_FMT_RGB24;
|
||||
break;
|
||||
default: return false;
|
||||
}
|
||||
context = SWSGetContext(videoStream->codec->width, videoStream->codec->height,
|
||||
videoStream->codec->pix_fmt,
|
||||
dwidth, dheight, pix_fmt_dest); // Image transformed and scaled
|
||||
if (!context) {
|
||||
SetError("Cannot initialize the conversion context");
|
||||
return false;
|
||||
}
|
||||
SDL_LockSurface(vp.surface);
|
||||
|
||||
sws_scale(context, frame->data, frame->linesize,
|
||||
0, videoStream->codec->height, (uint8_t* const*)&(vp.surface->pixels), &pitch);
|
||||
|
||||
SDL_UnlockSurface(vp.surface);
|
||||
}
|
||||
if (context)
|
||||
sws_freeContext(context);
|
||||
if (vp.overlay || vp.surface) {
|
||||
vp.pts = pts;
|
||||
|
||||
// now we can update the picture count
|
||||
if (++pictq_windex == VIDEO_PICTURE_QUEUE_SIZE)
|
||||
pictq_windex = 0;
|
||||
INTERLOCKED_(pictq_mutex) {
|
||||
pictq_size++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* pause or resume the video */
|
||||
void MediaFile::stream_pause() {
|
||||
paused = !paused;
|
||||
if (!paused) {
|
||||
video_current_pts = get_video_clock();
|
||||
frame_timer += (GetUSec() - video_current_pts_time) / 1000000.0;
|
||||
}
|
||||
}
|
||||
|
||||
void MediaFile::SetError(String str) {
|
||||
if (!strError.IsEmpty())
|
||||
strError << "\n";
|
||||
strError << ToUpper(str[0]) + DeQtfLf(str.Mid(1));
|
||||
}
|
||||
|
||||
bool MediaFile::BeginDecoder() {
|
||||
return decoderThreadId.Run(THISBACK(DecoderThread));
|
||||
//decoderThreadId = SDL_CreateThread(DecoderThread, this);
|
||||
//return !!decoderThreadId;
|
||||
}
|
||||
|
||||
|
|
@ -1,268 +0,0 @@
|
|||
#ifndef _Media_mediafile_h_
|
||||
#define _Media_mediafile_h_
|
||||
|
||||
#include <SDL/SDLCtrl.h>
|
||||
#include <Media/ffmpeg_base.h>
|
||||
#include "mt.h"
|
||||
|
||||
/* SDL audio buffer size, in samples. Should be small to have precise
|
||||
A/V sync as SDL does not have hardware buffer fullness info. */
|
||||
#define SDL_AUDIO_BUFFER_SIZE 1024
|
||||
|
||||
#define MAX_VIDEOQ_SIZE (5 * 256 * 1024)
|
||||
#define MAX_AUDIOQ_SIZE (5 * 16 * 1024)
|
||||
#define MAX_SUBTITLEQ_SIZE (5 * 16 * 1024)
|
||||
|
||||
#define VIDEO_PICTURE_QUEUE_SIZE 2
|
||||
#define SUBPICTURE_QUEUE_SIZE 4
|
||||
|
||||
// we use about AUDIO_DIFF_AVG_NB A-V differences to make the average
|
||||
#define AUDIO_DIFF_AVG_NB 20
|
||||
|
||||
// NOTE: the size must be big enough to compensate the hardware audio buffersize size
|
||||
#define SAMPLE_ARRAY_SIZE (2*65536)
|
||||
|
||||
/* maximum audio speed change to get correct sync */
|
||||
#define SAMPLE_CORRECTION_PERCENT_MAX 10
|
||||
|
||||
/* no AV sync correction is done if below the AV sync threshold */
|
||||
#define AV_SYNC_THRESHOLD 0.01
|
||||
/* no AV correction is done if too big error */
|
||||
#define AV_NOSYNC_THRESHOLD 10.0
|
||||
|
||||
#define FF_ALLOC_EVENT (SDL_USEREVENT)
|
||||
#define FF_REFRESH_EVENT (SDL_USEREVENT + 1)
|
||||
#define FF_QUIT_EVENT (SDL_USEREVENT + 2)
|
||||
|
||||
enum {
|
||||
AV_SYNC_AUDIO_MASTER, /* default choice */
|
||||
AV_SYNC_VIDEO_MASTER,
|
||||
AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */
|
||||
};
|
||||
|
||||
struct VideoPicture {
|
||||
double pts; // presentation time stamp for this picture
|
||||
double target_clock; // GetUSec() time at which this should be displayed ideally
|
||||
int64_t pos; // byte position in file
|
||||
SDL_Overlay *overlay;
|
||||
SDL_Surface *surface;
|
||||
int width, height; // source height & width
|
||||
bool allocated;
|
||||
enum PixelFormat pix_fmt;
|
||||
};
|
||||
|
||||
struct SubPicture {
|
||||
double pts; // presentation time stamp for this picture
|
||||
AVSubtitle sub;
|
||||
};
|
||||
|
||||
class PacketQueue {
|
||||
public:
|
||||
PacketQueue();
|
||||
void SetMaxSize(int _maxSize) {maxSize = _maxSize;};
|
||||
void Init();
|
||||
void Init(AVPacket &pkt, AVPacket *flush_pkt);
|
||||
int Put(AVPacket *pkt, AVPacket *flush_pkt);
|
||||
int Get(AVPacket *pkt, bool decodeEnd);
|
||||
void Flush();
|
||||
void End();
|
||||
void Abort();
|
||||
inline bool IsAbort() {return abort_request;};
|
||||
bool IsFull() {return size > maxSize;};
|
||||
|
||||
private:
|
||||
AVPacketList *first_pkt, *last_pkt;
|
||||
int nb_packets;
|
||||
int size;
|
||||
int maxSize;
|
||||
bool abort_request;
|
||||
Mutex mutex;
|
||||
ConditionVariable cond;
|
||||
};
|
||||
|
||||
void sdl_audio_callback(void *data, Uint8 *stream, int len);
|
||||
|
||||
class MediaFile {
|
||||
typedef MediaFile CLASSNAME;
|
||||
public:
|
||||
friend int decoderInterrupt_cb();
|
||||
friend void sdl_audio_callback(void *data, Uint8 *stream, int len);
|
||||
|
||||
MediaFile();
|
||||
~MediaFile();
|
||||
|
||||
inline bool IsOpened() {return fileData;};
|
||||
|
||||
inline String GetFileName() {return !fileData ? "" : fileData->filename;};
|
||||
inline double GetDuration() {return !fileData ? -1 : double(fileData->duration) / AV_TIME_BASE;};
|
||||
inline int64 GetDurationTimeBase() {return !fileData ? -1 : fileData->duration;};
|
||||
inline int GetNumStreams() {return !fileData ? -1 : fileData->nb_streams;};
|
||||
|
||||
int GetNumVideo() {return numVideoStreams;};
|
||||
int GetNumAudio() {return numAudioStreams;};
|
||||
|
||||
inline double GetSecond() {return second;};
|
||||
void SetSecond(double second);
|
||||
|
||||
void EnableAudio(bool v = true) {audio_disable = !v;};
|
||||
void EnableVideo(bool v = true) {video_disable = !v;};
|
||||
|
||||
inline void SetVideo(int id) {if(id < GetNumStreams() && id >= -1) idVideo = id;};
|
||||
inline void SetAudio(int id) {if(id < GetNumStreams() && id >= -1) idAudio = id;};
|
||||
inline void SetSubtitle(int id) {if(id < GetNumStreams() && id >= -1) idSubtitle = id;};
|
||||
inline int GetVideo() {return idVideo;};
|
||||
inline int GetAudio() {return idAudio;};
|
||||
inline int GetSubtitle() {return idSubtitle;};
|
||||
|
||||
inline MediaFile& ShowAudio(bool show = true) {showAudio = show; return *this;};
|
||||
inline MediaFile& SetShowAudioFPS(double fps) {showAudioFps = fps; return *this;};
|
||||
|
||||
inline MediaFile& SetAudioFactor(double f) {audioFactor = int(f*1000); return *this;};
|
||||
|
||||
struct StreamData {
|
||||
int id;
|
||||
String codec;
|
||||
String lang;
|
||||
uint32 bitrate;
|
||||
String tags; // Tags in metadata
|
||||
};
|
||||
struct VideoData : public StreamData {
|
||||
String pixFmt;
|
||||
Size size;
|
||||
Size par; // Pixel aspect ratio
|
||||
Size dar; // Display aspect ratio
|
||||
Size frameRate, tbr, tbn, tbc;
|
||||
};
|
||||
struct AudioData : public StreamData {
|
||||
int channels;
|
||||
String bits;
|
||||
uint32 sampleRate;
|
||||
};
|
||||
Array<AudioData> audioData;
|
||||
int GetAudioId();
|
||||
void SetAudioId(int id);
|
||||
|
||||
Array<VideoData> videoData;
|
||||
int GetVideoId();
|
||||
void SetVideoId(int id);
|
||||
|
||||
inline MediaFile& SetRGB(bool v) {rgb = v; return *this;};
|
||||
|
||||
protected:
|
||||
void Reset();
|
||||
void stream_seek(int64_t pos, int64_t rel, bool seek_by_bytes);
|
||||
bool StreamOpen(int streamId);
|
||||
void StreamClose(int streamId);
|
||||
int audio_decode_frame(double *pts_ptr);
|
||||
void update_sample_display(short *samples, int samples_size);
|
||||
int synchronize_audio(short *samples, int samples_size1, double pts);
|
||||
int GetAudioOutputBufferSize();
|
||||
double get_audio_clock();
|
||||
double get_video_clock();
|
||||
double get_master_clock();
|
||||
double get_external_clock();
|
||||
bool queue_picture(AVFrame *src_frame, double pts);
|
||||
void stream_pause();
|
||||
void DecoderThread();//void *arg);
|
||||
void VideoThread();//(void *arg);
|
||||
void SubtitleThread();//(void *arg);
|
||||
bool BeginDecoder();
|
||||
|
||||
AVFormatContext *fileData;
|
||||
PacketQueue videoq, audioq, subtitleq;
|
||||
AtomicVar requestAbort,
|
||||
decodeThEnd, decodeThEnded,
|
||||
audioThEnd, videoThEnd, subtitleThEnd;
|
||||
int threadCount;
|
||||
int numVideoStreams, numAudioStreams;
|
||||
double second, lastSecond;
|
||||
int idVideo, idAudio, idSubtitle;
|
||||
String tags;
|
||||
bool audio_disable, video_disable;
|
||||
bool seek_by_bytes;
|
||||
int64_t start_time;
|
||||
bool seek_req;
|
||||
int seek_flags;
|
||||
int64_t seek_pos;
|
||||
int64_t seek_rel;
|
||||
int paused, last_paused;
|
||||
AVPacket flush_pkt;
|
||||
|
||||
VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE];
|
||||
int pictq_size, pictq_rindex, pictq_windex;
|
||||
Mutex pictq_mutex;
|
||||
ConditionVariable pictq_cond;
|
||||
|
||||
SubPicture subpq[SUBPICTURE_QUEUE_SIZE];
|
||||
int subpq_size, subpq_rindex, subpq_windex;
|
||||
Mutex subpq_mutex;
|
||||
ConditionVariable subpq_cond;
|
||||
|
||||
AVStream *audioStream, *videoStream, *subtitleStream;
|
||||
|
||||
AVAudioConvert *reformat_ctx;
|
||||
|
||||
Thread video_tid, decoderThreadId, /*refresh_tid,*/ subtitle_tid;
|
||||
|
||||
int subtitle_stream_changed;
|
||||
int debug, debug_mv, workaround_bugs;
|
||||
int lowres;
|
||||
bool fast;
|
||||
int genpts;
|
||||
int idct;
|
||||
enum AVDiscard skip_frame, skip_idct, skip_loop_filter;
|
||||
int decoder_reorder_pts;
|
||||
|
||||
int64_t audio_callback_time;
|
||||
|
||||
// Samples output by the codec. we reserve more space for avsync compensation
|
||||
DECLARE_ALIGNED(16,uint8_t,audio_buf1)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
|
||||
DECLARE_ALIGNED(16,uint8_t,audio_buf2)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
|
||||
uint8_t *audio_buf;
|
||||
unsigned int audio_buf_size; // In bytes
|
||||
int audio_buf_index; // In bytes
|
||||
|
||||
bool showAudio; // if true, display audio samples in graphs
|
||||
double showAudioFps;
|
||||
double lastAudioShow;
|
||||
|
||||
int16_t sample_array[SAMPLE_ARRAY_SIZE];
|
||||
int sample_array_index;
|
||||
|
||||
double audio_clock;
|
||||
double audio_diff_cum; // used for AV difference average computation
|
||||
double audio_diff_avg_coef;
|
||||
double audio_diff_threshold;
|
||||
int audio_diff_avg_count;
|
||||
int audio_hw_buf_size;
|
||||
|
||||
enum SampleFormat audio_src_fmt;
|
||||
|
||||
AVPacket audio_pkt, audio_pkt_temp;
|
||||
|
||||
double video_current_pts; //Current displayed pts (different from video_clock if frame fifos are used)
|
||||
int64_t video_current_pts_time; //Time (GetUSec) at which we updated video_current_pts - used to have running video pts
|
||||
int64_t video_current_pos; //Current displayed file pos
|
||||
|
||||
int av_sync_type;
|
||||
TimeStop externalClock;
|
||||
double video_clock; // pts of last decoded frame / predicted pts of next decoded frame
|
||||
|
||||
double frame_timer;
|
||||
bool step; // Jump to next frame
|
||||
|
||||
String strError;
|
||||
String GetError() {return strError;};
|
||||
void SetError(String str);
|
||||
void ResetError() {strError = "";};
|
||||
|
||||
AtomicVar rgb; // Is the image YUV or RGB
|
||||
bool forceAspect; // Force aspect ratio
|
||||
Rect imgRect; // Image size
|
||||
Mutex mtx;
|
||||
|
||||
AtomicVar audioFactor;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,824 +0,0 @@
|
|||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#include "MediaFile.h"
|
||||
#include "MediaPlayer.h"
|
||||
#include "utility.h"
|
||||
#include "mediaplayer_in.h"
|
||||
|
||||
|
||||
static inline void fill_rectangle(SDL_Surface *screen,
|
||||
int x, int y, int w, int h, int color)
|
||||
{
|
||||
SDL_Rect rect;
|
||||
rect.x = x;
|
||||
rect.y = y;
|
||||
rect.w = w;
|
||||
rect.h = h;
|
||||
SDL_FillRect(screen, &rect, color);
|
||||
}
|
||||
|
||||
|
||||
#define BPP 1
|
||||
|
||||
static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, int imgh)
|
||||
{
|
||||
int wrap, wrap3, width2, skip2;
|
||||
int y, u, v, a, u1, v1, a1, w, h;
|
||||
uint8_t *lum, *cb, *cr;
|
||||
const uint8_t *p;
|
||||
const uint32_t *pal;
|
||||
int dstx, dsty, dstw, dsth;
|
||||
|
||||
dstw = av_clip(rect->w, 0, imgw);
|
||||
dsth = av_clip(rect->h, 0, imgh);
|
||||
dstx = av_clip(rect->x, 0, imgw - dstw);
|
||||
dsty = av_clip(rect->y, 0, imgh - dsth);
|
||||
lum = dst->data[0] + dsty * dst->linesize[0];
|
||||
cb = dst->data[1] + (dsty >> 1) * dst->linesize[1];
|
||||
cr = dst->data[2] + (dsty >> 1) * dst->linesize[2];
|
||||
|
||||
width2 = ((dstw + 1) >> 1) + (dstx & ~dstw & 1);
|
||||
skip2 = dstx >> 1;
|
||||
wrap = dst->linesize[0];
|
||||
wrap3 = rect->pict.linesize[0];
|
||||
p = rect->pict.data[0];
|
||||
pal = (const uint32_t *)rect->pict.data[1]; /* Now in YCrCb! */
|
||||
|
||||
if (dsty & 1) {
|
||||
lum += dstx;
|
||||
cb += skip2;
|
||||
cr += skip2;
|
||||
|
||||
if (dstx & 1) {
|
||||
YUVA_IN(y, u, v, a, p, pal);
|
||||
lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
|
||||
cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
|
||||
cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
|
||||
cb++;
|
||||
cr++;
|
||||
lum++;
|
||||
p += BPP;
|
||||
}
|
||||
for(w = dstw - (dstx & 1); w >= 2; w -= 2) {
|
||||
YUVA_IN(y, u, v, a, p, pal);
|
||||
u1 = u;
|
||||
v1 = v;
|
||||
a1 = a;
|
||||
lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
|
||||
|
||||
YUVA_IN(y, u, v, a, p + BPP, pal);
|
||||
u1 += u;
|
||||
v1 += v;
|
||||
a1 += a;
|
||||
lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
|
||||
cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1);
|
||||
cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1);
|
||||
cb++;
|
||||
cr++;
|
||||
p += 2 * BPP;
|
||||
lum += 2;
|
||||
}
|
||||
if (w) {
|
||||
YUVA_IN(y, u, v, a, p, pal);
|
||||
lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
|
||||
cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
|
||||
cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
|
||||
p++;
|
||||
lum++;
|
||||
}
|
||||
p += wrap3 - dstw * BPP;
|
||||
lum += wrap - dstw - dstx;
|
||||
cb += dst->linesize[1] - width2 - skip2;
|
||||
cr += dst->linesize[2] - width2 - skip2;
|
||||
}
|
||||
for(h = dsth - (dsty & 1); h >= 2; h -= 2) {
|
||||
lum += dstx;
|
||||
cb += skip2;
|
||||
cr += skip2;
|
||||
|
||||
if (dstx & 1) {
|
||||
YUVA_IN(y, u, v, a, p, pal);
|
||||
u1 = u;
|
||||
v1 = v;
|
||||
a1 = a;
|
||||
lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
|
||||
p += wrap3;
|
||||
lum += wrap;
|
||||
YUVA_IN(y, u, v, a, p, pal);
|
||||
u1 += u;
|
||||
v1 += v;
|
||||
a1 += a;
|
||||
lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
|
||||
cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1);
|
||||
cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1);
|
||||
cb++;
|
||||
cr++;
|
||||
p += -wrap3 + BPP;
|
||||
lum += -wrap + 1;
|
||||
}
|
||||
for(w = dstw - (dstx & 1); w >= 2; w -= 2) {
|
||||
YUVA_IN(y, u, v, a, p, pal);
|
||||
u1 = u;
|
||||
v1 = v;
|
||||
a1 = a;
|
||||
lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
|
||||
|
||||
YUVA_IN(y, u, v, a, p + BPP, pal);
|
||||
u1 += u;
|
||||
v1 += v;
|
||||
a1 += a;
|
||||
lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
|
||||
p += wrap3;
|
||||
lum += wrap;
|
||||
|
||||
YUVA_IN(y, u, v, a, p, pal);
|
||||
u1 += u;
|
||||
v1 += v;
|
||||
a1 += a;
|
||||
lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
|
||||
|
||||
YUVA_IN(y, u, v, a, p + BPP, pal);
|
||||
u1 += u;
|
||||
v1 += v;
|
||||
a1 += a;
|
||||
lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
|
||||
|
||||
cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 2);
|
||||
cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 2);
|
||||
|
||||
cb++;
|
||||
cr++;
|
||||
p += -wrap3 + 2 * BPP;
|
||||
lum += -wrap + 2;
|
||||
}
|
||||
if (w) {
|
||||
YUVA_IN(y, u, v, a, p, pal);
|
||||
u1 = u;
|
||||
v1 = v;
|
||||
a1 = a;
|
||||
lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
|
||||
p += wrap3;
|
||||
lum += wrap;
|
||||
YUVA_IN(y, u, v, a, p, pal);
|
||||
u1 += u;
|
||||
v1 += v;
|
||||
a1 += a;
|
||||
lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
|
||||
cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1);
|
||||
cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1);
|
||||
cb++;
|
||||
cr++;
|
||||
p += -wrap3 + BPP;
|
||||
lum += -wrap + 1;
|
||||
}
|
||||
p += wrap3 + (wrap3 - dstw * BPP);
|
||||
lum += wrap + (wrap - dstw - dstx);
|
||||
cb += dst->linesize[1] - width2 - skip2;
|
||||
cr += dst->linesize[2] - width2 - skip2;
|
||||
}
|
||||
/* handle odd height */
|
||||
if (h) {
|
||||
lum += dstx;
|
||||
cb += skip2;
|
||||
cr += skip2;
|
||||
|
||||
if (dstx & 1) {
|
||||
YUVA_IN(y, u, v, a, p, pal);
|
||||
lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
|
||||
cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
|
||||
cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
|
||||
cb++;
|
||||
cr++;
|
||||
lum++;
|
||||
p += BPP;
|
||||
}
|
||||
for(w = dstw - (dstx & 1); w >= 2; w -= 2) {
|
||||
YUVA_IN(y, u, v, a, p, pal);
|
||||
u1 = u;
|
||||
v1 = v;
|
||||
a1 = a;
|
||||
lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
|
||||
|
||||
YUVA_IN(y, u, v, a, p + BPP, pal);
|
||||
u1 += u;
|
||||
v1 += v;
|
||||
a1 += a;
|
||||
lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
|
||||
cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u, 1);
|
||||
cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v, 1);
|
||||
cb++;
|
||||
cr++;
|
||||
p += 2 * BPP;
|
||||
lum += 2;
|
||||
}
|
||||
if (w) {
|
||||
YUVA_IN(y, u, v, a, p, pal);
|
||||
lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
|
||||
cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
|
||||
cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void free_subpicture(SubPicture *sp)
|
||||
{
|
||||
avsubtitle_free(&sp->sub);
|
||||
}
|
||||
|
||||
void MediaPlayer::video_image_display()
|
||||
{
|
||||
VideoPicture &vp = pictq[pictq_rindex];
|
||||
if (!vp.overlay && !vp.surface)
|
||||
return;
|
||||
if (subtitleStream) {
|
||||
if (subpq_size > 0) {
|
||||
SubPicture *sp = &subpq[subpq_rindex];
|
||||
|
||||
if (vp.pts >= sp->pts + (float(sp->sub.start_display_time)/1000.)) {
|
||||
SDL_LockYUVOverlay(vp.overlay);
|
||||
|
||||
AVPicture pict;
|
||||
pict.data[0] = vp.overlay->pixels[0];
|
||||
pict.data[1] = vp.overlay->pixels[2];
|
||||
pict.data[2] = vp.overlay->pixels[1];
|
||||
|
||||
pict.linesize[0] = vp.overlay->pitches[0];
|
||||
pict.linesize[1] = vp.overlay->pitches[2];
|
||||
pict.linesize[2] = vp.overlay->pitches[1];
|
||||
|
||||
for (unsigned i = 0; i < sp->sub.num_rects; i++)
|
||||
blend_subrect(&pict, sp->sub.rects[i], vp.overlay->w, vp.overlay->h);
|
||||
|
||||
SDL_UnlockYUVOverlay(vp.overlay);
|
||||
}
|
||||
}
|
||||
}
|
||||
// We suppose the screen has a 1.0 pixel ratio
|
||||
SDL_Rect rect;
|
||||
INTERLOCKED_(mtx) {
|
||||
rect.x = imgRect.left;
|
||||
rect.y = imgRect.top;
|
||||
rect.w = imgRect.GetWidth();
|
||||
rect.h = imgRect.GetHeight();
|
||||
}
|
||||
if (vp.overlay)
|
||||
SDL_DisplayYUVOverlay(vp.overlay, &rect);
|
||||
else if (vp.surface) {
|
||||
if (WhenFrame) {
|
||||
SDLSurface srf(vp.surface);
|
||||
WhenFrame(srf);
|
||||
}
|
||||
SDL_BlitSurface(vp.surface, 0, screen, &rect);
|
||||
SDL_Flip(screen);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPlayer::Layout() {
|
||||
SDLCtrl::Layout();
|
||||
|
||||
if (!screen)
|
||||
return;
|
||||
INTERLOCKED_(mtx) {
|
||||
if (forceAspect) { // Fit image to screen considering aspect ratio
|
||||
int cx = screen->w;
|
||||
int cy = screen->h;
|
||||
double frameAspect = cx/double(cy);
|
||||
if (frameAspect > aspect_ratio) {
|
||||
double x = (cx - aspect_ratio*cy)/2.;
|
||||
imgRect.Set(int(x), 0, int(x + aspect_ratio*cy), cy);
|
||||
} else {
|
||||
double y = (cy - cx/aspect_ratio)/2.;
|
||||
imgRect.Set(0, int(y), cx, int(y + cx/aspect_ratio));
|
||||
}
|
||||
} else
|
||||
imgRect.Set(0, 0, screen->w, screen->h);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate a picture (needs to do that in main thread to avoid potential locking problems)
|
||||
bool MediaPlayer::alloc_picture()
|
||||
{
|
||||
VideoPicture &vp = pictq[pictq_windex];
|
||||
|
||||
if (vp.overlay)
|
||||
SDL_FreeYUVOverlay(vp.overlay);
|
||||
else if (vp.surface)
|
||||
SDL_FreeSurface(vp.surface);
|
||||
|
||||
if (videoStream) {
|
||||
vp.width = videoStream->codec->width;
|
||||
vp.height = videoStream->codec->height;
|
||||
vp.pix_fmt = videoStream->codec->pix_fmt;
|
||||
} else {
|
||||
vp.width = screen->w;
|
||||
vp.height = screen->h;
|
||||
vp.pix_fmt = PIX_FMT_YUV420P;
|
||||
}
|
||||
if (rgb) {
|
||||
vp.surface = SDL_CreateRGBSurface(0, vp.width, vp.height, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0);
|
||||
vp.overlay = 0;
|
||||
} else {
|
||||
vp.overlay = SDL_CreateYUVOverlay(vp.width, vp.height, SDL_YV12_OVERLAY, screen);
|
||||
vp.surface = 0;
|
||||
}
|
||||
|
||||
if ((rgb && !vp.surface) ||
|
||||
(!rgb && (!vp.overlay || vp.overlay->pitches[0] < vp.width))) {
|
||||
SDLCtrl::SetError(Format("Error: the video system does not support an image\n"
|
||||
"size of %dx%d pixels.", vp.width, vp.height));
|
||||
return false;
|
||||
}
|
||||
|
||||
INTERLOCKED_(pictq_mutex) {
|
||||
vp.allocated = true;
|
||||
pictq_cond.Signal();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MediaPlayer::video_audioWaveform()
|
||||
{
|
||||
int i_start, x, y1, y, ys, delay, n, nb_display_channels;
|
||||
int ch, channels, h, h2, bgcolor, fgcolor;
|
||||
int16_t time_diff;
|
||||
int rdft_bits, nb_freq;
|
||||
|
||||
for(rdft_bits=1; (1<<rdft_bits)<2*screen->h; rdft_bits++)
|
||||
;
|
||||
nb_freq= 1<<(rdft_bits-1);
|
||||
|
||||
// compute display index : center on currently output samples
|
||||
channels = audioStream->codec->channels;
|
||||
nb_display_channels = channels;
|
||||
if (!paused) {
|
||||
int data_used = screen->w;
|
||||
n = 2 * channels;
|
||||
delay = GetAudioOutputBufferSize();
|
||||
delay /= n;
|
||||
|
||||
// to be more precise, we take into account the time spent since the last buffer computation
|
||||
if (audio_callback_time) {
|
||||
time_diff = int16_t(GetUSec() - audio_callback_time);
|
||||
delay -= (time_diff * audioStream->codec->sample_rate) / 1000000;
|
||||
}
|
||||
|
||||
delay += 2*data_used;
|
||||
if (delay < data_used)
|
||||
delay = data_used;
|
||||
|
||||
i_start = x = compute_mod(sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
|
||||
|
||||
h= INT_MIN;
|
||||
for(int i = 0; i < 1000; i += channels) {
|
||||
int idx= (SAMPLE_ARRAY_SIZE + x - i) % SAMPLE_ARRAY_SIZE;
|
||||
int a= sample_array[idx];
|
||||
int b= sample_array[(idx + 4*channels)%SAMPLE_ARRAY_SIZE];
|
||||
int c= sample_array[(idx + 5*channels)%SAMPLE_ARRAY_SIZE];
|
||||
int d= sample_array[(idx + 9*channels)%SAMPLE_ARRAY_SIZE];
|
||||
int score= a-d;
|
||||
if(h < score && (b^c)<0){
|
||||
h = score;
|
||||
i_start= idx;
|
||||
}
|
||||
}
|
||||
last_i_start = i_start;
|
||||
} else
|
||||
i_start = last_i_start;
|
||||
|
||||
bgcolor = SDL_MapRGB(screen->format, 0x80, 0x80, 0x80);
|
||||
|
||||
fill_rectangle(screen, 0, 0, screen->w, screen->h, bgcolor);
|
||||
|
||||
fgcolor = SDL_MapRGB(screen->format, 0x00, 0xff, 0x00);
|
||||
|
||||
// total height for one channel
|
||||
h = screen->h / nb_display_channels;
|
||||
// graph height / 2
|
||||
h2 = (h * 9) / 20;
|
||||
for(ch = 0; ch < nb_display_channels; ch++) {
|
||||
int i = i_start + ch;
|
||||
y1 = ch * h + (h / 2); /* position of center line */
|
||||
for(x = 0; x < screen->w; x++) {
|
||||
y = (sample_array[i] * h2) >> 15;
|
||||
ys = y1 - y;
|
||||
/*if (y < 0) {
|
||||
y = -y;
|
||||
ys = y1 - y;
|
||||
} else {
|
||||
ys = y1;
|
||||
}*/
|
||||
fill_rectangle(screen, x, ys, 1, 1/*y*/, fgcolor);
|
||||
i += channels;
|
||||
if (i >= SAMPLE_ARRAY_SIZE)
|
||||
i -= SAMPLE_ARRAY_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
fgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0xff);
|
||||
|
||||
for(ch = 1; ch < nb_display_channels; ch++) {
|
||||
y = ch * h;
|
||||
fill_rectangle(screen, 0, y, screen->w, 1, fgcolor);
|
||||
}
|
||||
SDL_UpdateRect(screen, 0, 0, screen->w, screen->h);
|
||||
}
|
||||
|
||||
// called to display each frame
|
||||
void MediaPlayer::video_refresh() {
|
||||
if (videoStream) {
|
||||
if (pictq_size > 0) { // There is picture
|
||||
double masterClock = get_master_clock();
|
||||
|
||||
double diff = video_current_pts - masterClock;
|
||||
if(diff > 0 && diff < 2)
|
||||
return;
|
||||
|
||||
// Update current video pts
|
||||
VideoPicture &vp = pictq[pictq_rindex]; // Dequeue the picture
|
||||
video_current_pts = vp.pts;
|
||||
video_current_pts_time = GetUSec();
|
||||
video_current_pos = vp.pos;
|
||||
|
||||
diff = video_current_pts - masterClock;
|
||||
if (diff > 2) {
|
||||
// update queue size and signal for next picture
|
||||
if (++pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
|
||||
pictq_rindex = 0;
|
||||
|
||||
INTERLOCKED_(pictq_mutex) {
|
||||
pictq_size--;
|
||||
pictq_cond.Signal();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(subtitleStream) {
|
||||
if (subtitle_stream_changed) {
|
||||
INTERLOCKED_(subpq_mutex) {
|
||||
while (subpq_size) {
|
||||
free_subpicture(&subpq[subpq_rindex]);
|
||||
|
||||
// update queue size for next picture
|
||||
if (++subpq_rindex == SUBPICTURE_QUEUE_SIZE)
|
||||
subpq_rindex = 0;
|
||||
|
||||
subpq_size--;
|
||||
}
|
||||
subtitle_stream_changed = false;
|
||||
|
||||
subpq_cond.Signal();
|
||||
}
|
||||
} else {
|
||||
if (subpq_size > 0) {
|
||||
SubPicture *sp, *sp2;
|
||||
sp = &subpq[subpq_rindex];
|
||||
|
||||
if (subpq_size > 1)
|
||||
sp2 = &subpq[(subpq_rindex + 1) % SUBPICTURE_QUEUE_SIZE];
|
||||
else
|
||||
sp2 = NULL;
|
||||
|
||||
if ((video_current_pts > (sp->pts + (float(sp->sub.end_display_time) / 1000)))
|
||||
|| (sp2 && video_current_pts > (sp2->pts + (float(sp2->sub.start_display_time) / 1000)))) {
|
||||
free_subpicture(sp);
|
||||
|
||||
// update queue size and signal for next picture
|
||||
if (++subpq_rindex == SUBPICTURE_QUEUE_SIZE)
|
||||
subpq_rindex = 0;
|
||||
|
||||
INTERLOCKED_(subpq_mutex) {
|
||||
subpq_size--;
|
||||
subpq_cond.Signal();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
video_image_display(); // display image
|
||||
|
||||
// update queue size and signal for next picture
|
||||
if (++pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
|
||||
pictq_rindex = 0;
|
||||
|
||||
INTERLOCKED_(pictq_mutex) {
|
||||
pictq_size--;
|
||||
pictq_cond.Signal();
|
||||
}
|
||||
}
|
||||
} else if (audioStream && showAudio) {
|
||||
if (get_external_clock() > lastAudioShow + 1./showAudioFps) {
|
||||
video_audioWaveform(); // Display audio waveform
|
||||
lastAudioShow = get_external_clock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPlayer::close() {
|
||||
// Free all pictures
|
||||
for(int i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
|
||||
VideoPicture &vp = pictq[i];
|
||||
if (vp.overlay) {
|
||||
SDL_FreeYUVOverlay(vp.overlay);
|
||||
vp.overlay = 0;
|
||||
} else if (vp.surface) {
|
||||
SDL_FreeSurface(vp.surface);
|
||||
vp.surface = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MediaPlayer::Load0Failed() {
|
||||
requestAbort = true;
|
||||
|
||||
// Close each stream
|
||||
if (idAudio >= 0)
|
||||
StreamClose(idAudio);
|
||||
if (idVideo >= 0)
|
||||
StreamClose(idVideo);
|
||||
if (idSubtitle >= 0)
|
||||
StreamClose(idSubtitle);
|
||||
if (fileData) {
|
||||
av_close_input_file(fileData);
|
||||
fileData = NULL;
|
||||
}
|
||||
url_set_interrupt_cb(NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MediaPlayer::Load(const char *_fileName) {
|
||||
ResetError();
|
||||
Reset(GetSurface(), GetVideoFlags());
|
||||
|
||||
int err;
|
||||
|
||||
AVFormatParameters params, *ap = ¶ms;
|
||||
int eof=0;
|
||||
int pkt_in_play_range = 0;
|
||||
|
||||
fileData = avformat_alloc_context();
|
||||
|
||||
idVideo = idAudio = idSubtitle = -1;
|
||||
|
||||
memset(ap, 0, sizeof(*ap));
|
||||
|
||||
ap->prealloced_context = 1;
|
||||
ap->time_base.num = 1;
|
||||
ap->time_base.den = 25;
|
||||
ap->pix_fmt = frame_pix_fmt;
|
||||
|
||||
err = av_open_input_file(&fileData, ToSystemCharset(_fileName), iformat, 0, ap);
|
||||
if (err < 0) {
|
||||
MediaFile::SetError(GetAvError(err));
|
||||
return Load0Failed();
|
||||
}
|
||||
|
||||
if(genpts)
|
||||
fileData->flags |= AVFMT_FLAG_GENPTS;
|
||||
|
||||
err = av_find_stream_info(fileData);
|
||||
if (err < 0) {
|
||||
MediaFile::SetError(GetAvError(err));
|
||||
return Load0Failed();
|
||||
}
|
||||
if(fileData->pb)
|
||||
fileData->pb->eof_reached= 0; //FIXME hack, ffplay maybe should not use url_feof() to test for the end
|
||||
|
||||
// if seeking requested, we execute it
|
||||
if (start_time != AV_NOPTS_VALUE) {
|
||||
int64_t timestamp;
|
||||
|
||||
timestamp = start_time;
|
||||
// add the stream start time
|
||||
if (fileData->start_time != AV_NOPTS_VALUE)
|
||||
timestamp += fileData->start_time;
|
||||
int ret = av_seek_frame(fileData, -1, timestamp, AVSEEK_FLAG_BACKWARD);
|
||||
if (ret < 0) {
|
||||
MediaFile::SetError(Format("Could not seek to position %0.3f", (double)timestamp / AV_TIME_BASE));
|
||||
return Load0Failed();
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < fileData->nb_streams; i++) {
|
||||
AVStream *st = fileData->streams[i];
|
||||
st->discard = AVDISCARD_ALL;
|
||||
switch(st->codec->codec_type) {
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
numAudioStreams++;
|
||||
{
|
||||
AudioData &audioD = audioData.Add();
|
||||
audioD.id = i;
|
||||
audioD.codec = GetCodecName(st->codec, 0);
|
||||
audioD.lang = GetStreamLanguage(st);
|
||||
audioD.sampleRate = st->codec->sample_rate;
|
||||
audioD.channels = st->codec->channels;
|
||||
audioD.bitrate = GetCodecBitRate(st->codec);
|
||||
audioD.bits = GetStreamAudioBitFormat(st);
|
||||
audioD.tags = GetStreamTags(st);
|
||||
}
|
||||
if (!audio_disable)
|
||||
idAudio = i;
|
||||
break;
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
numVideoStreams++;
|
||||
{
|
||||
VideoData &videoD = videoData.Add();
|
||||
videoD.id = i;
|
||||
videoD.codec = GetCodecName(st->codec, 0);
|
||||
if (st->codec->pix_fmt != PIX_FMT_NONE)
|
||||
videoD.pixFmt = avcodec_get_pix_fmt_name(st->codec->pix_fmt);
|
||||
videoD.lang = GetStreamLanguage(st);
|
||||
videoD.size.cx = st->codec->width;
|
||||
videoD.size.cy = st->codec->height;
|
||||
if (st->codec->sample_aspect_ratio.num) {
|
||||
AVRational display_aspect_ratio;
|
||||
av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,
|
||||
st->codec->width*st->codec->sample_aspect_ratio.num,
|
||||
st->codec->height*st->codec->sample_aspect_ratio.den,
|
||||
1024*1024);
|
||||
videoD.par.cx = st->codec->sample_aspect_ratio.num;
|
||||
videoD.par.cy = st->codec->sample_aspect_ratio.den;
|
||||
videoD.dar.cx = display_aspect_ratio.num;
|
||||
videoD.dar.cy = display_aspect_ratio.den;
|
||||
} else
|
||||
videoD.par.cx = videoD.par.cy = videoD.dar.cx = videoD.dar.cy = 1;
|
||||
|
||||
videoD.tags = GetStreamTags(st);
|
||||
videoD.frameRate.cx = st->avg_frame_rate.num;
|
||||
videoD.frameRate.cy = st->avg_frame_rate.den;
|
||||
videoD.tbr.cx = st->r_frame_rate.num;
|
||||
videoD.tbr.cy = st->r_frame_rate.den;
|
||||
videoD.tbn.cx = st->time_base.num;
|
||||
videoD.tbn.cy = st->time_base.den;
|
||||
videoD.tbc.cx = st->codec->time_base.num;
|
||||
videoD.tbc.cy = st->codec->time_base.den;
|
||||
|
||||
videoD.bitrate = GetCodecBitRate(st->codec);
|
||||
if (!video_disable)
|
||||
idVideo = i;
|
||||
}
|
||||
break;
|
||||
case AVMEDIA_TYPE_SUBTITLE:
|
||||
if (!video_disable)
|
||||
idSubtitle = i;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
tags = ::GetTags(fileData);
|
||||
|
||||
if (idAudio >= 0)
|
||||
audioStream = fileData->streams[idAudio];
|
||||
if (idVideo >= 0)
|
||||
videoStream = fileData->streams[idVideo];
|
||||
if (idSubtitle >= 0)
|
||||
audioStream = fileData->streams[idSubtitle];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MediaPlayer::Reset(SDL_Surface *_screen, int _videoFlags)
|
||||
{
|
||||
MediaFile::Reset();
|
||||
|
||||
iformat = 0;
|
||||
last_i_start = 0;
|
||||
|
||||
aspect_ratio = 1;
|
||||
screen = 0;
|
||||
|
||||
memset(&frame_pix_fmt, 0, sizeof(frame_pix_fmt));
|
||||
|
||||
frame_pix_fmt = PIX_FMT_NONE;
|
||||
av_sync_type = AV_SYNC_AUDIO_MASTER;
|
||||
start_time = AV_NOPTS_VALUE;
|
||||
|
||||
fast = false;
|
||||
genpts = 0;
|
||||
lowres = 0;
|
||||
idct = FF_IDCT_AUTO;
|
||||
|
||||
screen = _screen;
|
||||
videoFlags = _videoFlags;
|
||||
}
|
||||
|
||||
void MediaPlayer::Pause()
|
||||
{
|
||||
stream_pause();
|
||||
step = false;
|
||||
}
|
||||
|
||||
void MediaPlayer::step_to_next_frame()
|
||||
{
|
||||
if (paused)
|
||||
stream_pause();
|
||||
step = true;
|
||||
}
|
||||
|
||||
/* handle an event sent by the GUI */
|
||||
bool MediaPlayer::event_loop()
|
||||
{
|
||||
for(;;) {
|
||||
Ctrl::ProcessEvents();
|
||||
|
||||
SDL_Event event;
|
||||
if (SDL_PollEvent(&event)) {
|
||||
switch(event.type) {
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
Pause();
|
||||
break;
|
||||
case FF_ALLOC_EVENT:
|
||||
if (!alloc_picture())
|
||||
return false;
|
||||
// Repaints background when change of size
|
||||
fill_rectangle(screen, 0, 0, screen->w, screen->h,
|
||||
SDL_MapRGB(screen->format, 0x00, 0x00, 0x00));
|
||||
SDL_UpdateRect(screen, 0, 0, screen->w, screen->h);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (decodeThEnded)
|
||||
return true;
|
||||
|
||||
video_refresh();
|
||||
|
||||
second = get_master_clock();
|
||||
if (fabs(second - lastSecond) > 1.) {
|
||||
lastSecond = second;
|
||||
if (WhenSecond)
|
||||
WhenSecond();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
MediaPlayer::MediaPlayer() {
|
||||
SetBpp(24);
|
||||
|
||||
Reset(0, 0);
|
||||
}
|
||||
|
||||
bool MediaPlayer::Play() {
|
||||
ResetError();
|
||||
|
||||
// open the streams and launch threads
|
||||
decodeThEnd = decodeThEnded = false;
|
||||
requestAbort = false;
|
||||
StreamOpen(idAudio);
|
||||
StreamOpen(idVideo);
|
||||
StreamOpen(idSubtitle);
|
||||
|
||||
if (idVideo < 0 && idAudio < 0) {
|
||||
MediaFile::SetError("Could not open codecs");
|
||||
return Load0Failed();
|
||||
}
|
||||
|
||||
if (!alloc_picture()) {
|
||||
SDLCtrl::SetError("Could not alloc picture");
|
||||
return Load0Failed();
|
||||
}
|
||||
|
||||
VideoPicture &vp = pictq[pictq_rindex];
|
||||
|
||||
if (vp.overlay || vp.surface) {
|
||||
if (videoStream) {
|
||||
if (videoStream->sample_aspect_ratio.num)
|
||||
aspect_ratio = float(av_q2d(videoStream->sample_aspect_ratio));
|
||||
else if (videoStream->codec->sample_aspect_ratio.num)
|
||||
aspect_ratio = float(av_q2d(videoStream->codec->sample_aspect_ratio));
|
||||
else
|
||||
aspect_ratio = 0;
|
||||
|
||||
if (aspect_ratio <= 0.0)
|
||||
aspect_ratio = 1.0;
|
||||
aspect_ratio *= float(vp.width) / float(vp.height);
|
||||
} else
|
||||
aspect_ratio = 1;
|
||||
}
|
||||
Layout(); // After aspect_ratio setting
|
||||
|
||||
SetSecond(0);
|
||||
externalClock.Reset();
|
||||
|
||||
if (!fileData)
|
||||
throw Exc("MediaFile has been deleted");
|
||||
|
||||
if (!BeginDecoder())
|
||||
return false;
|
||||
|
||||
event_loop();
|
||||
close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MediaPlayer::Stop() {
|
||||
requestAbort = true;
|
||||
};
|
||||
|
||||
MediaPlayer::~MediaPlayer() {
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
#ifndef _Media_mediaplayer_h
|
||||
#define _Media_mediaplayer_h
|
||||
|
||||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#include <SDL/SDLCtrl.h>
|
||||
#include "ffmpeg_base.h"
|
||||
#include "MediaFile.h"
|
||||
|
||||
class MediaPlayer : public MediaFile, public SDLCtrl {
|
||||
typedef MediaPlayer CLASSNAME;
|
||||
public:
|
||||
MediaPlayer();
|
||||
~MediaPlayer();
|
||||
|
||||
bool Load(const char *filename);
|
||||
bool Play();
|
||||
void Stop();
|
||||
void Pause();
|
||||
MediaPlayer &ForceAspect(bool f = true) {forceAspect = f; Layout(); return *this;};
|
||||
|
||||
bool IsPaused() {return paused;};
|
||||
|
||||
Callback1<SDLSurface &> WhenFrame;
|
||||
Callback WhenSecond;
|
||||
Callback WhenPause;
|
||||
|
||||
String GetTags() {return tags;};
|
||||
|
||||
void Reset(SDL_Surface *screen, int videoFlags);
|
||||
|
||||
void ResetError() {MediaFile::ResetError(); SDLCtrl::ResetError();};
|
||||
String GetError() {return MediaFile::GetError()+SDLCtrl::GetError();};
|
||||
|
||||
private:
|
||||
bool Load0Failed();
|
||||
void close();
|
||||
void video_refresh();
|
||||
bool event_loop();
|
||||
void video_image_display();
|
||||
void video_audioWaveform();
|
||||
void video_display();
|
||||
double compute_frame_delay(double frame_current_pts);
|
||||
bool output_picture2(AVFrame *src_frame, double pts1);
|
||||
void step_to_next_frame();
|
||||
void toggle_audio_display();
|
||||
bool alloc_picture();
|
||||
void Layout();
|
||||
|
||||
AVInputFormat *iformat;
|
||||
int last_i_start;
|
||||
enum PixelFormat frame_pix_fmt;
|
||||
SDL_Surface *screen;
|
||||
double aspect_ratio;
|
||||
int videoFlags;
|
||||
//bool forceAspect;
|
||||
uint64 msec;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,22 +0,0 @@
|
|||
ctrl MediaPlayer {
|
||||
group "Complex";
|
||||
|
||||
GetMinSize() { return Size(0, 0); }
|
||||
GetStdSize() { return Size(140, 140); }
|
||||
|
||||
Frame SetFrame @1;
|
||||
|
||||
Paint(w) {
|
||||
r = GetRect();
|
||||
|
||||
DrawCtrlFrame(w, r, .SetFrame);
|
||||
|
||||
sz = Size(r.right - r.left, r.bottom - r.top);
|
||||
|
||||
DeflateRect(r);
|
||||
sz = Size(r.right - r.left, r.bottom - r.top);
|
||||
w.DrawRect(r.left, r.top, sz.cx, sz.cy, :SWhite);
|
||||
img = "Media:MediaPlayer.iml:Image";
|
||||
w.DrawImage(r.left, r.top, sz.cx, sz.cy, img);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#include "MediaPlayer.h"
|
||||
#include "utility.h"
|
||||
#include "mediaplayer_in.h"
|
||||
|
||||
|
||||
PacketQueue::PacketQueue()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
void PacketQueue::Init()
|
||||
{
|
||||
first_pkt = last_pkt = 0;
|
||||
nb_packets = size = 0;
|
||||
abort_request = false;
|
||||
//mutex = 0;
|
||||
//cond = 0;
|
||||
}
|
||||
|
||||
void PacketQueue::Init(AVPacket &pkt, AVPacket *flush_pkt)
|
||||
{
|
||||
Init();
|
||||
//mutex = SDL_CreateMutex();
|
||||
//cond = SDL_CreateCond();
|
||||
Put(&pkt, flush_pkt);
|
||||
}
|
||||
|
||||
void PacketQueue::Flush()
|
||||
{
|
||||
AVPacketList *pkt, *pkt1;
|
||||
|
||||
INTERLOCKED_(mutex) {
|
||||
for(pkt = first_pkt; pkt != NULL; pkt = pkt1) {
|
||||
pkt1 = pkt->next;
|
||||
av_free_packet(&pkt->pkt);
|
||||
av_freep(&pkt);
|
||||
}
|
||||
first_pkt = last_pkt = 0;
|
||||
nb_packets = size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void PacketQueue::End()
|
||||
{
|
||||
Flush();
|
||||
//SDL_DestroyMutex(mutex);
|
||||
//SDL_DestroyCond(cond);
|
||||
}
|
||||
|
||||
int PacketQueue::Put(AVPacket *pkt, AVPacket *flush_pkt)
|
||||
{
|
||||
AVPacketList *pkt1;
|
||||
|
||||
// Duplicate the packet
|
||||
if (pkt != flush_pkt && av_dup_packet(pkt) < 0)
|
||||
return -1;
|
||||
|
||||
pkt1 = (AVPacketList*)av_malloc(sizeof(AVPacketList));
|
||||
if (!pkt1)
|
||||
return -1;
|
||||
pkt1->pkt = *pkt;
|
||||
pkt1->next = NULL;
|
||||
|
||||
INTERLOCKED_(mutex) {
|
||||
if (!last_pkt)
|
||||
first_pkt = pkt1;
|
||||
else
|
||||
last_pkt->next = pkt1;
|
||||
last_pkt = pkt1;
|
||||
nb_packets++;
|
||||
size += pkt1->pkt.size + sizeof(*pkt1);
|
||||
// Should duplicate packet data in DV case
|
||||
cond.Signal();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PacketQueue::Abort()
|
||||
{
|
||||
INTERLOCKED_(mutex) {
|
||||
abort_request = true;
|
||||
cond.Signal();
|
||||
}
|
||||
}
|
||||
|
||||
// return < 0 if aborted, 0 if no packet and > 0 if packet.
|
||||
int PacketQueue::Get(AVPacket *pkt, bool decodeEnd)
|
||||
{
|
||||
AVPacketList *pkt1;
|
||||
int ret;
|
||||
|
||||
INTERLOCKED_(mutex) {
|
||||
for(;;) {
|
||||
if (abort_request) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
pkt1 = first_pkt;
|
||||
if (pkt1) {
|
||||
first_pkt = pkt1->next;
|
||||
if (!first_pkt)
|
||||
last_pkt = NULL;
|
||||
nb_packets--;
|
||||
size -= pkt1->pkt.size + sizeof(*pkt1);
|
||||
*pkt = pkt1->pkt;
|
||||
av_free(pkt1);
|
||||
ret = 1;
|
||||
break;
|
||||
} else if (decodeEnd) {
|
||||
ret = 0;
|
||||
break;
|
||||
} else
|
||||
cond.Wait(mutex);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,222 +0,0 @@
|
|||
#ifndef _Media_Player_h_
|
||||
#define _Media_Player_h_
|
||||
|
||||
|
||||
#define MAX_VIDEOQ_SIZE (5 * 256 * 1024)
|
||||
#define MAX_AUDIOQ_SIZE (5 * 16 * 1024)
|
||||
#define MAX_SUBTITLEQ_SIZE (5 * 16 * 1024)
|
||||
|
||||
/* SDL audio buffer size, in samples. Should be small to have precise
|
||||
A/V sync as SDL does not have hardware buffer fullness info. */
|
||||
#define SDL_AUDIO_BUFFER_SIZE 1024
|
||||
|
||||
/* no AV sync correction is done if below the AV sync threshold */
|
||||
#define AV_SYNC_THRESHOLD 0.01
|
||||
/* no AV correction is done if too big error */
|
||||
#define AV_NOSYNC_THRESHOLD 10.0
|
||||
|
||||
#define FRAME_SKIP_FACTOR 0.05
|
||||
|
||||
/* maximum audio speed change to get correct sync */
|
||||
#define SAMPLE_CORRECTION_PERCENT_MAX 10
|
||||
|
||||
/* we use about AUDIO_DIFF_AVG_NB A-V differences to make the average */
|
||||
#define AUDIO_DIFF_AVG_NB 20
|
||||
|
||||
/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
|
||||
#define SAMPLE_ARRAY_SIZE (2*65536)
|
||||
|
||||
struct PacketQueue {
|
||||
AVPacketList *first_pkt, *last_pkt;
|
||||
int nb_packets;
|
||||
int size;
|
||||
int abort_request;
|
||||
SDL_mutex *mutex;
|
||||
SDL_cond *cond;
|
||||
};
|
||||
|
||||
#define VIDEO_PICTURE_QUEUE_SIZE 2
|
||||
#define SUBPICTURE_QUEUE_SIZE 4
|
||||
|
||||
struct VideoPicture {
|
||||
double pts; ///<presentation time stamp for this picture
|
||||
double target_clock; ///<av_gettime() time at which this should be displayed ideally
|
||||
int64_t pos; ///<byte position in file
|
||||
SDL_Overlay *bmp;
|
||||
int width, height; /* source height & width */
|
||||
int allocated;
|
||||
enum PixelFormat pix_fmt;
|
||||
};
|
||||
|
||||
struct SubPicture {
|
||||
double pts; /* presentation time stamp for this picture */
|
||||
AVSubtitle sub;
|
||||
};
|
||||
|
||||
enum {
|
||||
AV_SYNC_AUDIO_MASTER, /* default choice */
|
||||
AV_SYNC_VIDEO_MASTER,
|
||||
AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */
|
||||
};
|
||||
|
||||
bool play_stream(const char * input_filename);
|
||||
|
||||
class VideoState {
|
||||
public:
|
||||
VideoState();
|
||||
void Reset();
|
||||
void close();
|
||||
|
||||
bool event_loop();
|
||||
void schedule_refresh(int delay);
|
||||
int audio_write_get_buf_size();
|
||||
void video_image_display();
|
||||
void video_audio_display();
|
||||
int video_open();
|
||||
void video_display();
|
||||
double get_audio_clock();
|
||||
double get_video_clock();
|
||||
double get_external_clock();
|
||||
double get_master_clock();
|
||||
void stream_seek(int64_t pos, int64_t rel, int seek_by_bytes);
|
||||
void stream_pause();
|
||||
double compute_frame_delay(double frame_current_pts);
|
||||
int queue_picture(AVFrame *src_frame, double pts);
|
||||
int output_picture2(AVFrame *src_frame, double pts1);
|
||||
void update_sample_display(short *samples, int samples_size);
|
||||
int synchronize_audio(short *samples, int samples_size1, double pts);
|
||||
int audio_decode_frame(double *pts_ptr);
|
||||
int stream_component_open(int stream_index);
|
||||
void stream_component_close(int stream_index);
|
||||
void stream_cycle_channel(int codec_type);
|
||||
void toggle_pause();
|
||||
void step_to_next_frame();
|
||||
void toggle_audio_display();
|
||||
bool alloc_picture();
|
||||
|
||||
SDL_Thread *parse_tid;
|
||||
SDL_Thread *video_tid;
|
||||
SDL_Thread *refresh_tid;
|
||||
AVInputFormat *iformat;
|
||||
int no_background;
|
||||
int abort_request;
|
||||
int paused;
|
||||
int last_paused;
|
||||
int seek_req;
|
||||
int seek_flags;
|
||||
int64_t seek_pos;
|
||||
int64_t seek_rel;
|
||||
int read_pause_return;
|
||||
AVFormatContext *icc;
|
||||
|
||||
int audio_stream;
|
||||
|
||||
int av_sync_type;
|
||||
double external_clock; /* external clock base */
|
||||
int64_t external_clock_time;
|
||||
|
||||
double audio_clock;
|
||||
double audio_diff_cum; /* used for AV difference average computation */
|
||||
double audio_diff_avg_coef;
|
||||
double audio_diff_threshold;
|
||||
int audio_diff_avg_count;
|
||||
AVStream *audio_st;
|
||||
PacketQueue audioq;
|
||||
int audio_hw_buf_size;
|
||||
/* samples output by the codec. we reserve more space for avsync compensation */
|
||||
DECLARE_ALIGNED(16,uint8_t,audio_buf1)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
|
||||
DECLARE_ALIGNED(16,uint8_t,audio_buf2)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
|
||||
uint8_t *audio_buf;
|
||||
unsigned int audio_buf_size; /* in bytes */
|
||||
int audio_buf_index; /* in bytes */
|
||||
AVPacket audio_pkt_temp;
|
||||
AVPacket audio_pkt;
|
||||
enum SampleFormat audio_src_fmt;
|
||||
AVAudioConvert *reformat_ctx;
|
||||
|
||||
int show_audio; /* if true, display audio samples */
|
||||
int16_t sample_array[SAMPLE_ARRAY_SIZE];
|
||||
int sample_array_index;
|
||||
int last_i_start;
|
||||
|
||||
SDL_Thread *subtitle_tid;
|
||||
int subtitle_stream;
|
||||
int subtitle_stream_changed;
|
||||
AVStream *subtitle_st;
|
||||
PacketQueue subtitleq;
|
||||
SubPicture subpq[SUBPICTURE_QUEUE_SIZE];
|
||||
int subpq_size, subpq_rindex, subpq_windex;
|
||||
SDL_mutex *subpq_mutex;
|
||||
SDL_cond *subpq_cond;
|
||||
|
||||
double frame_timer;
|
||||
double frame_last_pts;
|
||||
double frame_last_delay;
|
||||
double video_clock; ///<pts of last decoded frame / predicted pts of next decoded frame
|
||||
int video_stream;
|
||||
AVStream *video_st;
|
||||
PacketQueue videoq;
|
||||
double video_current_pts; ///<current displayed pts (different from video_clock if frame fifos are used)
|
||||
int64_t video_current_pts_time; ///<time (av_gettime) at which we updated video_current_pts - used to have running video pts
|
||||
int64_t video_current_pos; ///<current displayed file pos
|
||||
VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE];
|
||||
int pictq_size, pictq_rindex, pictq_windex;
|
||||
SDL_mutex *pictq_mutex;
|
||||
SDL_cond *pictq_cond;
|
||||
|
||||
String filename;
|
||||
int width, height, xleft, ytop;
|
||||
|
||||
float skip_frames;
|
||||
int refresh;
|
||||
|
||||
const char *input_filename;
|
||||
const char *window_title;
|
||||
int fs_screen_width;
|
||||
int fs_screen_height;
|
||||
int screen_width;
|
||||
int screen_height;
|
||||
int frame_width;
|
||||
int frame_height;
|
||||
enum PixelFormat frame_pix_fmt;
|
||||
int audio_disable;
|
||||
int video_disable;
|
||||
int wanted_audio_stream;
|
||||
int wanted_video_stream;
|
||||
int wanted_subtitle_stream;
|
||||
int seek_by_bytes;
|
||||
int show_status ;
|
||||
int64_t start_time;
|
||||
int64_t duration;
|
||||
int debug;
|
||||
int debug_mv;
|
||||
int step;
|
||||
int thread_count;
|
||||
int workaround_bugs;
|
||||
int fast;
|
||||
int genpts;
|
||||
int lowres;
|
||||
int idct;
|
||||
enum AVDiscard skip_frame;
|
||||
enum AVDiscard skip_idct;
|
||||
enum AVDiscard skip_loop_filter;
|
||||
int decoder_reorder_pts;
|
||||
int loop;
|
||||
int framedrop;
|
||||
|
||||
int rdftspeed;
|
||||
int64_t audio_callback_time;
|
||||
|
||||
AVPacket flush_pkt;
|
||||
|
||||
SDL_Surface *screen;
|
||||
|
||||
String strError;
|
||||
};
|
||||
|
||||
|
||||
#define FF_ALLOC_EVENT (SDL_USEREVENT)
|
||||
#define FF_REFRESH_EVENT (SDL_USEREVENT + 1)
|
||||
#define FF_QUIT_EVENT (SDL_USEREVENT + 2)
|
||||
|
||||
#endif
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
#include "VolumeCtrl.h"
|
||||
|
||||
|
||||
SliderVolume::SliderVolume() {
|
||||
moving = false;
|
||||
Jump();
|
||||
}
|
||||
|
||||
void SliderVolume::LeftDown(Point pos, dword keyflags) {
|
||||
SliderCtrl::LeftDown(pos, keyflags);
|
||||
moving = true;
|
||||
}
|
||||
|
||||
void SliderVolume::LeftUp(Point pos, dword keyflags) {
|
||||
SliderCtrl::LeftUp(pos, keyflags);
|
||||
moving = false;
|
||||
}
|
||||
|
||||
void SliderVolume::SetData(const Value& v) {
|
||||
Size sz = GetSize();
|
||||
bool horiz = sz.cx > sz.cy;
|
||||
|
||||
if (horiz)
|
||||
SliderCtrl::SetData(v);
|
||||
else
|
||||
SliderCtrl::SetData(GetMax() - int(v));
|
||||
}
|
||||
|
||||
Value SliderVolume::GetData() const {
|
||||
Size sz = GetSize();
|
||||
bool horiz = sz.cx > sz.cy;
|
||||
|
||||
Value val = SliderCtrl::GetData();
|
||||
if (horiz)
|
||||
return val;
|
||||
else
|
||||
return GetMax() - int(val);
|
||||
}
|
||||
|
||||
VolumeCtrl::VolumeCtrl() {
|
||||
Add(sliderL);
|
||||
Add(sliderR);
|
||||
sliderL.MinMax(0, MAX_MAINVOLUME);
|
||||
sliderR.MinMax(0, MAX_MAINVOLUME);
|
||||
sliderL.WhenAction = THISBACK(Action);
|
||||
sliderR.WhenAction = THISBACK(Action);
|
||||
Add(labelL);
|
||||
Add(labelR);
|
||||
labelL.SetLabel("L");
|
||||
labelR.SetLabel("R");
|
||||
SetTimeCallback(-100, THISBACK(TimerAction));
|
||||
stereo = false;
|
||||
showLR = true;
|
||||
TimerAction();
|
||||
}
|
||||
|
||||
void VolumeCtrl::Action() {
|
||||
if (stereo) {
|
||||
int left, right;
|
||||
if (!GetMainVolume(left, right))
|
||||
return;
|
||||
int valL = sliderL.GetData();
|
||||
int valR = sliderR.GetData();
|
||||
if (valL != left || valR != right)
|
||||
SetMainVolume(valL, valR);
|
||||
} else {
|
||||
int val = sliderL.GetData();
|
||||
if (val != GetMainVolume())
|
||||
SetMainVolume(val);
|
||||
}
|
||||
}
|
||||
|
||||
void VolumeCtrl::TimerAction() {
|
||||
if(sliderL.IsMoving() && (sliderR.IsMoving() || !stereo))
|
||||
return;
|
||||
if (stereo) {
|
||||
int left, right;
|
||||
if (!GetMainVolume(left, right))
|
||||
return;
|
||||
if (left != sliderL.GetData())
|
||||
sliderL.SetData(left);
|
||||
if (right != sliderR.GetData())
|
||||
sliderR.SetData(right);
|
||||
} else {
|
||||
int val = GetMainVolume();
|
||||
if ((val != -1) && (val != sliderL.GetData()))
|
||||
sliderL.SetData(val);
|
||||
}
|
||||
}
|
||||
|
||||
void VolumeCtrl::Layout() {
|
||||
Rect r = GetRect();
|
||||
Size sz = GetSize();
|
||||
|
||||
if (stereo) {
|
||||
sliderR.Show();
|
||||
labelL.Show(showLR);
|
||||
labelR.Show(showLR);
|
||||
if (sz.cx < sz.cy) {
|
||||
Font f = Arial(sz.cx/4);
|
||||
Size fontSize = GetTextSize("X", f);
|
||||
if (showLR)
|
||||
labelL.SetFont(f).BottomPosZ(0, fontSize.cy).LeftPosZ(int(0.15*sz.cx), 2*fontSize.cx);
|
||||
sliderL.VSizePosZ(0, (showLR ? fontSize.cy : 0)).LeftPosZ(0, sz.cx/2);
|
||||
if (showLR)
|
||||
labelR.SetFont(f).BottomPosZ(0, fontSize.cy).LeftPosZ(int(0.65*sz.cx), 2*fontSize.cx);
|
||||
sliderR.VSizePosZ(0, (showLR ? fontSize.cy : 0)).LeftPosZ(sz.cx/2, sz.cx/2);
|
||||
} else {
|
||||
Font f = Arial(sz.cy/4);
|
||||
Size fontSize = GetTextSize("X", f);
|
||||
if (showLR)
|
||||
labelL.SetFont(f).HSizePosZ(0, 0).TopPosZ(int(0.1*sz.cy), fontSize.cy);
|
||||
sliderL.HSizePosZ((showLR ? int(1.5*fontSize.cx) : 0), 0).TopPosZ(0, sz.cy/2);
|
||||
if (showLR)
|
||||
labelR.SetFont(f).HSizePosZ(0, 0).TopPosZ(int(0.6*sz.cy), fontSize.cy);
|
||||
sliderR.HSizePosZ((showLR ? int(1.5*fontSize.cx) : 0), 0).TopPosZ(sz.cy/2, sz.cy/2);
|
||||
}
|
||||
} else {
|
||||
sliderL.SizePos();
|
||||
sliderR.Hide();
|
||||
labelL.Hide();
|
||||
labelR.Hide();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
#ifndef _Media_VolumeCtrl_h_
|
||||
#define _Media_VolumeCtrl_h_
|
||||
|
||||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#include "audioSystem.h"
|
||||
|
||||
|
||||
class SliderVolume : public SliderCtrl {
|
||||
typedef SliderVolume CLASSNAME;
|
||||
public:
|
||||
SliderVolume();
|
||||
bool IsMoving() {return moving;};
|
||||
virtual void SetData(const Value& v);
|
||||
virtual Value GetData() const;
|
||||
|
||||
private:
|
||||
bool moving;
|
||||
|
||||
void LeftDown(Point pos, dword keyflags);
|
||||
void LeftUp(Point pos, dword keyflags);
|
||||
};
|
||||
|
||||
class VolumeCtrl : public StaticRect {
|
||||
typedef VolumeCtrl CLASSNAME;
|
||||
public:
|
||||
VolumeCtrl();
|
||||
VolumeCtrl &SetStereo(bool _stereo = false) {stereo = _stereo; return *this;};
|
||||
VolumeCtrl &ShowLR(bool _showLR = true) {showLR = _showLR; return *this;};
|
||||
|
||||
private:
|
||||
bool stereo;
|
||||
bool showLR;
|
||||
|
||||
SliderVolume sliderL, sliderR;
|
||||
Label labelL, labelR;
|
||||
|
||||
void Action();
|
||||
void TimerAction();
|
||||
|
||||
virtual void Layout();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
ctrl VolumeCtrl {
|
||||
group "Media";
|
||||
|
||||
GetMinSize() { return Size(0, 0); }
|
||||
GetStdSize() { return Size(64, 24); }
|
||||
|
||||
Frame SetFrame @1;
|
||||
bool SetStereo = false;
|
||||
bool ShowLR = true;
|
||||
|
||||
PaintSlider(w, r) {
|
||||
sz = Size(r.right - r.left, r.bottom - r.top);
|
||||
|
||||
halfX = int(r.left + r.right) >> 1;
|
||||
halfY = int(r.top + r.bottom) >> 1;
|
||||
|
||||
if (sz.cx < sz.cy) {
|
||||
DrawInsetFrame(w, Rect(halfX - 2, r.top + 2, halfX + 2, r.bottom - 2));
|
||||
imgSz = GetImageSize("CtrlImg::vthumb");
|
||||
w.DrawImage(halfX - (imgSz.cx >> 1), halfY - (imgSz.cy >> 1), "CtrlImg::vthumb");
|
||||
} else {
|
||||
DrawInsetFrame(w, Rect(r.left + 2, halfY - 2, r.right - 2, halfY + 2));
|
||||
imgSz = GetImageSize("CtrlImg::hthumb");
|
||||
w.DrawImage(halfX - (imgSz.cx >> 1), halfY - (imgSz.cy >> 1), "CtrlImg::hthumb");
|
||||
}
|
||||
}
|
||||
Paint(w) {
|
||||
r = GetRect();
|
||||
DrawCtrlFrame(w, r, .SetFrame);
|
||||
|
||||
if (.SetStereo) {
|
||||
sz = Size(r.right - r.left, r.bottom - r.top);
|
||||
if (sz.cx < sz.cy) {
|
||||
fontSize = GetTextSize("X", Arial(sz.cx/4));
|
||||
if (.ShowLR)
|
||||
w.DrawText(r.left + 0.15*sz.cx, r.top + sz.cy - fontSize.cy, "L", Arial(sz.cx/4), :SBlack);
|
||||
PaintSlider(w, Rect(r.left, r.top, r.left + sz.cx/2, r.bottom - (.ShowLR ? fontSize.cy : 0)));
|
||||
if (.ShowLR)
|
||||
w.DrawText(r.left + 0.65*sz.cx, r.top + sz.cy - fontSize.cy, "R", Arial(sz.cx/4), :SBlack);
|
||||
PaintSlider(w, Rect(r.left + sz.cx/2, r.top, r.right, r.bottom - (.ShowLR ? fontSize.cy : 0)));
|
||||
} else {
|
||||
fontSize = GetTextSize("X", Arial(sz.cy/4));
|
||||
if (.ShowLR)
|
||||
w.DrawText(r.left, r.top + 0.1*sz.cy, "L", Arial(sz.cy/4), :SBlack);
|
||||
PaintSlider(w, Rect(r.left + (.ShowLR ? 1.5*fontSize.cx : 0), r.top, r.right, r.bottom/2));
|
||||
if (.ShowLR)
|
||||
w.DrawText(r.left, r.top + 0.6*sz.cy, "R", Arial(sz.cy/4), :SBlack);
|
||||
PaintSlider(w, Rect(r.left + (.ShowLR ? 1.5*fontSize.cx : 0), r.top + sz.cy/2, r.right, r.bottom));
|
||||
}
|
||||
} else
|
||||
PaintSlider(w, r);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,178 +0,0 @@
|
|||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#include <Functions4U/Functions4U.h>
|
||||
#include "audioSystem.h"
|
||||
|
||||
int GetMainVolume() {
|
||||
int left, right;
|
||||
|
||||
if(!GetMainVolume(left, right))
|
||||
return -1;
|
||||
return Average(left, right);
|
||||
}
|
||||
|
||||
bool SetMainVolume(int vol) {
|
||||
return SetMainVolume(vol, vol);
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_POSIX
|
||||
//#include <fcntl.h>
|
||||
#include <linux/soundcard.h>
|
||||
//#include <stdio.h>
|
||||
//#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
// See more details here
|
||||
|
||||
bool GetMainVolume(int &left, int &right) {
|
||||
int fAudio = open("/dev/mixer", O_RDWR, 0);
|
||||
if (fAudio == -1)
|
||||
return false;
|
||||
int vol;
|
||||
bool ret;
|
||||
if(ioctl(fAudio, MIXER_READ(SOUND_MIXER_VOLUME), &vol) == -1)
|
||||
ret = false;
|
||||
else
|
||||
ret = true;
|
||||
close(fAudio);
|
||||
|
||||
// Linux levels are in percentage
|
||||
if (ret) {
|
||||
left = (MAX_MAINVOLUME/100)*(vol & 0x7f);
|
||||
right = (MAX_MAINVOLUME/100)*((vol >> 8) & 0x7f);
|
||||
} else
|
||||
left = right = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool SetMainVolume(int left, int right) {
|
||||
int vol = ((right/(MAX_MAINVOLUME/100)) << 8) | (left/(MAX_MAINVOLUME/100));
|
||||
int fAudio = open("/dev/mixer", O_RDWR, 0);
|
||||
if (fAudio == -1)
|
||||
return -1;
|
||||
bool ret;
|
||||
if(ioctl(fAudio, MIXER_WRITE(SOUND_MIXER_VOLUME), &vol) == -1)
|
||||
ret = false;
|
||||
else
|
||||
ret = true;
|
||||
close(fAudio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <mmsystem.h>
|
||||
|
||||
// See more details here http://echochamber.me/viewtopic.php?f=11&t=15858
|
||||
|
||||
bool GetVolumeCtrl(HMIXER &hMixer, MIXERCONTROL &mc) {
|
||||
MMRESULT result;
|
||||
|
||||
if (MMSYSERR_NOERROR != (result = mixerOpen(&hMixer, MIXER_OBJECTF_MIXER, 0, 0, 0)))
|
||||
return false;
|
||||
|
||||
// Get the speaker line of the mixer device.
|
||||
MIXERLINE ml = {0};
|
||||
ml.cbStruct = sizeof(MIXERLINE);
|
||||
ml.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
|
||||
result = mixerGetLineInfo((HMIXEROBJ) hMixer, &ml, MIXER_GETLINEINFOF_COMPONENTTYPE);
|
||||
if (result != MMSYSERR_NOERROR) {
|
||||
mixerClose(hMixer);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the volume control of the speaker line.
|
||||
MIXERLINECONTROLS mlc = {0};
|
||||
mlc.cbStruct = sizeof(MIXERLINECONTROLS);
|
||||
mlc.dwLineID = ml.dwLineID;
|
||||
mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
|
||||
mlc.cControls = 1;
|
||||
mlc.pamxctrl = &mc;
|
||||
mlc.cbmxctrl = sizeof(MIXERCONTROL);
|
||||
result = mixerGetLineControls((HMIXEROBJ) hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
|
||||
if (result != MMSYSERR_NOERROR) {
|
||||
mixerClose(hMixer);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetMainVolume(int left, int right) {
|
||||
HMIXER hMixer;
|
||||
MIXERCONTROL mc = {0};
|
||||
|
||||
GetVolumeCtrl(hMixer, mc);
|
||||
|
||||
MIXERCONTROLDETAILS mcd = {0};
|
||||
MIXERCONTROLDETAILS_UNSIGNED mcdVol[2] = {0};
|
||||
double range = mc.Bounds.dwMaximum - mc.Bounds.dwMinimum;
|
||||
DWORD dwLeft = DWORD(left *range/MAX_MAINVOLUME);
|
||||
DWORD dwRight = DWORD(right*range/MAX_MAINVOLUME);
|
||||
|
||||
memcpy(&mcdVol[0], &dwLeft, sizeof(MIXERCONTROLDETAILS_UNSIGNED));
|
||||
memcpy(&mcdVol[1], &dwRight, sizeof(MIXERCONTROLDETAILS_UNSIGNED));
|
||||
|
||||
mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
|
||||
mcd.hwndOwner = 0;
|
||||
mcd.dwControlID = mc.dwControlID;
|
||||
mcd.paDetails = &mcdVol;
|
||||
mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
|
||||
mcd.cChannels = 2;
|
||||
MMRESULT result = mixerSetControlDetails((HMIXEROBJ) hMixer, &mcd,
|
||||
MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);
|
||||
mixerClose(hMixer);
|
||||
|
||||
return result == MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
bool GetMainVolume(int &left, int &right) {
|
||||
HMIXER hMixer;
|
||||
MIXERCONTROL mc = {0};
|
||||
|
||||
GetVolumeCtrl(hMixer, mc);
|
||||
|
||||
MIXERCONTROLDETAILS mcd = {0};
|
||||
MIXERCONTROLDETAILS_UNSIGNED mcdVol[2] = {0};
|
||||
|
||||
mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
|
||||
mcd.hwndOwner = 0;
|
||||
mcd.dwControlID = mc.dwControlID;
|
||||
mcd.paDetails = &mcdVol;
|
||||
mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
|
||||
mcd.cChannels = 2;
|
||||
MMRESULT result = mixerGetControlDetails((HMIXEROBJ) hMixer, &mcd,
|
||||
MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE);
|
||||
|
||||
if (result == MMSYSERR_NOERROR) {
|
||||
double range = mc.Bounds.dwMaximum - mc.Bounds.dwMinimum;
|
||||
left = int((mcdVol[0].dwValue - mc.Bounds.dwMinimum)*MAX_MAINVOLUME/range);
|
||||
right = int((mcdVol[1].dwValue - mc.Bounds.dwMinimum)*MAX_MAINVOLUME/range);
|
||||
} else
|
||||
left = right = -1;
|
||||
|
||||
mixerClose(hMixer);
|
||||
|
||||
return result == MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
const char* GetAudioErrorDescription(MMRESULT code) {
|
||||
switch(code) {
|
||||
case MMSYSERR_ERROR: return "Unspecified Error";
|
||||
case MMSYSERR_BADDEVICEID: return "Device ID out of range";
|
||||
case MMSYSERR_NOTENABLED: return "Driver failed enable";
|
||||
case MMSYSERR_ALLOCATED: return "Device already allocated";
|
||||
case MMSYSERR_INVALHANDLE: return "Device handle is invalid";
|
||||
case MMSYSERR_NODRIVER: return "No device driver present";
|
||||
case MMSYSERR_NOMEM: return "Memory allocation error";
|
||||
case MMSYSERR_NOTSUPPORTED: return "Function isn't supported";
|
||||
case MMSYSERR_BADERRNUM: return "Error value out of range";
|
||||
case MMSYSERR_INVALFLAG: return "Invalid flag passed";
|
||||
case MMSYSERR_INVALPARAM: return "Invalid parameter passed";
|
||||
case MMSYSERR_LASTERROR: return "Last error in range";
|
||||
default: return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef _Media_audioSystem_h_
|
||||
#define _Media_audioSystem_h_
|
||||
|
||||
#define MAX_MAINVOLUME 10000
|
||||
|
||||
bool GetMainVolume(int &left, int &right);
|
||||
int GetMainVolume();
|
||||
bool SetMainVolume(int left, int right);
|
||||
bool SetMainVolume(int vol);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#include <Media/MediaFile.h>
|
||||
#include "utility.h"
|
||||
|
||||
|
||||
// Get the current audio clock value
|
||||
double MediaFile::get_audio_clock()
|
||||
{
|
||||
double pts = audio_clock;
|
||||
int bytes_per_sec = 0;
|
||||
if (audioStream)
|
||||
bytes_per_sec = audioStream->codec->sample_rate * 2 * audioStream->codec->channels;
|
||||
|
||||
if (bytes_per_sec)
|
||||
pts -= double(GetAudioOutputBufferSize()) / bytes_per_sec;
|
||||
return pts;
|
||||
}
|
||||
|
||||
// Get the current video clock value
|
||||
double MediaFile::get_video_clock()
|
||||
{
|
||||
double delta;
|
||||
if (paused)
|
||||
delta = 0;
|
||||
else
|
||||
delta = (GetUSec() - video_current_pts_time) / 1000000.0;
|
||||
|
||||
return video_current_pts + delta;
|
||||
}
|
||||
|
||||
// Get the current external clock value
|
||||
double MediaFile::get_external_clock()
|
||||
{
|
||||
return externalClock.Elapsed() / 1000.0;
|
||||
}
|
||||
|
||||
// Get the current master clock value
|
||||
double MediaFile::get_master_clock()
|
||||
{
|
||||
double val;
|
||||
|
||||
if (av_sync_type == AV_SYNC_VIDEO_MASTER) {
|
||||
if (videoStream)
|
||||
val = get_video_clock();
|
||||
else
|
||||
val = get_audio_clock();
|
||||
} else if (av_sync_type == AV_SYNC_AUDIO_MASTER) {
|
||||
if (audioStream)
|
||||
val = get_audio_clock();
|
||||
else
|
||||
val = get_video_clock();
|
||||
} else
|
||||
val = get_external_clock();
|
||||
|
||||
return val;
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
#ifndef _Ffmpeg_Ffmpeg_h_
|
||||
#define _Ffmpeg_Ffmpeg_h_
|
||||
|
||||
#include <SDL/SDLCtrl.h>
|
||||
|
||||
extern "C" {
|
||||
#include <libavutil/eval.h>
|
||||
#include <libavutil/fifo.h>
|
||||
#include <libavutil/pixfmt.h>
|
||||
#include <libavutil/avstring.h>
|
||||
#include <libavutil/colorspace.h>
|
||||
#include <libavutil/pixdesc.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <libavutil/error.h>
|
||||
|
||||
#include <libavcore/imgutils.h>
|
||||
#include <libavcore/parseutils.h>
|
||||
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
#include <libavdevice/avdevice.h>
|
||||
|
||||
#include <libswscale/swscale.h>
|
||||
|
||||
#include <libavcodec/audioconvert.h>
|
||||
#include <libavcodec/avfft.h>
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
extern AVRational myAVTIMEBASEQ;
|
||||
#undef AV_TIME_BASE_Q
|
||||
#define AV_TIME_BASE_Q myAVTIMEBASEQ
|
||||
#define snprintf( buf, count, format, ... ) _snprintf_s( buf, 512, count, format, __VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
#ifndef _Media_mediaplayer_in_h_
|
||||
#define _Media_mediaplayer_in_h_
|
||||
|
||||
int video_thread(void *arg);
|
||||
int subtitle_thread(void *arg);
|
||||
void sdl_audio_callback(void *opaque, uint16 *stream, int len);
|
||||
|
||||
#define ALPHA_BLEND(a, oldp, newp, s)\
|
||||
((((oldp << s) * (255 - (a))) + (newp * (a))) / (255 << s))
|
||||
|
||||
#define RGBA_IN(r, g, b, a, s)\
|
||||
{\
|
||||
unsigned int v = ((const uint32_t *)(s))[0];\
|
||||
a = (v >> 24) & 0xff;\
|
||||
r = (v >> 16) & 0xff;\
|
||||
g = (v >> 8) & 0xff;\
|
||||
b = v & 0xff;\
|
||||
}
|
||||
|
||||
#define YUVA_IN(y, u, v, a, s, pal)\
|
||||
{\
|
||||
unsigned int val = ((const uint32_t *)(pal))[*(const uint8_t*)(s)];\
|
||||
a = (val >> 24) & 0xff;\
|
||||
y = (val >> 16) & 0xff;\
|
||||
u = (val >> 8) & 0xff;\
|
||||
v = val & 0xff;\
|
||||
}
|
||||
|
||||
#define YUVA_OUT(d, y, u, v, a)\
|
||||
{\
|
||||
((uint32_t *)(d))[0] = (a << 24) | (y << 16) | (u << 8) | v;\
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef _Media_mt_h_
|
||||
#define _Media_mt_h_
|
||||
|
||||
// Classes thanks to U++ Forum supporters
|
||||
|
||||
// Safe atomic
|
||||
class AtomicVar {
|
||||
private:
|
||||
Atomic val;
|
||||
public:
|
||||
AtomicVar() {};
|
||||
|
||||
AtomicVar(const AtomicVar& p) {AtomicWrite(val, AtomicRead(p.val));}
|
||||
template <class T>
|
||||
AtomicVar& operator=(const T& p) {AtomicWrite(val, p); return *this;}
|
||||
|
||||
operator int() {return AtomicRead(val);}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#include "mediaplayer.h"
|
||||
#include "utility.h"
|
||||
#include "mediaplayer_in.h"
|
||||
|
||||
|
||||
PacketQueue::PacketQueue()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
void PacketQueue::Init()
|
||||
{
|
||||
first_pkt = last_pkt = 0;
|
||||
nb_packets = size = 0;
|
||||
abort_request = false;
|
||||
mutex = 0;
|
||||
cond = 0;
|
||||
}
|
||||
|
||||
void PacketQueue::Init(AVPacket &pkt, AVPacket *flush_pkt)
|
||||
{
|
||||
Init();
|
||||
mutex = SDL_CreateMutex();
|
||||
cond = SDL_CreateCond();
|
||||
Put(&pkt, flush_pkt);
|
||||
}
|
||||
|
||||
void PacketQueue::Flush()
|
||||
{
|
||||
AVPacketList *pkt, *pkt1;
|
||||
|
||||
SDL_LockMutex(mutex);
|
||||
for(pkt = first_pkt; pkt != NULL; pkt = pkt1) {
|
||||
pkt1 = pkt->next;
|
||||
av_free_packet(&pkt->pkt);
|
||||
av_freep(&pkt);
|
||||
}
|
||||
first_pkt = last_pkt = 0;
|
||||
nb_packets = size = 0;
|
||||
SDL_UnlockMutex(mutex);
|
||||
}
|
||||
|
||||
void PacketQueue::End()
|
||||
{
|
||||
Flush();
|
||||
SDL_DestroyMutex(mutex);
|
||||
SDL_DestroyCond(cond);
|
||||
}
|
||||
|
||||
int PacketQueue::Put(AVPacket *pkt, AVPacket *flush_pkt)
|
||||
{
|
||||
AVPacketList *pkt1;
|
||||
|
||||
/* duplicate the packet */
|
||||
if (pkt != flush_pkt && av_dup_packet(pkt) < 0)
|
||||
return -1;
|
||||
|
||||
pkt1 = (AVPacketList*)av_malloc(sizeof(AVPacketList));
|
||||
if (!pkt1)
|
||||
return -1;
|
||||
pkt1->pkt = *pkt;
|
||||
pkt1->next = NULL;
|
||||
|
||||
SDL_LockMutex(mutex);
|
||||
|
||||
if (!last_pkt)
|
||||
first_pkt = pkt1;
|
||||
else
|
||||
last_pkt->next = pkt1;
|
||||
last_pkt = pkt1;
|
||||
nb_packets++;
|
||||
size += pkt1->pkt.size + sizeof(*pkt1);
|
||||
/* XXX: should duplicate packet data in DV case */
|
||||
SDL_CondSignal(cond);
|
||||
|
||||
SDL_UnlockMutex(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PacketQueue::Abort()
|
||||
{
|
||||
SDL_LockMutex(mutex);
|
||||
|
||||
abort_request = true;
|
||||
|
||||
SDL_CondSignal(cond);
|
||||
|
||||
SDL_UnlockMutex(mutex);
|
||||
}
|
||||
|
||||
// return < 0 if aborted, 0 if no packet and > 0 if packet.
|
||||
int PacketQueue::Get(AVPacket *pkt, int block)
|
||||
{
|
||||
AVPacketList *pkt1;
|
||||
int ret;
|
||||
|
||||
SDL_LockMutex(mutex);
|
||||
|
||||
for(;;) {
|
||||
if (abort_request) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
pkt1 = first_pkt;
|
||||
if (pkt1) {
|
||||
first_pkt = pkt1->next;
|
||||
if (!first_pkt)
|
||||
last_pkt = NULL;
|
||||
nb_packets--;
|
||||
size -= pkt1->pkt.size + sizeof(*pkt1);
|
||||
*pkt = pkt1->pkt;
|
||||
av_free(pkt1);
|
||||
ret = 1;
|
||||
break;
|
||||
} else if (!block) {
|
||||
ret = 0;
|
||||
break;
|
||||
} else
|
||||
SDL_CondWait(cond, mutex);
|
||||
}
|
||||
SDL_UnlockMutex(mutex);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
topic "Ffmpeg install";
|
||||
[ $$0,0#00000000000000000000000000000000:Default]
|
||||
[a83;*R6 $$1,0#31310162474203024125188417583966:caption]
|
||||
[{_}%EN-US
|
||||
[s1; [+184 Ffmpeg install]&]
|
||||
[s0; [2 Ffmpeg is a great library but it does not include complete
|
||||
installing instructions. Here are some useful links.]&]
|
||||
[s0;2 &]
|
||||
[s0;2 &]
|
||||
[s0; [* In Linux]&]
|
||||
[s0;2 &]
|
||||
[s0; [2 Install ffmpeg packages:]&]
|
||||
[s0;i150;O0; [2 libavcodec52 or libavcodec`-extra`-52]&]
|
||||
[s0;i150;O0; [2 libavcodec`-dev]&]
|
||||
[s0;i150;O0; [2 libavformat52 or libavformat`-extra`-52]&]
|
||||
[s0;i150;O0; [2 libavformat`-dev]&]
|
||||
[s0;i150;O0; [2 libavdevice52 or libavdevice`-extra`-52]&]
|
||||
[s0;i150;O0; [2 libavdevice`-dev]&]
|
||||
[s0;i150;O0; [2 libavfilter0 or libavfilter`-extra`-0]&]
|
||||
[s0;i150;O0; [2 libavfilter`-dev]&]
|
||||
[s0;i150;O0; [2 libavutil49 or libavutil`-extra`-49]&]
|
||||
[s0;i150;O0; [2 libavutil`-dev]&]
|
||||
[s0;i150;O0; [2 libpostproc51 or libpostproc`-extra`-51]&]
|
||||
[s0;i150;O0; [2 libpostproc`-dev]&]
|
||||
[s0;i150;O0; [2 libswscale0 or libswscale`-extra`-0]&]
|
||||
[s0;i150;O0; [2 libswscale`-dev]&]
|
||||
[s0;2 &]
|
||||
[s0; [2 Other possible packages are:]&]
|
||||
[s0;i150;O0; [2 libdc1394`-22`-dev]&]
|
||||
[s0;i150;O0; [2 libfaad`-dev]&]
|
||||
[s0;i150;O0; [2 libgsm1`-dev]&]
|
||||
[s0;i150;O0; [2 libogg`-dev]&]
|
||||
[s0;i150;O0; [2 libraw1394`-dev]&]
|
||||
[s0;i150;O0; [2 libschroedinger`-dev]&]
|
||||
[s0;i150;O0; [2 libspeex`-dev]&]
|
||||
[s0;i150;O0; [2 libtheora`-dev ]&]
|
||||
[s0;i150;O0; [2 libvorbis`-dev]&]
|
||||
[s0;2 &]
|
||||
[s0;2 &]
|
||||
[s0; [2 It is also possible to compile it from sources, but I have
|
||||
not found a reliable way to do it.]&]
|
||||
[s0;2 &]
|
||||
[s0;2 &]
|
||||
[s0; [* In Windows]&]
|
||||
[s0;2 &]
|
||||
[s0; [2 Windows users are fortunate. They have three possibilities:
|
||||
safe (recommended!!), medium and hard ways.]&]
|
||||
[s0;2 &]
|
||||
[s0;2 &]
|
||||
[s0; [*2 Safe way]&]
|
||||
[s0;2 &]
|
||||
[s0;# [2 Download ][^https`:`/`/sourceforge`.net`/projects`/upp`/files`/GPL`-sources`/Ffmpeg`%20plugin`_LGPL`.7z`/download^2 f
|
||||
fmpeg][2 and ][^https`:`/`/sourceforge`.net`/projects`/upp`/files`/GPL`-sources`/SDL`%20plugin`_LGPL`.7z`/download^2 S
|
||||
DL][2 from U`+`+ Sourceforge following the links. They include
|
||||
.dll, .lib, .a, .h and source code for recent versions.]&]
|
||||
[s0;#2 &]
|
||||
[s0;# [2 Copy the downloaded folders in upp folder. You will get a
|
||||
folder structure like this:]&]
|
||||
[s0; [2 drive:`\upp`\uppsrc`\plugin`\ffmpeg]&]
|
||||
[s0; [2 drive:`\upp`\uppsrc`\plugin`\SDL]&]
|
||||
[s0;2 &]
|
||||
[s0; [2 In Setup/Build Methods menu include the next folders:]&]
|
||||
[s0;%- &]
|
||||
[ {{3371:3564:3065 [s0;= [2 PATH `- executable directories]]
|
||||
:: [s0;= [2 INCLUDE directories]]
|
||||
:: [s0;= [2 LIB directories]]
|
||||
:: [s0; [2 drive:`\upp]]
|
||||
:: [s0; [2 drive:`\upp`\uppsrc`\plugin`\SDL`\include]&]
|
||||
[s0; [2 drive:`\upp`\uppsrc`\plugin`\ffmpeg`\include]]
|
||||
:: [s0; [2 drive:`\upp`\uppsrc`\plugin`\SDL`\lib]&]
|
||||
[s0; [2 drive:`\upp`\uppsrc`\plugin`\ffmpeg`\lib]]}}&]
|
||||
[s0;2 &]
|
||||
[s0; [2 In addition, MSC9 and MSC10 require an additional include folder]&]
|
||||
[s0;2 &]
|
||||
[ {{3211:6789 [s0;= [2 Compiler]]
|
||||
:: [s0;= [2 INCLUDE directories]]
|
||||
:: [s0; [2 MSC9]]
|
||||
::|1 [s0; [2 drive:`\upp`\uppsrc`\plugin`\ffmpeg`\include`_msc]]
|
||||
:: [s0; [2 MSC10]]
|
||||
:: [s0;%- ]}}&]
|
||||
[s0;2 &]
|
||||
[s0;2 &]
|
||||
[s0; [*2 Medium]&]
|
||||
[s0;2 &]
|
||||
[s0; [2 All ffmpeg files in `"safe way`" have been got from the great
|
||||
daily updated ][^http`:`/`/ffmpeg`.arrozcru`.org`/autobuilds`/^2 `"Automated
|
||||
Ffmpeg Builds`" by Ramiro Polla][2 .]&]
|
||||
[s0;2 &]
|
||||
[s0; [2 To get the bleeding edge compiled files, download the files
|
||||
labeled `"shared`" and `"shared`-dev`".]&]
|
||||
[s0;2 &]
|
||||
[s0; [2 You can set them in your own folder structure or just follow
|
||||
the `"Safe way`" one. Do not forget to delete inttipes.h and
|
||||
stdint.h when compiling with MinGW.]&]
|
||||
[s0;2 &]
|
||||
[s0; [2 Remember that these files are supplied `"as is`" and they do
|
||||
not usually represent any `"stable`" version.]&]
|
||||
[s0;2 &]
|
||||
[s0;2 &]
|
||||
[s0; [*2 Hard way]&]
|
||||
[s0;2 &]
|
||||
[s0; [2 Ramiro Polla web also includes ][^http`:`/`/ffmpeg`.arrozcru`.org`/wiki`/index`.php`?title`=Links^2 i
|
||||
nstructions to build ffmpeg from sources][2 . Only for very experts.]&]
|
||||
[s0; ]
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
topic "General description";
|
||||
[ $$0,0#00000000000000000000000000000000:Default]
|
||||
[a83;*R6 $$1,0#31310162474203024125188417583966:caption]
|
||||
[{_}%EN-US
|
||||
[s1; [+184 Media]&]
|
||||
[s0; [2 Video and audio playing and processing for U`+`+.]&]
|
||||
[s0;2 &]
|
||||
[ {{10000 [s0;= [2 This package is preliminary so important changes are expected]]}}&]
|
||||
[s0;2 &]
|
||||
[s0; [2 It uses LGPL libraries ffmpeg and SDL (SDLCtrl). The instructions
|
||||
to install them are ][^topic`:`/`/Media`/srcdoc`/FfmpegInstall`$en`-us^2 here][2 .]&]
|
||||
[s0;2 &]
|
||||
[s0;i150;O0; [2 SDL gives audio playing and fast YUV video.]&]
|
||||
[s0;i150;O0; [2 ffmpeg gives audio and video decoding and encoding.]&]
|
||||
[s0;2 &]
|
||||
[s0;2 &]
|
||||
[s0; [^topic`:`/`/MediaPlayer`/srcdoc`/MediaPlayer`$en`-us^2 Media`_Demo
|
||||
package][2 is a demo of Media classes capabilities.]&]
|
||||
[s0;2 &]
|
||||
[s0; [2 In summary for playing:]&]
|
||||
[s0;2 &]
|
||||
[s0;i150;O0; [2 ffmpeg opens the file (.avi, .mp3, ...)]&]
|
||||
[s0;i150;O0; [2 ffmpeg reads the codified data and converts it in uncompressed
|
||||
images and audio chunks.]&]
|
||||
[s0;i150;O0; [2 SDL displays the images and plays the audio fluently.]&]
|
||||
[s0;2 &]
|
||||
[s0;2 &]
|
||||
[s0; [2 It uses at least 5 threads... plus the main:]&]
|
||||
[s0;2 &]
|
||||
[s0;i150;O0; [2 basic data chunks (called packets) retrieval]&]
|
||||
[s0;i150;O0; [2 audio decoding]&]
|
||||
[s0;i150;O0; [2 video decoding]&]
|
||||
[s0;i150;O0; [2 subtitles decoding]&]
|
||||
[s0;i150;O0; [2 audio playing]&]
|
||||
[s0;2 &]
|
||||
[s0;2 &]
|
||||
[s0; [2 The next immediate steps from now are:]&]
|
||||
[s0;2 &]
|
||||
[s0;i150;O0; [2 Solve problems]&]
|
||||
[s0;i150;O0; [2 Add RGB video playing to do video processing: ][*2 Done]&]
|
||||
[s0;i150;O0; [2 Reduce number of threads... specially video decoding
|
||||
thread has to be removed (it has been the source of many problems)]&]
|
||||
[s0;2 &]
|
||||
[s0;2 &]
|
||||
[s0; [2 Other improvements are:]&]
|
||||
[s0;2 &]
|
||||
[s0;i150;O0; [2 Add video and audio encoding (to generate new files,
|
||||
.avi. mp3, ...)]&]
|
||||
[s0;i150;O0; [2 Remove SDL dependencies:]&]
|
||||
[s0;l160;i150;O0; [2 To do fast image rendering]&]
|
||||
[s0;l160;i150;O0; [2 Playing audio with PortAudio]&]
|
||||
[s0; ]
|
||||
|
|
@ -1,280 +0,0 @@
|
|||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#include "MediaPlayer.h"
|
||||
#include "utility.h"
|
||||
#include "mediaplayer_in.h"
|
||||
|
||||
thread__ MediaFile *globalMediaFile;
|
||||
|
||||
int decoderInterrupt_cb() {
|
||||
return (globalMediaFile && globalMediaFile->requestAbort);
|
||||
}
|
||||
|
||||
// MediaFile streams retrieval and storage in packets
|
||||
void MediaFile::DecoderThread()//void *data)
|
||||
{
|
||||
//MediaFile &mf = *this;// *(MediaFile*)data;
|
||||
requestAbort = false;
|
||||
decodeThEnd = decodeThEnded = false;
|
||||
globalMediaFile = this;
|
||||
url_set_interrupt_cb(decoderInterrupt_cb);
|
||||
|
||||
int ret;
|
||||
for(;;) {
|
||||
if (requestAbort) // Abort request
|
||||
break;
|
||||
if (paused != last_paused) { // Pausing
|
||||
last_paused = paused;
|
||||
if (paused)
|
||||
av_read_pause(fileData);// Pauses a network based stream
|
||||
else
|
||||
av_read_play(fileData);
|
||||
}
|
||||
if (seek_req) { // Somebody asked a seek
|
||||
decodeThEnd = false;
|
||||
int64_t seek_target= seek_pos;
|
||||
int64_t seek_min = seek_rel > 0 ? seek_target - seek_rel + 2: INT64_MIN;
|
||||
int64_t seek_max = seek_rel < 0 ? seek_target - seek_rel - 2: INT64_MAX;
|
||||
|
||||
if (0 > avformat_seek_file(fileData, -1, seek_min, seek_target, seek_max, seek_flags))
|
||||
SetError(Format("%s: error while seeking", GetFileName()));
|
||||
else {
|
||||
if (idAudio >= 0) {
|
||||
audioq.Flush();
|
||||
audioq.Put(&flush_pkt, &flush_pkt);
|
||||
}
|
||||
if (idSubtitle >= 0) {
|
||||
subtitleq.Flush();
|
||||
subtitleq.Put(&flush_pkt, &flush_pkt);
|
||||
}
|
||||
if (idVideo >= 0) {
|
||||
videoq.Flush();
|
||||
videoq.Put(&flush_pkt, &flush_pkt);
|
||||
}
|
||||
}
|
||||
seek_req = false;
|
||||
}
|
||||
|
||||
// If any of the queues is full, it waits
|
||||
if (audioq.IsFull() || videoq.IsFull() || subtitleq.IsFull()) {
|
||||
Sleep(10);
|
||||
continue;
|
||||
}
|
||||
AVPacket pkt;
|
||||
if(url_feof(fileData->pb)) {
|
||||
/*av_init_packet(&pkt);
|
||||
pkt.data = NULL;
|
||||
pkt.size = 0;
|
||||
pkt.stream_index = idVideo;
|
||||
videoq.Put(&pkt, &flush_pkt);
|
||||
continue;*/
|
||||
break;
|
||||
}
|
||||
ret = av_read_frame(fileData, &pkt);
|
||||
if (ret < 0) {
|
||||
if (ret != AVERROR_EOF && url_ferror(fileData->pb) == 0) {
|
||||
Sleep(100); // Wait for user event
|
||||
continue;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (pkt.stream_index == idAudio)
|
||||
audioq.Put(&pkt, &flush_pkt);
|
||||
else if (pkt.stream_index == idVideo)
|
||||
videoq.Put(&pkt, &flush_pkt);
|
||||
else if (pkt.stream_index == idSubtitle)
|
||||
subtitleq.Put(&pkt, &flush_pkt);
|
||||
else
|
||||
av_free_packet(&pkt);
|
||||
}
|
||||
decodeThEnd = true; // Ask PaquetQeue to stop, so all threads end
|
||||
|
||||
while (!requestAbort && !(audioThEnd && videoThEnd && subtitleThEnd))// Wait until end
|
||||
Sleep(100);
|
||||
|
||||
// Close each stream
|
||||
if (idAudio >= 0)
|
||||
StreamClose(idAudio);
|
||||
if (idVideo >= 0)
|
||||
StreamClose(idVideo);
|
||||
if (idSubtitle >= 0)
|
||||
StreamClose(idSubtitle);
|
||||
|
||||
url_set_interrupt_cb(NULL);
|
||||
|
||||
decodeThEnded = true;
|
||||
|
||||
//return 0;
|
||||
}
|
||||
|
||||
void MediaFile::VideoThread() //void *data)
|
||||
{
|
||||
//MediaFile &mf = *this; // *(MediaFile *)data;
|
||||
AVFrame *frame= avcodec_alloc_frame();
|
||||
videoThEnd = false;
|
||||
|
||||
for(;;) {
|
||||
while (paused && !videoq.IsAbort())
|
||||
Sleep(10);
|
||||
|
||||
AVPacket pkt;
|
||||
if (videoq.Get(&pkt, decodeThEnd) <= 0) // Gets a video packet
|
||||
break;
|
||||
|
||||
if(pkt.data == flush_pkt.data)
|
||||
avcodec_flush_buffers(videoStream->codec);
|
||||
else {
|
||||
videoStream->codec->reordered_opaque = pkt.pts;
|
||||
int got_picture;
|
||||
// It does not check for errors
|
||||
#if (((LIBAVCODEC_VERSION_MAJOR <= 52) && (LIBAVCODEC_VERSION_MINOR <= 20)) || UBUNTU_TRICK)
|
||||
int len1 = avcodec_decode_video(videoStream->codec, frame, &got_picture, pkt.data, pkt.size);
|
||||
#else
|
||||
int len1 = avcodec_decode_video2(videoStream->codec, frame, &got_picture, &pkt);
|
||||
#endif
|
||||
|
||||
double pts;
|
||||
if((decoder_reorder_pts || pkt.dts == AV_NOPTS_VALUE) &&
|
||||
(frame->reordered_opaque != AV_NOPTS_VALUE))
|
||||
pts = double(frame->reordered_opaque);
|
||||
else if(pkt.dts != AV_NOPTS_VALUE)
|
||||
pts = double(pkt.dts);
|
||||
else
|
||||
pts = 0;
|
||||
pts *= av_q2d(videoStream->time_base);
|
||||
|
||||
if (got_picture) { // Compute video clock
|
||||
double frame_delay;
|
||||
|
||||
if (pts != 0)
|
||||
video_clock = pts; // Update video clock with pts, if present
|
||||
|
||||
// Update video clock for next frame
|
||||
frame_delay = av_q2d(videoStream->codec->time_base);
|
||||
|
||||
// For MPEG2, the frame can be repeated, so we update the clock accordingly
|
||||
frame_delay += frame->repeat_pict * (frame_delay * 0.5);
|
||||
video_clock += frame_delay;
|
||||
|
||||
if (!queue_picture(frame, pts))
|
||||
break;
|
||||
}
|
||||
av_free_packet(&pkt);
|
||||
if (step)
|
||||
stream_pause();
|
||||
}
|
||||
}
|
||||
av_free(frame);
|
||||
videoThEnd = true;
|
||||
//return 0;
|
||||
}
|
||||
|
||||
void MediaFile::SubtitleThread() //void *data)
|
||||
{
|
||||
//MediaFile &mf = *this; // *(MediaFile *)data;
|
||||
subtitleThEnd = false;
|
||||
|
||||
for(;;) {
|
||||
while (paused && !subtitleq.IsAbort())
|
||||
Sleep(10);
|
||||
|
||||
AVPacket pkt;
|
||||
if (subtitleq.Get(&pkt, 1) < 0)
|
||||
break;
|
||||
|
||||
if(pkt.data == flush_pkt.data){
|
||||
avcodec_flush_buffers(subtitleStream->codec);
|
||||
continue;
|
||||
}
|
||||
INTERLOCKED_(subpq_mutex) {
|
||||
while (subpq_size >= SUBPICTURE_QUEUE_SIZE && !subtitleq.IsAbort())
|
||||
subpq_cond.Wait(subpq_mutex);
|
||||
}
|
||||
|
||||
if (subtitleq.IsAbort())
|
||||
return ;//0;
|
||||
|
||||
SubPicture *sp = &subpq[subpq_windex];
|
||||
|
||||
double pts = 0;
|
||||
if (pkt.pts != AV_NOPTS_VALUE)
|
||||
pts = av_q2d(subtitleStream->time_base)*pkt.pts;
|
||||
|
||||
int got_subtitle;
|
||||
// It does not check for errors
|
||||
#if (((LIBAVCODEC_VERSION_MAJOR <= 52) && (LIBAVCODEC_VERSION_MINOR <= 20)) || UBUNTU_TRICK)
|
||||
int len1 = avcodec_decode_subtitle(subtitleStream->codec, &sp->sub, &got_subtitle,
|
||||
pkt.data, pkt.size);
|
||||
#else
|
||||
int len1 = avcodec_decode_subtitle2(subtitleStream->codec, &sp->sub, &got_subtitle,
|
||||
&pkt);
|
||||
#endif
|
||||
if (got_subtitle && sp->sub.format == 0) {
|
||||
sp->pts = pts;
|
||||
|
||||
for (unsigned i = 0; i < sp->sub.num_rects; i++) {
|
||||
for (int j = 0; j < sp->sub.rects[i]->nb_colors; j++) {
|
||||
int r, g, b, y, u, v, a;
|
||||
RGBA_IN(r, g, b, a, (uint32_t*)sp->sub.rects[i]->pict.data[1] + j);
|
||||
y = RGB_TO_Y_CCIR(r, g, b);
|
||||
u = RGB_TO_U_CCIR(r, g, b, 0);
|
||||
v = RGB_TO_V_CCIR(r, g, b, 0);
|
||||
YUVA_OUT((uint32_t*)sp->sub.rects[i]->pict.data[1] + j, y, u, v, a);
|
||||
}
|
||||
}
|
||||
if (++subpq_windex == SUBPICTURE_QUEUE_SIZE) // New picture is added
|
||||
subpq_windex = 0;
|
||||
INTERLOCKED_(subpq_mutex) {
|
||||
subpq_size++;
|
||||
}
|
||||
}
|
||||
av_free_packet(&pkt);
|
||||
}
|
||||
subtitleThEnd = true;
|
||||
//return 0;
|
||||
}
|
||||
|
||||
// Prepare a new audio buffer
|
||||
void sdl_audio_callback(void *data, Uint8 *stream, int len)
|
||||
{
|
||||
MediaFile &mf = *(MediaFile *)data;
|
||||
|
||||
mf.audio_callback_time = GetUSec();
|
||||
|
||||
while (len > 0) {
|
||||
if (unsigned(mf.audio_buf_index) >= mf.audio_buf_size) {
|
||||
double pts;
|
||||
int audio_size = mf.audio_decode_frame(&pts);
|
||||
if (audio_size < 0) { // If error, it outputs silence
|
||||
mf.audio_buf = mf.audio_buf1;
|
||||
mf.audio_buf_size = 1024;
|
||||
memset(mf.audio_buf, 0, mf.audio_buf_size);
|
||||
} else if (audio_size == 0) // Audio is ended
|
||||
mf.audioThEnd = true;
|
||||
else {
|
||||
if (mf.showAudio)
|
||||
mf.update_sample_display((int16_t *)mf.audio_buf, audio_size);
|
||||
audio_size = mf.synchronize_audio((int16_t *)mf.audio_buf, audio_size, pts);
|
||||
mf.audio_buf_size = audio_size;
|
||||
}
|
||||
mf.audio_buf_index = 0;
|
||||
}
|
||||
int len1 = min(len, mf.GetAudioOutputBufferSize());
|
||||
//memcpy(stream, (uint8_t *)mf.audio_buf + mf.audio_buf_index, len1);
|
||||
int16 *audioStr = (int16 *)(mf.audio_buf + mf.audio_buf_index);
|
||||
int16 *destStream = (int16 *)stream;
|
||||
for (int i = 0; i < len1/2; ++i) {
|
||||
double val = audioStr[i]*mf.audioFactor/1000.; // Meter tambien un "WhenAudioFrame"
|
||||
if (val < -32767+2) // To avoid audio saturation. A bit less than the limit
|
||||
val = -32767+2;
|
||||
else if (val > 32768-2)
|
||||
val = 32768-2;
|
||||
destStream[i] = int16(val);
|
||||
}
|
||||
len -= len1;
|
||||
stream += len1;
|
||||
mf.audio_buf_index += len1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#include <Media/ffmpeg_base.h>
|
||||
#include "utility.h"
|
||||
|
||||
|
||||
int av_strerror(int errnum, char *errbuf, size_t errbuf_size)
|
||||
{
|
||||
int ret = 0;
|
||||
const char *errstr = NULL;
|
||||
|
||||
switch (errnum) {
|
||||
case AVERROR_EOF: errstr = "End of file"; break;
|
||||
case AVERROR_INVALIDDATA: errstr = "Invalid data found when processing input"; break;
|
||||
case AVERROR_NUMEXPECTED: errstr = "Number syntax expected in filename"; break;
|
||||
case AVERROR_PATCHWELCOME: errstr = "Not yet implemented in FFmpeg, patches welcome"; break;
|
||||
case AVERROR_DEMUXER_NOT_FOUND: errstr = "Demuxer not found"; break;
|
||||
case AVERROR_MUXER_NOT_FOUND: errstr = "Muxer not found"; break;
|
||||
case AVERROR_DECODER_NOT_FOUND: errstr = "Decoder not found"; break;
|
||||
case AVERROR_ENCODER_NOT_FOUND: errstr = "Encoder not found"; break;
|
||||
case AVERROR_PROTOCOL_NOT_FOUND:errstr = "Protocol not found"; break;
|
||||
case AVERROR_FILTER_NOT_FOUND: errstr = "Filter not found"; break;
|
||||
case AVERROR_BSF_NOT_FOUND: errstr = "Bitstream filter not found"; break;
|
||||
case AVERROR_STREAM_NOT_FOUND: errstr = "Stream not found"; break;
|
||||
}
|
||||
|
||||
if (errstr) {
|
||||
av_strlcpy(errbuf, errstr, errbuf_size);
|
||||
} else {
|
||||
#if HAVE_STRERROR_R
|
||||
ret = strerror_r(AVUNERROR(errnum), errbuf, errbuf_size);
|
||||
#else
|
||||
ret = -1;
|
||||
#endif
|
||||
if (ret < 0)
|
||||
snprintf(errbuf, errbuf_size, "Error number %d occurred", errnum);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void av_free_packet(AVPacket *pkt)
|
||||
{
|
||||
if (pkt) {
|
||||
if (pkt->destruct) pkt->destruct(pkt);
|
||||
pkt->data = NULL; pkt->size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: suppress the packet queue
|
||||
static void flush_packet_queue(AVFormatContext *s)
|
||||
{
|
||||
AVPacketList *pktl;
|
||||
|
||||
for(;;) {
|
||||
pktl = s->packet_buffer;
|
||||
if (!pktl)
|
||||
break;
|
||||
s->packet_buffer = pktl->next;
|
||||
av_free_packet(&pktl->pkt);
|
||||
av_free(pktl);
|
||||
}
|
||||
while(s->raw_packet_buffer){
|
||||
pktl = s->raw_packet_buffer;
|
||||
s->raw_packet_buffer = pktl->next;
|
||||
av_free_packet(&pktl->pkt);
|
||||
av_free(pktl);
|
||||
}
|
||||
s->packet_buffer_end=
|
||||
s->raw_packet_buffer_end= NULL;
|
||||
s->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
// Flush the frame reader.
|
||||
void ff_read_frame_flush(AVFormatContext *s)
|
||||
{
|
||||
AVStream *st;
|
||||
int j;
|
||||
|
||||
flush_packet_queue(s);
|
||||
|
||||
s->cur_st = NULL;
|
||||
|
||||
// for each stream, reset read state
|
||||
for(unsigned i = 0; i < s->nb_streams; i++) {
|
||||
st = s->streams[i];
|
||||
|
||||
if (st->parser) {
|
||||
av_parser_close(st->parser);
|
||||
st->parser = NULL;
|
||||
av_free_packet(&st->cur_pkt);
|
||||
}
|
||||
st->last_IP_pts = AV_NOPTS_VALUE;
|
||||
st->cur_dts = AV_NOPTS_VALUE; // we set the current DTS to an unspecified origin
|
||||
st->reference_dts = AV_NOPTS_VALUE;
|
||||
// fail safe
|
||||
st->cur_ptr = NULL;
|
||||
st->cur_len = 0;
|
||||
|
||||
st->probe_packets = MAX_PROBE_PACKETS;
|
||||
|
||||
for(j=0; j<MAX_REORDER_DELAY+1; j++)
|
||||
st->pts_buffer[j]= AV_NOPTS_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
|
||||
{
|
||||
if(min_ts > ts || max_ts < ts)
|
||||
return -1;
|
||||
|
||||
ff_read_frame_flush(s);
|
||||
|
||||
if (s->iformat->read_seek2)
|
||||
return s->iformat->read_seek2(s, stream_index, min_ts, ts, max_ts, flags);
|
||||
|
||||
if(s->iformat->read_timestamp){
|
||||
//try to seek via read_timestamp()
|
||||
}
|
||||
|
||||
//Fallback to old API if new is not implemented but old is
|
||||
//Note the old has somewat different sematics
|
||||
if(s->iformat->read_seek || 1)
|
||||
return av_seek_frame(s, stream_index, ts, flags | (ts - min_ts > max_ts - ts ? AVSEEK_FLAG_BACKWARD : 0));
|
||||
|
||||
// try some generic seek like av_seek_frame_generic() but with new ts semantics
|
||||
}
|
||||
|
||||
void avsubtitle_free(AVSubtitle *sub)
|
||||
{
|
||||
for (unsigned i = 0; i < sub->num_rects; i++)
|
||||
{
|
||||
av_freep(&sub->rects[i]->pict.data[0]);
|
||||
av_freep(&sub->rects[i]->pict.data[1]);
|
||||
av_freep(&sub->rects[i]->pict.data[2]);
|
||||
av_freep(&sub->rects[i]->pict.data[3]);
|
||||
av_freep(&sub->rects[i]->text);
|
||||
av_freep(&sub->rects[i]->ass);
|
||||
av_freep(&sub->rects[i]);
|
||||
}
|
||||
|
||||
av_freep(&sub->rects);
|
||||
|
||||
memset(sub, 0, sizeof(AVSubtitle));
|
||||
}
|
||||
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#include <Media/ffmpeg_base.h>
|
||||
//#include <Functions4U/Functions4U.h>
|
||||
#include "utility.h"
|
||||
|
||||
|
||||
#ifdef PLATFORM_POSIX
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
int64 GetUSec() {
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
memset(&tz, 0, sizeof(tz));
|
||||
gettimeofday(&tv, &tz);
|
||||
return int64(tv.tv_sec)*1000000 + tv.tv_usec;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int64 GetUSec() {
|
||||
LARGE_INTEGER ticksPerSec;
|
||||
LARGE_INTEGER tick;
|
||||
|
||||
QueryPerformanceFrequency(&ticksPerSec);
|
||||
QueryPerformanceCounter(&tick);
|
||||
return tick.QuadPart/(ticksPerSec.QuadPart/1000000);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
#ifndef _Media_utility_h_
|
||||
#define _Media_utility_h_
|
||||
|
||||
#include "audioSystem.h"
|
||||
|
||||
String GetTags(AVFormatContext *fileData);
|
||||
String GetAvError(int err);
|
||||
SwsContext *SWSGetContext(int width, int height, PixelFormat pix_fmt,
|
||||
int d_width, int d_height, PixelFormat d_pix_fmt);
|
||||
void AvLogCallback(void* ptr, int level, const char* fmt, va_list vl);
|
||||
|
||||
const char *GetStreamAudioBitFormat(AVStream *stream);
|
||||
String GetStreamTags(AVStream *stream);
|
||||
String GetStreamLanguage(AVStream *stream);
|
||||
|
||||
int GetCodecBitRate(AVCodecContext *codec);
|
||||
String GetCodecName(AVCodecContext *codec, bool encode);
|
||||
|
||||
inline int compute_mod(int a, int b)
|
||||
{
|
||||
a = a % b;
|
||||
if (a >= 0)
|
||||
return a;
|
||||
else
|
||||
return a + b;
|
||||
}
|
||||
|
||||
int64 GetUSec();
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#include <Media/ffmpeg_base.h>
|
||||
#include "utility.h"
|
||||
|
||||
|
||||
int GetCodecBitRate(AVCodecContext *codec) {
|
||||
int bit_rate, bits_per_sample;
|
||||
|
||||
switch(codec->codec_type) {
|
||||
case CODEC_TYPE_VIDEO:
|
||||
case CODEC_TYPE_DATA:
|
||||
case CODEC_TYPE_SUBTITLE:
|
||||
case CODEC_TYPE_ATTACHMENT:
|
||||
bit_rate = max(codec->bit_rate, av_get_bits_per_sample(codec->codec_id));
|
||||
break;
|
||||
case CODEC_TYPE_AUDIO:
|
||||
bits_per_sample = av_get_bits_per_sample(codec->codec_id);
|
||||
bit_rate = bits_per_sample ? codec->sample_rate * codec->channels * bits_per_sample :
|
||||
codec->bit_rate;
|
||||
break;
|
||||
default:
|
||||
bit_rate = 0;
|
||||
break;
|
||||
}
|
||||
return bit_rate;
|
||||
}
|
||||
|
||||
size_t av_get_codec_tag_string(char *buf, size_t buf_size, unsigned int codec_tag)
|
||||
{
|
||||
size_t len, ret = 0;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
len = snprintf(buf, buf_size,
|
||||
isprint(codec_tag&0xFF) ? "%c" : "[%d]", codec_tag&0xFF);
|
||||
buf += len;
|
||||
buf_size = buf_size > len ? buf_size - len : 0;
|
||||
ret += len;
|
||||
codec_tag>>=8;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
String GetCodecName(AVCodecContext *codec, bool encode) {
|
||||
String ret;
|
||||
AVCodec *p;
|
||||
|
||||
if (encode)
|
||||
p = avcodec_find_encoder(codec->codec_id);
|
||||
else
|
||||
p = avcodec_find_decoder(codec->codec_id);
|
||||
|
||||
if (p)
|
||||
ret = String(p->long_name) + " (" + p->name + ")";
|
||||
else if (codec->codec_id == CODEC_ID_MPEG2TS)
|
||||
ret = "mpeg2ts"; // fake mpeg2 transport stream codec (currently not registered)
|
||||
else if (codec->codec_name[0] != '\0')
|
||||
ret = String(codec->codec->long_name) + " (" + codec->codec_name + ")";
|
||||
else { // output avi tags
|
||||
char tag_buf[32];
|
||||
av_get_codec_tag_string(tag_buf, sizeof(tag_buf), codec->codec_tag);
|
||||
ret = Format("%s / 0x%04X", tag_buf, int(codec->codec_tag));
|
||||
}
|
||||
if (codec->codec_type == CODEC_TYPE_VIDEO) {
|
||||
if (codec->mb_decision)
|
||||
ret << " (hq)";
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#include <Media/ffmpeg_base.h>
|
||||
#include "utility.h"
|
||||
|
||||
|
||||
// Return a String with all file tags
|
||||
String GetTags(AVFormatContext *fileData) {
|
||||
char tagStrings[1024];
|
||||
tagStrings[0] = 0;
|
||||
AVMetadataTag *tag = NULL;
|
||||
|
||||
//av_metadata_conv(fileData, NULL, fileData->iformat->metadata_conv);
|
||||
while ((tag = av_metadata_get(fileData->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX))) {
|
||||
if (tag->key[0] != 0 && tag->value[0] != 0) {
|
||||
int ln = strlen(tagStrings);
|
||||
snprintf(tagStrings + ln, 1024-ln, "%s%s: %s",
|
||||
tagStrings[0] != 0 ? "\n" : "", tag->key, tag->value);
|
||||
}
|
||||
}
|
||||
return tagStrings;
|
||||
}
|
||||
|
||||
String GetAvError(int err) {
|
||||
char errbuf[128];
|
||||
const char *errbuf_ptr = errbuf;
|
||||
|
||||
if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)
|
||||
errbuf_ptr = strerror(AVUNERROR(err));
|
||||
return errbuf_ptr;
|
||||
}
|
||||
|
||||
int handle_jpeg(enum PixelFormat *format)
|
||||
{
|
||||
switch (*format) {
|
||||
case PIX_FMT_YUVJ420P: *format = PIX_FMT_YUV420P; return 1;
|
||||
case PIX_FMT_YUVJ422P: *format = PIX_FMT_YUV422P; return 1;
|
||||
case PIX_FMT_YUVJ444P: *format = PIX_FMT_YUV444P; return 1;
|
||||
case PIX_FMT_YUVJ440P: *format = PIX_FMT_YUV440P; return 1;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
SwsContext *SWSGetContext(int width, int height, PixelFormat pix_fmt,
|
||||
int d_width, int d_height, PixelFormat d_pix_fmt) {
|
||||
//#if (LIBSWSCALE_VERSION_MAJOR <= 0 && LIBSWSCALE_VERSION_MINOR < 12)
|
||||
return sws_getContext(width, height, pix_fmt, d_width, d_height, d_pix_fmt,
|
||||
SWS_BILINEAR/*SWS_BICUBIC*/, NULL, NULL, NULL);
|
||||
/*#else
|
||||
SwsContext *context = sws_alloc_context();
|
||||
if (context) {
|
||||
av_set_int(context, "srcw", width);
|
||||
av_set_int(context, "srch", height);
|
||||
av_set_int(context, "src_format", pix_fmt);
|
||||
av_set_int(context, "src_range", handle_jpeg(&pix_fmt));
|
||||
av_set_int(context, "dstw", width);
|
||||
av_set_int(context, "dsth", height);
|
||||
av_set_int(context, "dst_format", dst_pix_fmt);
|
||||
av_set_int(context, "dst_range", handle_jpeg((PixelFormat*)&dst_pix_fmt));
|
||||
av_set_int(context, "sws_flags", SWS_BICUBIC);
|
||||
|
||||
if (sws_init_context(context, NULL, NULL) < 0) {
|
||||
//SetError("Cannot initialize resampling context");
|
||||
sws_freeContext(context);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return context;
|
||||
#endif */
|
||||
}
|
||||
|
||||
void AvLogCallback(void* ptr, int level, const char* fmt, va_list vl)
|
||||
{
|
||||
if (level > AV_LOG_ERROR)
|
||||
return;
|
||||
char str[1024];
|
||||
snprintf(str, 4, "%3d ", level);
|
||||
vsnprintf(str+4, 1024-4, fmt, vl);
|
||||
int kk = 1;
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#include <Media/ffmpeg_base.h>
|
||||
#include "utility.h"
|
||||
|
||||
|
||||
// Returns a string with the bit format of an audio stream
|
||||
const char *GetStreamAudioBitFormat(AVStream *st) {
|
||||
switch(st->codec->sample_fmt) {
|
||||
case SAMPLE_FMT_U8: return "Unsigned 8";
|
||||
case SAMPLE_FMT_S16: return "Signed 16";
|
||||
case SAMPLE_FMT_S32: return "Signed 32";
|
||||
case SAMPLE_FMT_FLT: return "Float";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
String GetStreamLanguage(AVStream *stream) {
|
||||
AVMetadataTag *lang = av_metadata_get(stream->metadata, "language", NULL, 0);
|
||||
if (lang)
|
||||
return lang->value;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
// Return a String with all stream tags but language
|
||||
String GetStreamTags(AVStream *stream) {
|
||||
char tagStrings[1024];
|
||||
tagStrings[0] = 0;
|
||||
AVMetadataTag *tag = NULL;
|
||||
|
||||
while ((tag = av_metadata_get(stream->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX))) {
|
||||
if (tag->key[0] != 0 && strcmp(tag->key, "language") != 0 && tag->value[0] != 0) {
|
||||
int ln = strlen(tagStrings);
|
||||
snprintf(tagStrings + ln, 1024-ln, "%s%s: %s",
|
||||
tagStrings[0] != 0 ? "\n" : "", tag->key, tag->value);
|
||||
}
|
||||
}
|
||||
return tagStrings;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
description "Media package examples\377";
|
||||
|
||||
uses
|
||||
CtrlLib,
|
||||
Controls4U,
|
||||
Media;
|
||||
|
||||
file
|
||||
main.cpp,
|
||||
demo.lay,
|
||||
demoMediaPlayer.cpp,
|
||||
demoMediaPlayer.lay,
|
||||
demoVolumeCtrl.cpp,
|
||||
demoVolumeCtrl.lay,
|
||||
srcdoc.tpp;
|
||||
|
||||
mainconfig
|
||||
"" = "GUI MT";
|
||||
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
LAYOUT(Main, 400, 164)
|
||||
ITEM(ArrayCtrl, grid, HSizePosZ(4, 4).VSizePosZ(32, 4))
|
||||
ITEM(Label, dv___1, SetLabel(t_("Choose a Media demo")).LeftPosZ(8, 128).TopPosZ(8, 19))
|
||||
ITEM(Button, butRun, SetLabel(t_("Run")).RightPosZ(4, 76).TopPosZ(4, 24))
|
||||
END_LAYOUT
|
||||
|
||||
|
|
@ -1,393 +0,0 @@
|
|||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#include <Media/MediaPlayer.h>
|
||||
#include <Controls4U/Controls4U.h>
|
||||
#include <Media/VolumeCtrl.h>
|
||||
|
||||
#define LAYOUTFILE <Media_demo/demoMediaPlayer.lay>
|
||||
#include <CtrlCore/lay.h>
|
||||
|
||||
struct MediaPlayerDemo : public WithMainMediaPlayer<TopWindow> {
|
||||
typedef MediaPlayerDemo CLASSNAME;
|
||||
void Play() {
|
||||
butPlay.Disable();
|
||||
butPause.Enable();
|
||||
butStop.Enable();
|
||||
butFormat.Disable();
|
||||
file.Disable();
|
||||
seconds.Hide();
|
||||
secondsLabel.SetText("0");
|
||||
sliderPosition.SetData(0);
|
||||
|
||||
if (!player.Play())
|
||||
Exclamation(player.GetError());
|
||||
|
||||
seconds.SetText("0");
|
||||
sliderPosition.SetData(0);
|
||||
butPlay.Enable();
|
||||
butPause.Disable();
|
||||
butStop.Disable();
|
||||
butFormat.Enable();
|
||||
file.Enable();
|
||||
seconds.Show();
|
||||
}
|
||||
void Stop() {
|
||||
player.Stop();
|
||||
seconds.SetText("0");
|
||||
sliderPosition.SetData(0);
|
||||
}
|
||||
void Pause() {
|
||||
player.Pause();
|
||||
}
|
||||
void Load() {
|
||||
if (!player.Load(~file)) {
|
||||
Exclamation(player.GetError());
|
||||
return;
|
||||
}
|
||||
Layout();
|
||||
int duration = int(player.GetDuration());
|
||||
if (duration <= 0)
|
||||
duration = 1;
|
||||
sliderPosition.MinMax(0, duration);
|
||||
if (duration < 20) {
|
||||
sliderPosition.SetMajorTicks(5);
|
||||
sliderPosition.SetMinorTicks(1);
|
||||
} else if (duration < 60) {
|
||||
sliderPosition.SetMajorTicks(10);
|
||||
sliderPosition.SetMinorTicks(5);
|
||||
} else if (duration < 60*10) {
|
||||
sliderPosition.SetMajorTicks(60);
|
||||
sliderPosition.SetMinorTicks(10);
|
||||
} else if (duration < 60*60) {
|
||||
sliderPosition.SetMajorTicks(10*60);
|
||||
sliderPosition.SetMinorTicks(5*60);
|
||||
} else {
|
||||
sliderPosition.SetMajorTicks(15*60);
|
||||
sliderPosition.SetMinorTicks(5*60);
|
||||
}
|
||||
sliderPosition.SetData(0);
|
||||
sliderPosition.Enable();
|
||||
butFormat.Enable();
|
||||
butPlay.Enable();
|
||||
butStop.Enable();
|
||||
butPause.Enable();
|
||||
}
|
||||
virtual void Close() {
|
||||
player.Stop();
|
||||
TopWindow::Close();
|
||||
}
|
||||
void BWEffect(SDLSurface &surface) {
|
||||
static int x, y;
|
||||
static bool left, up;
|
||||
int width = int(surface.GetWidth()/3);
|
||||
int height = int(surface.GetHeight()/3);
|
||||
int delta = 2;
|
||||
|
||||
if (!player.IsPaused()) {
|
||||
if (left)
|
||||
x -= delta;
|
||||
else
|
||||
x += delta;
|
||||
if (up)
|
||||
y -= delta;
|
||||
else
|
||||
y += delta;
|
||||
if (x < 0) {
|
||||
left = false;
|
||||
x = 1;
|
||||
} else if (x >= surface.GetWidth()-width) {
|
||||
left = true;
|
||||
x = surface.GetWidth()-width - 1;
|
||||
}
|
||||
if (y < 0) {
|
||||
up = false;
|
||||
y = 1;
|
||||
} else if (y >= surface.GetHeight()-height) {
|
||||
up = true;
|
||||
y = surface.GetHeight()-height - 1;
|
||||
}
|
||||
}
|
||||
for (int r = y; r < y+height; ++r) {
|
||||
for (int c = x; c < x+width; ++c) {
|
||||
byte bw = Grayscale(surface.GetPixel(c, r));
|
||||
surface.DrawPixel(c, r, Color(bw, bw, bw));
|
||||
}
|
||||
}
|
||||
surface.DrawRect(x, y, width, height, 1, Black());
|
||||
}
|
||||
void MotionDetect(SDLSurface &surface) {
|
||||
static Buffer <byte> img0;
|
||||
static Buffer <byte> img1;
|
||||
static bool which;
|
||||
static int prevLen;
|
||||
byte *prev, *actual;
|
||||
const int delta = 3;
|
||||
|
||||
int len = int(surface.GetWidth()*surface.GetHeight()/delta);
|
||||
if (len != prevLen) {
|
||||
img0.Alloc(len);
|
||||
img1.Alloc(len);
|
||||
}
|
||||
if (which) {
|
||||
prev = img0;
|
||||
actual = img1;
|
||||
which = false;
|
||||
} else {
|
||||
prev = img1;
|
||||
actual = img0;
|
||||
which = true;
|
||||
}
|
||||
|
||||
byte *preva, *actuala;
|
||||
actuala = actual;
|
||||
for (int r = 0; r < surface.GetHeight(); r+=delta) {
|
||||
for (int c = 0; c < surface.GetWidth(); c+=delta)
|
||||
*(actuala++) = Grayscale(surface.GetPixel(c, r));
|
||||
}
|
||||
if (len != prevLen) {
|
||||
prevLen = len;
|
||||
return;
|
||||
}
|
||||
actuala = actual;
|
||||
preva = prev;
|
||||
for (int r = 0; r < surface.GetHeight(); r+=delta) {
|
||||
for (int c = 0; c < surface.GetWidth(); c+=delta) {
|
||||
if (abs(*(actuala++) - *(preva++)) > 10)
|
||||
surface.FillRect(c, r, delta, delta, Blue());
|
||||
}
|
||||
}
|
||||
}
|
||||
void OnFrame(SDLSurface &surface) {
|
||||
surface.Lock();
|
||||
if (blackWhite)
|
||||
BWEffect(surface);
|
||||
if (showLogo)
|
||||
surface.DrawImage(imLogo, 0, 0, Black());
|
||||
if (motionDetect)
|
||||
MotionDetect(surface);
|
||||
surface.Unlock();
|
||||
}
|
||||
void OnSecond() {
|
||||
double sec = player.GetSecond();
|
||||
secondsLabel.SetText(SecondsToString(int(sec), false));
|
||||
sliderPosition.SetData(int(sec));
|
||||
}
|
||||
void OnPause() {
|
||||
if (player.IsPaused()) {
|
||||
seconds.Show();
|
||||
seconds = SecondsToString(player.GetSecond(), false);
|
||||
} else
|
||||
seconds.Hide();
|
||||
}
|
||||
void OnSliderPosition() {
|
||||
player.SetSecond(int(~sliderPosition));
|
||||
seconds = SecondsToString(player.GetSecond(), false);
|
||||
}
|
||||
void OnSliderVolume() {
|
||||
player.SetAudioFactor(int(~sliderVolume)/100.);
|
||||
}
|
||||
void OnEditSeconds() {
|
||||
player.SetSecond(StringToSeconds(seconds));
|
||||
}
|
||||
void OnRgb() {
|
||||
player.SetRGB(rgb);
|
||||
motionDetect.Enable(rgb);
|
||||
showLogo.Enable(rgb);
|
||||
blackWhite.Enable(rgb);
|
||||
}
|
||||
void CheckOption(int ii, ArrayCtrl *arr) {
|
||||
int num = 0;
|
||||
for(int i = 0; i < arr->GetCount(); i++) {
|
||||
if (arr->Get(i, 0))
|
||||
num++;
|
||||
}
|
||||
if (num > 1) {
|
||||
Exclamation("It is possible to play only one stream");
|
||||
arr->Set(ii, 0, false);
|
||||
}
|
||||
}
|
||||
/*void OnFullScreen() {
|
||||
static Rect last;
|
||||
Close();
|
||||
if (IsFullScreen()) {
|
||||
FullScreen(false);
|
||||
SetRect(last);
|
||||
} else {
|
||||
last = GetRect();
|
||||
FullScreen(true);
|
||||
}
|
||||
OpenMain();
|
||||
}*/
|
||||
void FormatDialog() {
|
||||
WithFormat<TopWindow> format;
|
||||
|
||||
CtrlLayoutOK(format, "File format");
|
||||
format.duration.SetText(SecondsToString(player.GetDuration(), false));
|
||||
format.fileName.SetText(player.GetFileName());
|
||||
|
||||
format.arrVideo.SetLineCy(Draw::GetStdFontCy()+4);
|
||||
format.arrVideo.AddColumn("Sel");
|
||||
format.arrVideo.AddColumn("Codec");
|
||||
format.arrVideo.AddColumn("Pixel Format");
|
||||
format.arrVideo.AddColumn("Lang");
|
||||
format.arrVideo.AddColumn("Width");
|
||||
format.arrVideo.AddColumn("Height");
|
||||
format.arrVideo.AddColumn("PAR width");
|
||||
format.arrVideo.AddColumn("PAR height");
|
||||
format.arrVideo.AddColumn("DAR width");
|
||||
format.arrVideo.AddColumn("DAR height");
|
||||
format.arrVideo.AddColumn("Frame rate fps");
|
||||
format.arrVideo.AddColumn("Tbr");
|
||||
format.arrVideo.AddColumn("Tbn");
|
||||
format.arrVideo.AddColumn("Tbc");
|
||||
format.arrVideo.AddColumn("Bitrate kbps");
|
||||
format.arrVideo.AddColumn("Tags");
|
||||
format.arrVideo.ColumnWidths("30 100 70 40 45 45 60 60 60 60 80 50 50 50 70 80");
|
||||
format.arrVideo.AutoHideSb().HeaderObject().Absolute();
|
||||
|
||||
Array<Option> optionVideo;
|
||||
for (int i = 0; i < player.videoData.GetCount(); ++i) {
|
||||
format.arrVideo.Add(false, player.videoData[i].codec, player.videoData[i].pixFmt,
|
||||
player.videoData[i].lang,
|
||||
player.videoData[i].size.cx, player.videoData[i].size.cy,
|
||||
player.videoData[i].par.cx, player.videoData[i].par.cy,
|
||||
player.videoData[i].dar.cx, player.videoData[i].dar.cy,
|
||||
FormatDouble(player.videoData[i].frameRate.cx/double(player.videoData[i].frameRate.cy), 2),
|
||||
FormatDouble(player.videoData[i].tbr.cx/double(player.videoData[i].tbr.cy), 2),
|
||||
FormatDouble(player.videoData[i].tbn.cy/double(player.videoData[i].tbn.cx), 2),
|
||||
FormatDouble(player.videoData[i].tbc.cy/double(player.videoData[i].tbc.cx), 2),
|
||||
int(player.videoData[i].bitrate/1000),
|
||||
player.videoData[i].tags);
|
||||
Option &option = optionVideo.Add();
|
||||
format.arrVideo.SetCtrl(i, 0, option);
|
||||
option <<= THISBACK2(CheckOption, i, &format.arrVideo);
|
||||
}
|
||||
if (player.GetVideo() >= 0)
|
||||
format.arrVideo.Set(player.GetVideoId(), 0, true);
|
||||
|
||||
format.arrAudio.SetLineCy(Draw::GetStdFontCy()+4);
|
||||
format.arrAudio.AddColumn("Sel");
|
||||
format.arrAudio.AddColumn("Codec");
|
||||
format.arrAudio.AddColumn("Lang");
|
||||
format.arrAudio.AddColumn("Channels");
|
||||
format.arrAudio.AddColumn("Sample rate Hz");
|
||||
format.arrAudio.AddColumn("Bitrate kbps");
|
||||
format.arrAudio.AddColumn("Bits");
|
||||
format.arrAudio.AddColumn("Tags");
|
||||
format.arrAudio.ColumnWidths("30 100 40 60 90 70 40 100");
|
||||
format.arrAudio.AutoHideSb().HeaderObject().Absolute();
|
||||
|
||||
format.tags.NoEofLine();
|
||||
format.tags.SetData(player.GetTags());
|
||||
|
||||
Array<Option> optionAudio;
|
||||
for (int i = 0; i < player.audioData.GetCount(); ++i) {
|
||||
format.arrAudio.Add(false, player.audioData[i].codec, player.audioData[i].lang,
|
||||
player.audioData[i].channels,
|
||||
int64(player.audioData[i].sampleRate),
|
||||
int(player.audioData[i].bitrate/1000),
|
||||
player.audioData[i].bits,
|
||||
player.audioData[i].tags);
|
||||
Option &option = optionAudio.Add();
|
||||
format.arrAudio.SetCtrl(i, 0, option);
|
||||
option <<= THISBACK2(CheckOption, i, &format.arrAudio);
|
||||
}
|
||||
if (player.GetAudio() >= 0)
|
||||
format.arrAudio.Set(player.GetAudioId(), 0, true);
|
||||
|
||||
format.Sizeable();
|
||||
format.Execute();
|
||||
|
||||
int idVideo = -1;
|
||||
for (int i = 0; i < format.arrVideo.GetCount(); ++i) {
|
||||
if (format.arrVideo.Get(i, 0))
|
||||
idVideo = i;
|
||||
}
|
||||
player.SetVideoId(idVideo);
|
||||
|
||||
int idAudio = -1;
|
||||
for (int i = 0; i < format.arrAudio.GetCount(); ++i) {
|
||||
if (format.arrAudio.Get(i, 0))
|
||||
idAudio = i;
|
||||
}
|
||||
player.SetAudioId(idAudio);
|
||||
}
|
||||
void LabelFormatting(String &str, int val) {
|
||||
str = SecondsToString(val, false);
|
||||
}
|
||||
MediaPlayerDemo() {
|
||||
CtrlLayout(*this, "MediaPlayer demo");
|
||||
Zoomable().Sizeable();
|
||||
|
||||
butPlay.Disable();
|
||||
butPlay.WhenAction = THISBACK(Play);
|
||||
|
||||
butStop.Disable();
|
||||
butStop.WhenAction = THISBACK(Stop);
|
||||
|
||||
butPause.Disable();
|
||||
butPause.WhenAction = THISBACK(Pause);
|
||||
|
||||
butFormat.Disable();
|
||||
butFormat.WhenAction = THISBACK(FormatDialog);
|
||||
|
||||
file.WhenChange = THISBACK(Load);
|
||||
|
||||
forceAspect = true;
|
||||
forceAspect.WhenAction = THISBACK(OnForceAspect);
|
||||
|
||||
fullScreen = false;
|
||||
fullScreen.Disable();
|
||||
//fullScreen.WhenAction = THISBACK(OnFullScreen);
|
||||
|
||||
player.ForceAspect(forceAspect);
|
||||
player.WhenFrame = THISBACK(OnFrame);
|
||||
player.WhenSecond = THISBACK(OnSecond);
|
||||
player.WhenPause = THISBACK(OnPause);
|
||||
player.ShowAudio(true);
|
||||
|
||||
sliderPosition.MinMax(0, 100).SetMinorTicksSize(30).Jump(true);
|
||||
sliderPosition.SetData(0);
|
||||
sliderPosition.WhenAction = THISBACK(OnSliderPosition);
|
||||
sliderPosition.LabelFormat = THISBACK(LabelFormatting);
|
||||
sliderPosition.Enable(false);
|
||||
|
||||
sliderVolume.MinMax(0, 400).Jump(true);
|
||||
sliderVolume.SetData(100);
|
||||
|
||||
sliderVolume.WhenAction = THISBACK(OnSliderVolume);
|
||||
|
||||
seconds.WhenEnter = THISBACK(OnEditSeconds);
|
||||
seconds.SetText("0");
|
||||
|
||||
secondsLabel.SetText("0");
|
||||
|
||||
rgb = false;
|
||||
rgb.WhenAction = THISBACK(OnRgb);
|
||||
|
||||
motionDetect = false;
|
||||
motionDetect.Disable();
|
||||
|
||||
showLogo = false;
|
||||
showLogo.Disable();
|
||||
|
||||
blackWhite = false;
|
||||
blackWhite.Disable();
|
||||
|
||||
ImageDraw iwLogo(500, 100);
|
||||
iwLogo.DrawEllipse(20, 20, 100, 40, Brown());
|
||||
iwLogo.DrawText(46, 26, "U++", Arial(25).Bold(), Black());
|
||||
imLogo = iwLogo;
|
||||
}
|
||||
void OnForceAspect() {
|
||||
player.ForceAspect(forceAspect);
|
||||
}
|
||||
Image imLogo;
|
||||
};
|
||||
|
||||
void Run_MediaPlayer() {
|
||||
MediaPlayerDemo().Run();
|
||||
}
|
||||
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
LAYOUT(MainMediaPlayer, 320, 320)
|
||||
ITEM(Label, secondsLabel, SetFrame(FieldFrame()).RightPosZ(148, 56).BottomPosZ(69, 19))
|
||||
ITEM(Button, butPause, SetLabel(t_("Pause")).RightPosZ(52, 40).BottomPosZ(68, 20))
|
||||
ITEM(Button, butFormat, SetLabel(t_("Format")).RightPosZ(8, 40).BottomPosZ(28, 20))
|
||||
ITEM(Button, butPlay, SetLabel(t_("Play")).RightPosZ(96, 48).BottomPosZ(68, 20))
|
||||
ITEM(EditFile, file, HSizePosZ(4, 208).BottomPosZ(69, 19))
|
||||
ITEM(Option, blackWhite, SetLabel(t_("Grayscale effect")).LeftPosZ(188, 100).BottomPosZ(9, 19))
|
||||
ITEM(Option, motionDetect, SetLabel(t_("Motion detect")).LeftPosZ(96, 88).BottomPosZ(9, 19))
|
||||
ITEM(Option, showLogo, SetLabel(t_("Show logo")).LeftPosZ(188, 72).BottomPosZ(29, 19))
|
||||
ITEM(Option, rgb, SetLabel(t_("RGB/YUV")).LeftPosZ(96, 68).BottomPosZ(29, 19))
|
||||
ITEM(Option, fullScreen, SetLabel(t_("Full screen")).LeftPosZ(4, 88).BottomPosZ(9, 19))
|
||||
ITEM(Option, forceAspect, SetLabel(t_("Force aspect")).LeftPosZ(4, 88).BottomPosZ(29, 19))
|
||||
ITEM(EditString, seconds, RightPosZ(148, 56).BottomPosZ(69, 19))
|
||||
ITEM(SliderCtrlX, sliderPosition, HSizePosZ(4, 8).BottomPosZ(84, 40))
|
||||
ITEM(Button, butStop, SetLabel(t_("Stop")).RightPosZ(8, 40).BottomPosZ(68, 20))
|
||||
ITEM(MediaPlayer, player, SetFrame(InsetFrame()).HSizePosZ(4, 4).VSizePosZ(4, 124))
|
||||
ITEM(SliderCtrl, sliderVolume, RightPosZ(8, 80).BottomPosZ(40, 24))
|
||||
ITEM(VolumeCtrl, mainVolume, RightPosZ(88, 76).BottomPosZ(40, 24))
|
||||
END_LAYOUT
|
||||
|
||||
LAYOUT(Format, 400, 392)
|
||||
ITEM(ArrayCtrl, arrAudio, HSizePosZ(4, 4).TopPosZ(200, 100))
|
||||
ITEM(Label, dv___1, SetLabel(t_("Audio streams")).LeftPosZ(4, 104).TopPosZ(180, 19))
|
||||
ITEM(ArrayCtrl, arrVideo, HSizePosZ(4, 4).TopPosZ(68, 100))
|
||||
ITEM(Label, dv___3, SetLabel(t_("Video streams")).LeftPosZ(4, 104).TopPosZ(48, 19))
|
||||
ITEM(Label, fileName, SetFrame(ThinInsetFrame()).HSizePosZ(64, 4).TopPosZ(4, 19))
|
||||
ITEM(Label, dv___5, SetLabel(t_("File name:")).LeftPosZ(4, 60).TopPosZ(4, 19))
|
||||
ITEM(Label, duration, SetFrame(ThinInsetFrame()).LeftPosZ(64, 60).TopPosZ(24, 19))
|
||||
ITEM(Label, dv___7, SetLabel(t_("Duration:")).LeftPosZ(4, 60).TopPosZ(24, 19))
|
||||
ITEM(Button, ok, SetLabel(t_("Close")).RightPosZ(4, 64).BottomPosZ(4, 20))
|
||||
ITEM(DocEdit, tags, SetFrame(ThinInsetFrame()).WantFocus(false).SetEditable(false).HSizePosZ(4, 84).VSizePosZ(324, 4))
|
||||
ITEM(Label, dv___10, SetLabel(t_("Tags")).LeftPosZ(4, 30).TopPosZ(304, 19))
|
||||
END_LAYOUT
|
||||
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
LAYOUT(VolumeCtrlDemoLayout, 200, 100)
|
||||
ITEM(VolumeCtrl, volume, LeftPosZ(20, 140).TopPosZ(24, 32))
|
||||
END_LAYOUT
|
||||
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#include <Media/MediaPlayer.h>
|
||||
#include <Media/VolumeCtrl.h>
|
||||
|
||||
#define LAYOUTFILE <Media_demo/demoVolumeCtrl.lay>
|
||||
#include <CtrlCore/lay.h>
|
||||
|
||||
class VolumeCtrlDemo : public WithMainVolumeCtrl<TopWindow> {
|
||||
public:
|
||||
typedef VolumeCtrlDemo CLASSNAME;
|
||||
VolumeCtrlDemo();
|
||||
};
|
||||
|
||||
|
||||
VolumeCtrlDemo::VolumeCtrlDemo() {
|
||||
CtrlLayout(*this, "VolumeCtrl demo");
|
||||
Zoomable().Sizeable();
|
||||
}
|
||||
|
||||
void Run_VolumeCtrl() {
|
||||
VolumeCtrlDemo().Run();
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
LAYOUT(MainVolumeCtrl, 276, 260)
|
||||
ITEM(VolumeCtrl, dv___0, SetStereo(true).SetFrame(ThinInsetFrame()).HSizePosZ(220, 4).VSizePosZ(68, 64))
|
||||
ITEM(VolumeCtrl, dv___1, SetStereo(true).SetFrame(ThinInsetFrame()).HSizePosZ(8, 4).BottomPosZ(4, 56))
|
||||
ITEM(Label, dv___2, SetLabel(t_("Move the controls to change L and R speakers\nmain volume.\nOpen PC volume controls to test it.")).SetFont(StdFontZ(12)).LeftPosZ(4, 268).TopPosZ(4, 56))
|
||||
ITEM(VolumeCtrl, dv___3, SetStereo(true).SetFrame(ThinInsetFrame()).LeftPosZ(8, 204).VSizePosZ(68, 136))
|
||||
END_LAYOUT
|
||||
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#define LAYOUTFILE <Media_demo/demo.lay>
|
||||
#include <CtrlCore/lay.h>
|
||||
|
||||
void Run_MediaPlayer();
|
||||
void Run_VolumeCtrl();
|
||||
|
||||
struct Media_Demo : public WithMain<TopWindow> {
|
||||
typedef Media_Demo CLASSNAME;
|
||||
void OnRun() {
|
||||
String demo = grid.Get(0);
|
||||
if (demo == "MediaPlayer")
|
||||
Run_MediaPlayer();
|
||||
else if (demo == "VolumeCtrl")
|
||||
Run_VolumeCtrl();
|
||||
}
|
||||
Media_Demo() {
|
||||
CtrlLayout(*this, "Media Examples");
|
||||
|
||||
butRun.WhenAction = THISBACK(OnRun);
|
||||
|
||||
grid.AddColumn("Demo", 20);
|
||||
grid.AddColumn("Description", 60);
|
||||
grid.Add("MediaPlayer", "MediaPlayer control demo");
|
||||
grid.Add("VolumeCtrl", "Simple VolumeCtrl control demo");
|
||||
grid.SetLineCy(int(1.4*StdFont().GetCy()));
|
||||
grid.WhenLeftDouble = THISBACK(OnRun);
|
||||
}
|
||||
};
|
||||
|
||||
GUI_APP_MAIN {
|
||||
Media_Demo().Run();
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue