Packages moved to archive/bazaar

git-svn-id: svn://ultimatepp.org/upp/trunk@11633 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
koldo 2017-12-26 23:15:57 +00:00
parent 70ee1b1b3f
commit 1718274ff1
38 changed files with 0 additions and 22088 deletions

View file

@ -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";

View file

@ -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;
}

View file

@ -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

View file

@ -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 = &params;
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() {
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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

View file

@ -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

View file

@ -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();
}
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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; ]

View file

@ -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; ]

View file

@ -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;
}
}

View file

@ -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));
}

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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";

View file

@ -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

View file

@ -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();
}

View file

@ -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

View file

@ -1,4 +0,0 @@
LAYOUT(VolumeCtrlDemoLayout, 200, 100)
ITEM(VolumeCtrl, volume, LeftPosZ(20, 140).TopPosZ(24, 32))
END_LAYOUT

View file

@ -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();
}

View file

@ -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

View file

@ -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