mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 17:16:51 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aba14813c0 | ||
|
|
0f449c2394 | ||
|
|
9a30d387a1 | ||
|
|
c8e70ec0fe | ||
|
|
5546354cc7 | ||
|
|
442e021d87 | ||
|
|
4301718329 | ||
|
|
3b7688b78b | ||
|
|
d2606a5d5f | ||
|
|
0d63fac2e8 | ||
|
|
c8c760a069 | ||
|
|
0c7170989d | ||
|
|
12bfab3f10 | ||
|
|
bded2ae5df | ||
|
|
1f2d1d235e | ||
|
|
f179264468 |
26
ChangeLog
26
ChangeLog
@@ -1,4 +1,30 @@
|
||||
User johns
|
||||
Date:
|
||||
|
||||
Release Version 0.1.5
|
||||
Adds OSS mixer support.
|
||||
Fix bug: audio new stream is not thread safe.
|
||||
New audio driver OSS.
|
||||
Fix bug: needed down sampling of 3/5/6 to 2 channels not reported.
|
||||
Search audio sync inside PES packets, for insane dvb streams.
|
||||
Use only the needed number of surfaces.
|
||||
|
||||
Date: Thu Dec 29 19:44:43 CET 2011
|
||||
|
||||
Release Version 0.1.4
|
||||
Prepared vdpau noise reduction support.
|
||||
Vdpau also displays a black surface, when no video is available.
|
||||
Fix bug: CodecVideoDecode destroys avpkt.
|
||||
|
||||
Date: Thu Dec 29 00:55:57 CET 2011
|
||||
|
||||
Release Version 0.1.3
|
||||
Add missing VdpauDecoderDestroy.
|
||||
Cleanup video packet ringbuffer.
|
||||
Allow build without VDPAU.
|
||||
Fix bug: swapped end and start.
|
||||
Support other than "PCM" alsa mixer channels.
|
||||
|
||||
Date: Sat Dec 24 15:26:27 CET 2011
|
||||
|
||||
Release Version 0.1.2
|
||||
|
||||
26
Makefile
26
Makefile
@@ -18,8 +18,11 @@ VERSION = $(shell grep 'static const char \*const VERSION *=' $(PLUGIN).cpp | aw
|
||||
### Configuration (edit this for your needs)
|
||||
|
||||
CONFIG := #-DDEBUG
|
||||
CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI")
|
||||
#CONFIG += -DHAVE_PTHREAD_NAME
|
||||
CONFIG += $(shell pkg-config --exists vdpau && echo "-DUSE_VDPAU")
|
||||
CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI")
|
||||
CONFIG += $(shell pkg-config --exists alsa && echo "-DUSE_ALSA")
|
||||
#CONFIG += -DUSE_OSS
|
||||
|
||||
### The C++ compiler and options:
|
||||
|
||||
@@ -30,14 +33,27 @@ CFLAGS ?= -g -O2 -W -Wall -Wextra -Winit-self \
|
||||
-Wdeclaration-after-statement -fPIC
|
||||
#CFLAGS += -Werror
|
||||
override CFLAGS += $(DEFINES) $(INCLUDES) \
|
||||
$(shell pkg-config --cflags alsa libavcodec libavformat)
|
||||
$(shell pkg-config --cflags libavcodec libavformat) \
|
||||
`pkg-config --cflags x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
|
||||
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
|
||||
`pkg-config --cflags gl glu` \
|
||||
$(if $(findstring USE_VDPAU,$(CONFIG)), \
|
||||
`pkg-config --cflags vdpau`) \
|
||||
$(if $(findstring USE_VAAPI,$(CONFIG)), \
|
||||
`pkg-config --cflags libva-x11 libva-glx libva`) \
|
||||
$(if $(findstring USE_ALSA,$(CONFIG)), \
|
||||
`pkg-config --cflags alsa`)
|
||||
override LDFLAGS += -lrt \
|
||||
$(shell pkg-config --libs alsa libavcodec libavformat) \
|
||||
$(shell pkg-config --libs libavcodec libavformat) \
|
||||
`pkg-config --libs x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
|
||||
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
|
||||
`pkg-config --libs gl glu` \
|
||||
`pkg-config --libs vdpau` \
|
||||
`pkg-config --libs libva-x11 libva-glx libva`
|
||||
$(if $(findstring USE_VDPAU,$(CONFIG)), \
|
||||
`pkg-config --libs vdpau`) \
|
||||
$(if $(findstring USE_VAAPI,$(CONFIG)), \
|
||||
`pkg-config --libs libva-x11 libva-glx libva`) \
|
||||
$(if $(findstring USE_ALSA,$(CONFIG)), \
|
||||
`pkg-config --libs alsa`)
|
||||
|
||||
### The directory environment:
|
||||
|
||||
|
||||
50
README.txt
50
README.txt
@@ -1,6 +1,6 @@
|
||||
@file README.txt @brief A software HD output device for VDR
|
||||
|
||||
Copyright (c) 2011 by Johns. All Rights Reserved.
|
||||
Copyright (c) 2011, 2012 by Johns. All Rights Reserved.
|
||||
|
||||
Contributor(s):
|
||||
|
||||
@@ -20,14 +20,21 @@ $Id$
|
||||
|
||||
A software and GPU emulated HD output device plugin for VDR.
|
||||
|
||||
o Video VA-API/VA-API
|
||||
o Video VA-API/VA-API (with intel, nvidia and amd backend supported)
|
||||
o Video CPU/VA-API
|
||||
o Video VDPAU/VDPAU
|
||||
o Video CPU/VDPAU
|
||||
o planned: Video VA-API/Opengl
|
||||
o planned: Video VDPAU/Opengl
|
||||
o planned: Video CPU/Xv
|
||||
o planned: Video CPU/Opengl
|
||||
o planned: Software Deinterlacer
|
||||
o Audio FFMpeg/Analog
|
||||
o Audio FFMpeg/Digital
|
||||
o planned: HDMI/SPDIF Passthrough
|
||||
o planned: Video XvBA/XvBA
|
||||
o Audio FFMpeg/Alsa/Analog
|
||||
o Audio FFMpeg/Alsa/Digital
|
||||
o Audio FFMpeg/OSS/Analog
|
||||
o planned: Alsa HDMI/SPDIF Passthrough
|
||||
o planned: OSS HDMI/SPDIF Passthrough
|
||||
|
||||
To compile you must have the 'requires' installed.
|
||||
|
||||
@@ -57,24 +64,37 @@ Install:
|
||||
cd vdr-softhddevice
|
||||
make VDRDIR=<path-to-your-vdr-files> LIBDIR=.
|
||||
|
||||
You can edit Makefile to enable/disable VDPAU / VA-API / Alsa / OSS
|
||||
support.
|
||||
|
||||
Setup: environment
|
||||
------
|
||||
Following is supported:
|
||||
|
||||
DISPLAY=:0.0
|
||||
x11 display name
|
||||
only if alsa is configured
|
||||
ALSA_DEVICE=default
|
||||
alsa PCM device name
|
||||
ALSA_MIXER=default
|
||||
alsa control device name
|
||||
ALSA_MIXER_CHANNEL=PCM
|
||||
alsa control channel name
|
||||
only if oss is configured
|
||||
OSS_AUDIODEV=/dev/dsp
|
||||
oss dsp device name
|
||||
OSS_MIXERDEV=/dev/mixer
|
||||
oss mixer device name
|
||||
OSS_MIXER_CHANNEL=pcm
|
||||
oss mixer channel name
|
||||
|
||||
Setup: /etc/vdr/setup.conf
|
||||
------
|
||||
Following is supported:
|
||||
|
||||
softhddevice.Deinterlace = 0
|
||||
0 = bob, 1 = weave, 2 = temporal, 3 = temporal_spatial, 4 = software
|
||||
(only 0, 1 supported)
|
||||
(only 0, 1 supported with vaapi)
|
||||
|
||||
softhddevice.MakePrimary = 1
|
||||
0 = no change, 1 make softhddevice primary at start
|
||||
@@ -85,15 +105,27 @@ Setup: /etc/vdr/setup.conf
|
||||
softhddevice.AudioDelay = 0
|
||||
+n or -n ms
|
||||
|
||||
Commandline:
|
||||
------------
|
||||
|
||||
Use vdr -h to see the command line arguments support by the plugin.
|
||||
|
||||
Warning:
|
||||
--------
|
||||
libav is not supported, expect many bugs with it.
|
||||
|
||||
Requires:
|
||||
---------
|
||||
media-video/ffmpeg
|
||||
media-video/ffmpeg (version >=0.7)
|
||||
Complete solution to record, convert and stream audio and
|
||||
video. Includes libavcodec.
|
||||
http://ffmpeg.org
|
||||
media-libs/alsa-lib
|
||||
Advanced Linux Sound Architecture Library
|
||||
http://www.alsa-project.org
|
||||
or
|
||||
kernel support for oss/oss4 or alsa oss emulation
|
||||
|
||||
x11-libs/libva
|
||||
Video Acceleration (VA) API for Linux
|
||||
http://www.freedesktop.org/wiki/Software/vaapi
|
||||
@@ -104,7 +136,7 @@ Requires:
|
||||
x11-libs/vdpau-video
|
||||
VDPAU Backend for Video Acceleration (VA) API
|
||||
http://www.freedesktop.org/wiki/Software/vaapi
|
||||
or untested
|
||||
or
|
||||
x11-libs/xvba-video
|
||||
XVBA Backend for Video Acceleration (VA) API
|
||||
http://www.freedesktop.org/wiki/Software/vaapi
|
||||
@@ -116,7 +148,7 @@ Requires:
|
||||
x11-libs/xcb-util-keysyms
|
||||
X C-language Bindings library
|
||||
http://xcb.freedesktop.org
|
||||
Only versions >= 0.3.8 are supported
|
||||
Only versions >= 0.3.8 are good supported
|
||||
|
||||
x11-libs/libX11
|
||||
X.Org X11 library
|
||||
|
||||
50
Todo
50
Todo
@@ -1,3 +1,23 @@
|
||||
@file Todo @brief A software HD output device for VDR
|
||||
|
||||
Copyright (c) 2011, 2012 by Johns. All Rights Reserved.
|
||||
|
||||
Contributor(s):
|
||||
|
||||
License: AGPLv3
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
$Id: $
|
||||
|
||||
missing:
|
||||
video out with xv
|
||||
video out with opengl
|
||||
@@ -7,11 +27,14 @@ missing:
|
||||
atmolight
|
||||
zoom/fit-zoom 4:3
|
||||
multistream handling
|
||||
HDMI/SPDIF Passthrough
|
||||
disable screensaver
|
||||
disable window cursor
|
||||
|
||||
vdpau:
|
||||
1080i with temporal spatial too slow GT 520
|
||||
1080i with temporal spatial and level 1 scaling too slow with GT 520
|
||||
1080i with temporal spatial too slow with GT 520 on some channels
|
||||
VdpPreemptionCallback handling
|
||||
Loose a surface
|
||||
|
||||
libva-intel-driver:
|
||||
intel still has hangups most with 1080i
|
||||
@@ -25,7 +48,6 @@ libva-vdpau-driver:
|
||||
-> vaDestroyContext -> pthread_rwlock_wrlock)
|
||||
|
||||
libva-xvba-driver:
|
||||
mpeg1/2 needs software decoder fixed
|
||||
|
||||
x11:
|
||||
support resize of x11 window
|
||||
@@ -35,19 +57,27 @@ x11:
|
||||
disable cursor
|
||||
|
||||
audio/alsa:
|
||||
video/audio asyncron
|
||||
random crash in av_parser_parse2, when switching channels
|
||||
done? video/audio asyncron
|
||||
random crashes in av_parser_parse2, when switching channels
|
||||
sometimes alsa hangs
|
||||
|
||||
playback of >2 channels on 2 channel hardware
|
||||
done?
|
||||
better downmix of >2 channels on 2 channel hardware
|
||||
remix support of unsupported sample rates
|
||||
libav supports only resample of mono to 2 channels
|
||||
ffmpeg didn't support resample of 5 to 2 channels
|
||||
CodecAudioOpen can fail "can't open audio codec" and does Fatal exit.
|
||||
|
||||
on some channels it takes long time until sound can be heared.
|
||||
this channels has packet start not at the beginning of the start packet
|
||||
audio/oss:
|
||||
alsa oss emulation mixer "pcm" not working
|
||||
ring buffer overflow with alsa oss emulation
|
||||
|
||||
playback of recording
|
||||
play back is too fast
|
||||
|
||||
setup:
|
||||
Setup menu parameters aren't automatic loaded?
|
||||
Setup of decoder type.
|
||||
Setup of output type.
|
||||
Setup of display type.
|
||||
Setup 4:3 zoom type
|
||||
Setup parameters are not used until restart.
|
||||
Can a notice be added to the setup menu?
|
||||
|
||||
276
codec.c
276
codec.c
@@ -1,7 +1,7 @@
|
||||
///
|
||||
/// @file codec.c @brief Codec functions
|
||||
///
|
||||
/// Copyright (c) 2009 - 2011 by Johns. All Rights Reserved.
|
||||
/// Copyright (c) 2009 - 2012 by Johns. All Rights Reserved.
|
||||
///
|
||||
/// Contributor(s):
|
||||
///
|
||||
@@ -26,6 +26,14 @@
|
||||
/// This module contains all decoder and codec functions.
|
||||
/// It is uses ffmpeg (http://ffmpeg.org) as backend.
|
||||
///
|
||||
/// It may work with libav (http://libav.org), but the tests show
|
||||
/// many bugs and incompatiblity in it. Don't use this shit.
|
||||
///
|
||||
|
||||
/**
|
||||
** use av_parser to support insane dvb audio streams.
|
||||
*/
|
||||
#define USE_AVPARSER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
@@ -44,6 +52,11 @@
|
||||
#include <libavcodec/vdpau.h>
|
||||
#endif
|
||||
|
||||
#ifndef __USE_GNU
|
||||
#define __USE_GNU
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef MAIN_H
|
||||
#include MAIN_H
|
||||
#endif
|
||||
@@ -52,6 +65,18 @@
|
||||
#include "audio.h"
|
||||
#include "codec.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Global
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// ffmpeg lock mutex
|
||||
///
|
||||
/// new ffmpeg dislikes simultanous open/close
|
||||
/// this breaks our code, until this is fixed use lock.
|
||||
///
|
||||
static pthread_mutex_t CodecLockMutex;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Video
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -348,16 +373,20 @@ void CodecVideoOpen(VideoDecoder * decoder, const char *name, int codec_id)
|
||||
}
|
||||
// FIXME: for software decoder use all cpus, otherwise 1
|
||||
decoder->VideoCtx->thread_count = 1;
|
||||
pthread_mutex_lock(&CodecLockMutex);
|
||||
// open codec
|
||||
#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(53,5,0)
|
||||
if (avcodec_open(decoder->VideoCtx, video_codec) < 0) {
|
||||
pthread_mutex_unlock(&CodecLockMutex);
|
||||
Fatal(_("codec: can't open video codec!\n"));
|
||||
}
|
||||
#else
|
||||
if (avcodec_open2(decoder->VideoCtx, video_codec, NULL) < 0) {
|
||||
pthread_mutex_unlock(&CodecLockMutex);
|
||||
Fatal(_("codec: can't open video codec!\n"));
|
||||
}
|
||||
#endif
|
||||
pthread_mutex_unlock(&CodecLockMutex);
|
||||
|
||||
decoder->VideoCtx->opaque = decoder; // our structure
|
||||
|
||||
@@ -436,7 +465,9 @@ void CodecVideoClose(VideoDecoder * video_decoder)
|
||||
// FIXME: play buffered data
|
||||
av_freep(&video_decoder->Frame);
|
||||
if (video_decoder->VideoCtx) {
|
||||
pthread_mutex_lock(&CodecLockMutex);
|
||||
avcodec_close(video_decoder->VideoCtx);
|
||||
pthread_mutex_unlock(&CodecLockMutex);
|
||||
av_freep(&video_decoder->VideoCtx);
|
||||
}
|
||||
}
|
||||
@@ -446,9 +477,9 @@ void CodecVideoClose(VideoDecoder * video_decoder)
|
||||
/**
|
||||
** Display pts...
|
||||
**
|
||||
** ffmpeg 0.9 pts always AV_NOPTS_VALUE
|
||||
** ffmpeg 0.9 pkt_pts nice monotonic (only with HD)
|
||||
** ffmpeg 0.9 pkt_dts wild jumping -160 - 340 ms
|
||||
** ffmpeg-0.9 pts always AV_NOPTS_VALUE
|
||||
** ffmpeg-0.9 pkt_pts nice monotonic (only with HD)
|
||||
** ffmpeg-0.9 pkt_dts wild jumping -160 - 340 ms
|
||||
**
|
||||
** libav 0.8_pre20111116 pts always AV_NOPTS_VALUE
|
||||
** libav 0.8_pre20111116 pkt_pts always 0 (could be fixed?)
|
||||
@@ -483,32 +514,28 @@ void DisplayPts(AVCodecContext * video_ctx, AVFrame * frame)
|
||||
**
|
||||
** @param decoder video decoder data
|
||||
** @param avpkt video packet
|
||||
**
|
||||
** @note this version destroys avpkt!!
|
||||
*/
|
||||
void CodecVideoDecode(VideoDecoder * decoder, AVPacket * avpkt)
|
||||
void CodecVideoDecode(VideoDecoder * decoder, const AVPacket * avpkt)
|
||||
{
|
||||
AVCodecContext *video_ctx;
|
||||
AVFrame *frame;
|
||||
int used;
|
||||
int got_frame;
|
||||
AVPacket pkt[1];
|
||||
|
||||
video_ctx = decoder->VideoCtx;
|
||||
frame = decoder->Frame;
|
||||
*pkt = *avpkt; // use copy
|
||||
|
||||
next_part:
|
||||
// FIXME: this function can crash with bad packets
|
||||
used = avcodec_decode_video2(video_ctx, frame, &got_frame, avpkt);
|
||||
Debug(4, "%s: %p %d -> %d %d\n", __FUNCTION__, avpkt->data, avpkt->size,
|
||||
used, got_frame);
|
||||
used = avcodec_decode_video2(video_ctx, frame, &got_frame, pkt);
|
||||
Debug(4, "%s: %p %d -> %d %d\n", __FUNCTION__, pkt->data, pkt->size, used,
|
||||
got_frame);
|
||||
|
||||
if (got_frame) { // frame completed
|
||||
//DisplayPts(video_ctx, frame);
|
||||
if (video_ctx->hwaccel_context) {
|
||||
VideoRenderFrame(decoder->HwDecoder, video_ctx, frame);
|
||||
} else {
|
||||
VideoRenderFrame(decoder->HwDecoder, video_ctx, frame);
|
||||
}
|
||||
VideoRenderFrame(decoder->HwDecoder, video_ctx, frame);
|
||||
} else {
|
||||
// some frames are needed for references, interlaced frames ...
|
||||
// could happen with h264 dvb streams, just drop data.
|
||||
@@ -516,23 +543,18 @@ void CodecVideoDecode(VideoDecoder * decoder, AVPacket * avpkt)
|
||||
Debug(4, "codec: %8d incomplete interlaced frame %d bytes used\n",
|
||||
video_ctx->frame_number, used);
|
||||
}
|
||||
if (used != avpkt->size) {
|
||||
if (used == 0) {
|
||||
goto next_part;
|
||||
}
|
||||
if (used != pkt->size) {
|
||||
if (used >= 0) {
|
||||
// some tv channels, produce this
|
||||
Debug(4,
|
||||
"codec: ooops didn't use complete video packet used %d of %d\n",
|
||||
used, avpkt->size);
|
||||
avpkt->data += used;
|
||||
avpkt->size -= used;
|
||||
used, pkt->size);
|
||||
pkt->data += used;
|
||||
pkt->size -= used;
|
||||
goto next_part;
|
||||
}
|
||||
Debug(3, "codec: bad frame %d\n", used);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -554,7 +576,7 @@ struct _audio_decoder_
|
||||
AVCodec *AudioCodec; ///< audio codec
|
||||
AVCodecContext *AudioCtx; ///< audio codec context
|
||||
|
||||
/// audio parser to support wired dvb streaks
|
||||
/// audio parser to support insane dvb streaks
|
||||
AVCodecParserContext *AudioParser;
|
||||
int SampleRate; ///< current stream sample rate
|
||||
int Channels; ///< current stream channels
|
||||
@@ -606,16 +628,20 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, const char *name,
|
||||
if (!(audio_decoder->AudioCtx = avcodec_alloc_context3(audio_codec))) {
|
||||
Fatal(_("codec: can't allocate audio codec context\n"));
|
||||
}
|
||||
pthread_mutex_lock(&CodecLockMutex);
|
||||
// open codec
|
||||
#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(53,5,0)
|
||||
if (avcodec_open(audio_decoder->AudioCtx, audio_codec) < 0) {
|
||||
pthread_mutex_unlock(&CodecLockMutex);
|
||||
Fatal(_("codec: can't open audio codec\n"));
|
||||
}
|
||||
#else
|
||||
if (avcodec_open2(audio_decoder->AudioCtx, audio_codec, NULL) < 0) {
|
||||
pthread_mutex_unlock(&CodecLockMutex);
|
||||
Fatal(_("codec: can't open audio codec\n"));
|
||||
}
|
||||
#endif
|
||||
pthread_mutex_unlock(&CodecLockMutex);
|
||||
Debug(3, "codec: audio '%s'\n", audio_decoder->AudioCtx->codec_name);
|
||||
|
||||
if (audio_codec->capabilities & CODEC_CAP_TRUNCATED) {
|
||||
@@ -650,20 +676,24 @@ void CodecAudioClose(AudioDecoder * audio_decoder)
|
||||
audio_decoder->AudioParser = NULL;
|
||||
}
|
||||
if (audio_decoder->AudioCtx) {
|
||||
pthread_mutex_lock(&CodecLockMutex);
|
||||
avcodec_close(audio_decoder->AudioCtx);
|
||||
pthread_mutex_unlock(&CodecLockMutex);
|
||||
av_freep(&audio_decoder->AudioCtx);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_AVPARSER
|
||||
|
||||
/**
|
||||
** Decode an audio packet.
|
||||
**
|
||||
** PTS must be handled self.
|
||||
**
|
||||
** @param audio_decoder audio_Decoder data
|
||||
** @param audio_decoder audio decoder data
|
||||
** @param avpkt audio packet
|
||||
*/
|
||||
void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
|
||||
void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
||||
{
|
||||
int16_t buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 4 +
|
||||
FF_INPUT_BUFFER_PADDING_SIZE] __attribute__ ((aligned(16)));
|
||||
@@ -708,7 +738,7 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
|
||||
buf_sz = sizeof(buf);
|
||||
l = avcodec_decode_audio3(audio_ctx, buf, &buf_sz, dpkt);
|
||||
if (l < 0) { // no audio frame could be decompressed
|
||||
Error(_("codec: error audio data\n"));
|
||||
Error(_("codec: error audio data at %d\n"), index);
|
||||
break;
|
||||
}
|
||||
#ifdef notyetFF_API_OLD_DECODE_AUDIO
|
||||
@@ -741,8 +771,10 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
|
||||
if ((err =
|
||||
AudioSetup(&audio_decoder->HwSampleRate,
|
||||
&audio_decoder->HwChannels))) {
|
||||
Debug(3, "codec/audio: resample %d -> %d\n",
|
||||
audio_ctx->channels, audio_decoder->HwChannels);
|
||||
Debug(3, "codec/audio: resample %dHz *%d -> %dHz *%d\n",
|
||||
audio_ctx->sample_rate, audio_ctx->channels,
|
||||
audio_decoder->HwSampleRate,
|
||||
audio_decoder->HwChannels);
|
||||
|
||||
if (err == 1) {
|
||||
audio_decoder->ReSample =
|
||||
@@ -750,10 +782,18 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
|
||||
audio_ctx->channels, audio_decoder->HwSampleRate,
|
||||
audio_ctx->sample_rate, audio_ctx->sample_fmt,
|
||||
audio_ctx->sample_fmt, 16, 10, 0, 0.8);
|
||||
// libav-0.8_pre didn't support 6 -> 2 channels
|
||||
if (!audio_decoder->ReSample) {
|
||||
Error(_("codec/audio: resample setup error\n"));
|
||||
audio_decoder->HwChannels = 0;
|
||||
audio_decoder->HwSampleRate = 0;
|
||||
}
|
||||
} else {
|
||||
Debug(3, "codec/audio: audio setup error\n");
|
||||
// FIXME: handle errors
|
||||
audio_decoder->HwChannels = 0;
|
||||
audio_decoder->HwSampleRate = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -766,10 +806,25 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
|
||||
__attribute__ ((aligned(16)));
|
||||
int outlen;
|
||||
|
||||
// FIXME: libav-0.7.2 crash here
|
||||
outlen =
|
||||
audio_resample(audio_decoder->ReSample, outbuf, buf,
|
||||
buf_sz);
|
||||
AudioEnqueue(outbuf, outlen);
|
||||
#ifdef DEBUG
|
||||
if (outlen != buf_sz) {
|
||||
Debug(3, "codec/audio: possible fixed ffmpeg\n");
|
||||
}
|
||||
#endif
|
||||
if (outlen) {
|
||||
// outlen seems to be wrong in ffmpeg-0.9
|
||||
outlen /= audio_decoder->Channels *
|
||||
av_get_bytes_per_sample(audio_ctx->sample_fmt);
|
||||
outlen *=
|
||||
audio_decoder->HwChannels *
|
||||
av_get_bytes_per_sample(audio_ctx->sample_fmt);
|
||||
Debug(4, "codec/audio: %d -> %d\n", buf_sz, outlen);
|
||||
AudioEnqueue(outbuf, outlen);
|
||||
}
|
||||
} else {
|
||||
AudioEnqueue(buf, buf_sz);
|
||||
}
|
||||
@@ -784,10 +839,167 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
|
||||
}
|
||||
|
||||
#if 1
|
||||
// or av_free_packet, make no difference here
|
||||
av_destruct_packet(spkt);
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/**
|
||||
** Decode an audio packet.
|
||||
**
|
||||
** PTS must be handled self.
|
||||
**
|
||||
** @param audio_decoder audio decoder data
|
||||
** @param avpkt audio packet
|
||||
*/
|
||||
void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
||||
{
|
||||
int16_t buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 4 +
|
||||
FF_INPUT_BUFFER_PADDING_SIZE] __attribute__ ((aligned(16)));
|
||||
AVCodecContext *audio_ctx;
|
||||
int index;
|
||||
|
||||
//#define spkt avpkt
|
||||
#if 1
|
||||
AVPacket spkt[1];
|
||||
|
||||
// av_new_packet reserves FF_INPUT_BUFFER_PADDING_SIZE and clears it
|
||||
if (av_new_packet(spkt, avpkt->size)) {
|
||||
Error(_("codec: out of memory\n"));
|
||||
return;
|
||||
}
|
||||
memcpy(spkt->data, avpkt->data, avpkt->size);
|
||||
spkt->pts = avpkt->pts;
|
||||
spkt->dts = avpkt->dts;
|
||||
#endif
|
||||
audio_ctx = audio_decoder->AudioCtx;
|
||||
index = 0;
|
||||
while (spkt->size > index) {
|
||||
int n;
|
||||
int buf_sz;
|
||||
AVPacket dpkt[1];
|
||||
|
||||
av_init_packet(dpkt);
|
||||
dpkt->data = spkt->data + index;
|
||||
dpkt->size = spkt->size - index;
|
||||
|
||||
buf_sz = sizeof(buf);
|
||||
n = avcodec_decode_audio3(audio_ctx, buf, &buf_sz, dpkt);
|
||||
if (n < 0) { // no audio frame could be decompressed
|
||||
Error(_("codec: error audio data at %d\n"), index);
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
Debug(4, "codec/audio: -> %d\n", buf_sz);
|
||||
if ((unsigned)buf_sz > sizeof(buf)) {
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
#ifdef notyetFF_API_OLD_DECODE_AUDIO
|
||||
// FIXME: ffmpeg git comeing
|
||||
int got_frame;
|
||||
|
||||
avcodec_decode_audio4(audio_ctx, frame, &got_frame, dpkt);
|
||||
#else
|
||||
#endif
|
||||
if (buf_sz > 0) { // something decoded
|
||||
// Update audio clock
|
||||
if ((uint64_t) spkt->pts != AV_NOPTS_VALUE) {
|
||||
AudioSetClock(spkt->pts);
|
||||
spkt->pts = AV_NOPTS_VALUE;
|
||||
}
|
||||
// FIXME: must first play remainings bytes, than change and play new.
|
||||
if (audio_decoder->SampleRate != audio_ctx->sample_rate
|
||||
|| audio_decoder->Channels != audio_ctx->channels) {
|
||||
int err;
|
||||
|
||||
if (audio_decoder->ReSample) {
|
||||
audio_resample_close(audio_decoder->ReSample);
|
||||
audio_decoder->ReSample = NULL;
|
||||
}
|
||||
|
||||
audio_decoder->SampleRate = audio_ctx->sample_rate;
|
||||
audio_decoder->HwSampleRate = audio_ctx->sample_rate;
|
||||
audio_decoder->Channels = audio_ctx->channels;
|
||||
audio_decoder->HwChannels = audio_ctx->channels;
|
||||
|
||||
// channels not support?
|
||||
if ((err =
|
||||
AudioSetup(&audio_decoder->HwSampleRate,
|
||||
&audio_decoder->HwChannels))) {
|
||||
Debug(3, "codec/audio: resample %dHz *%d -> %dHz *%d\n",
|
||||
audio_ctx->sample_rate, audio_ctx->channels,
|
||||
audio_decoder->HwSampleRate,
|
||||
audio_decoder->HwChannels);
|
||||
|
||||
if (err == 1) {
|
||||
audio_decoder->ReSample =
|
||||
av_audio_resample_init(audio_decoder->HwChannels,
|
||||
audio_ctx->channels, audio_decoder->HwSampleRate,
|
||||
audio_ctx->sample_rate, audio_ctx->sample_fmt,
|
||||
audio_ctx->sample_fmt, 16, 10, 0, 0.8);
|
||||
// libav-0.8_pre didn't support 6 -> 2 channels
|
||||
if (!audio_decoder->ReSample) {
|
||||
Error(_("codec/audio: resample setup error\n"));
|
||||
audio_decoder->HwChannels = 0;
|
||||
audio_decoder->HwSampleRate = 0;
|
||||
}
|
||||
} else {
|
||||
// FIXME: handle errors
|
||||
Debug(3, "codec/audio: audio setup error\n");
|
||||
audio_decoder->HwChannels = 0;
|
||||
audio_decoder->HwSampleRate = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (audio_decoder->HwSampleRate && audio_decoder->HwChannels) {
|
||||
// need to resample audio
|
||||
if (audio_decoder->ReSample) {
|
||||
int16_t outbuf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 4 +
|
||||
FF_INPUT_BUFFER_PADDING_SIZE]
|
||||
__attribute__ ((aligned(16)));
|
||||
int outlen;
|
||||
|
||||
// FIXME: libav-0.7.2 crash here
|
||||
outlen =
|
||||
audio_resample(audio_decoder->ReSample, outbuf, buf,
|
||||
buf_sz);
|
||||
#ifdef DEBUG
|
||||
if (outlen != buf_sz) {
|
||||
Debug(3, "codec/audio: possible fixed ffmpeg\n");
|
||||
}
|
||||
#endif
|
||||
if (outlen) {
|
||||
// outlen seems to be wrong in ffmpeg-0.9
|
||||
outlen /= audio_ctx->channels *
|
||||
av_get_bytes_per_sample(audio_ctx->sample_fmt);
|
||||
outlen *=
|
||||
audio_decoder->HwChannels *
|
||||
av_get_bytes_per_sample(audio_ctx->sample_fmt);
|
||||
Debug(4, "codec/audio: %d -> %d\n", buf_sz, outlen);
|
||||
AudioEnqueue(outbuf, outlen);
|
||||
}
|
||||
} else {
|
||||
AudioEnqueue(buf, buf_sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
index += n;
|
||||
}
|
||||
|
||||
#if 1
|
||||
// or av_free_packet, make no difference here
|
||||
av_destruct_packet(spkt);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Codec
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -807,6 +1019,7 @@ static void CodecNoopCallback( __attribute__ ((unused))
|
||||
*/
|
||||
void CodecInit(void)
|
||||
{
|
||||
pthread_mutex_init(&CodecLockMutex, NULL);
|
||||
#ifndef DEBUG
|
||||
// disable display ffmpeg error messages
|
||||
av_log_set_callback(CodecNoopCallback);
|
||||
@@ -821,4 +1034,5 @@ void CodecInit(void)
|
||||
*/
|
||||
void CodecExit(void)
|
||||
{
|
||||
pthread_mutex_destroy(&CodecLockMutex);
|
||||
}
|
||||
|
||||
4
codec.h
4
codec.h
@@ -47,7 +47,7 @@ extern void CodecVideoOpen(VideoDecoder *, const char *, int);
|
||||
extern void CodecVideoClose(VideoDecoder *);
|
||||
|
||||
/// Decode a video packet
|
||||
extern void CodecVideoDecode(VideoDecoder *, AVPacket * pkt);
|
||||
extern void CodecVideoDecode(VideoDecoder *, const AVPacket * pkt);
|
||||
|
||||
/// Allocate a new audio decoder context.
|
||||
extern AudioDecoder *CodecAudioNewDecoder(void);
|
||||
@@ -59,7 +59,7 @@ extern void CodecAudioOpen(AudioDecoder *, const char *, int);
|
||||
extern void CodecAudioClose(AudioDecoder *);
|
||||
|
||||
/// Decode an audio packet
|
||||
extern void CodecAudioDecode(AudioDecoder *, AVPacket * pkt);
|
||||
extern void CodecAudioDecode(AudioDecoder *, const AVPacket * pkt);
|
||||
|
||||
/// Setup and initialize codec module.
|
||||
extern void CodecInit(void);
|
||||
|
||||
27
misc.h
27
misc.h
@@ -1,7 +1,7 @@
|
||||
///
|
||||
/// @file misc.h @brief Misc function header file
|
||||
///
|
||||
/// Copyright (c) 2009 - 2011 by Lutz Sammer. All Rights Reserved.
|
||||
/// Copyright (c) 2009 - 2012 by Lutz Sammer. All Rights Reserved.
|
||||
///
|
||||
/// Contributor(s):
|
||||
/// Copied from uwm.
|
||||
@@ -46,24 +46,28 @@ extern int SysLogLevel; ///< how much information wanted
|
||||
// Prototypes
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline void Debug(const int, const char *format, ...)
|
||||
static inline void Syslog(const int, const char *format, ...)
|
||||
__attribute__ ((format(printf, 2, 3)));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Inlines
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DebugLevel 4 /// private debug level
|
||||
#else
|
||||
#define DebugLevel 0 /// private debug level
|
||||
#endif
|
||||
|
||||
/**
|
||||
** Debug output function.
|
||||
** Syslog output function.
|
||||
**
|
||||
** - 0 fatal errors and errors
|
||||
** - 1 warnings
|
||||
** - 2 info
|
||||
** - 3 important debug and fixme's
|
||||
*/
|
||||
static inline void Debug(const int level, const char *format, ...)
|
||||
static inline void Syslog(const int level, const char *format, ...)
|
||||
{
|
||||
if (SysLogLevel > level || DebugLevel > level) {
|
||||
va_list ap;
|
||||
@@ -77,7 +81,7 @@ static inline void Debug(const int level, const char *format, ...)
|
||||
/**
|
||||
** Show error.
|
||||
*/
|
||||
#define Error(fmt...) Debug(0, fmt)
|
||||
#define Error(fmt...) Syslog(0, fmt)
|
||||
|
||||
/**
|
||||
** Show fatal error.
|
||||
@@ -87,12 +91,21 @@ static inline void Debug(const int level, const char *format, ...)
|
||||
/**
|
||||
** Show warning.
|
||||
*/
|
||||
#define Warning(fmt...) Debug(1, fmt)
|
||||
#define Warning(fmt...) Syslog(1, fmt)
|
||||
|
||||
/**
|
||||
** Show info.
|
||||
*/
|
||||
#define Info(fmt...) Debug(2, fmt)
|
||||
#define Info(fmt...) Syslog(2, fmt)
|
||||
|
||||
/**
|
||||
** Show debug.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
#define Debug(level, fmt...) Syslog(level, fmt)
|
||||
#else
|
||||
#define Debug(level, fmt...) /* disabled */
|
||||
#endif
|
||||
|
||||
/**
|
||||
** Get ticks in ms.
|
||||
|
||||
266
softhddev.c
266
softhddev.c
@@ -1,7 +1,7 @@
|
||||
///
|
||||
/// @file softhddev.c @brief A software HD device plugin for VDR.
|
||||
///
|
||||
/// Copyright (c) 2011 by Johns. All Rights Reserved.
|
||||
/// Copyright (c) 2011, 2012 by Johns. All Rights Reserved.
|
||||
///
|
||||
/// Contributor(s):
|
||||
///
|
||||
@@ -44,17 +44,138 @@
|
||||
|
||||
static char BrokenThreadsAndPlugins; ///< broken vdr threads and plugins
|
||||
|
||||
#ifdef USE_VDPAU
|
||||
static char ConfigVdpauDecoder = 1; ///< use vdpau decoder, if possible
|
||||
#else
|
||||
#define ConfigVdpauDecoder 0 ///< no vdpau decoder configured
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Audio
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static volatile char NewAudioStream; ///< new audio stream
|
||||
static AudioDecoder *MyAudioDecoder; ///< audio decoder
|
||||
static enum CodecID AudioCodecID; ///< current codec id
|
||||
|
||||
extern void AudioTest(void); // FIXME:
|
||||
|
||||
/**
|
||||
** mpeg bitrate table.
|
||||
**
|
||||
** BitRateTable[Version][Layer][Index]
|
||||
*/
|
||||
static const uint16_t BitRateTable[2][4][16] = {
|
||||
// MPEG Version 1
|
||||
{{},
|
||||
{0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,
|
||||
0},
|
||||
{0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0},
|
||||
{0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0}},
|
||||
// MPEG Version 2 & 2.5
|
||||
{{},
|
||||
{0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0},
|
||||
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0},
|
||||
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
** mpeg samperate table.
|
||||
*/
|
||||
static const uint16_t SampleRateTable[4] = {
|
||||
44100, 48000, 32000, 0
|
||||
};
|
||||
|
||||
/**
|
||||
** Find sync in audio packet.
|
||||
**
|
||||
** @param avpkt audio packet
|
||||
**
|
||||
** From: http://www.mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm
|
||||
**
|
||||
** AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM
|
||||
**
|
||||
** o a 11x frame sync
|
||||
** o b 2x mpeg audio version (2.5, reserved, 2, 1)
|
||||
** o c 2x layer (reserved, III, II, I)
|
||||
** o e 2x BitRate index
|
||||
** o f 2x SampleRate index
|
||||
** o g 1x Paddding bit
|
||||
** o .. doesn't care
|
||||
**
|
||||
** frame length:
|
||||
** Layer I:
|
||||
** FrameLengthInBytes = (12 * BitRate / SampleRate + Padding) * 4
|
||||
** Layer II & III:
|
||||
** FrameLengthInBytes = 144 * BitRate / SampleRate + Padding
|
||||
*/
|
||||
static int FindAudioSync(const AVPacket * avpkt)
|
||||
{
|
||||
int i;
|
||||
const uint8_t *data;
|
||||
|
||||
i = 0;
|
||||
data = avpkt->data;
|
||||
while (i < avpkt->size - 4) {
|
||||
if (data[i] == 0xFF && (data[i + 1] & 0xFC) == 0xFC) {
|
||||
int mpeg2;
|
||||
int mpeg25;
|
||||
int layer;
|
||||
int bit_rate_index;
|
||||
int sample_rate_index;
|
||||
int padding;
|
||||
int bit_rate;
|
||||
int sample_rate;
|
||||
int frame_size;
|
||||
|
||||
mpeg2 = !(data[i + 1] & 0x08) && (data[i + 1] & 0x10);
|
||||
mpeg25 = !(data[i + 1] & 0x08) && !(data[i + 1] & 0x10);
|
||||
layer = 4 - ((data[i + 1] >> 1) & 0x03);
|
||||
bit_rate_index = (data[i + 2] >> 4) & 0x0F;
|
||||
sample_rate_index = (data[i + 2] >> 2) & 0x03;
|
||||
padding = (data[i + 2] >> 1) & 0x01;
|
||||
|
||||
sample_rate = SampleRateTable[sample_rate_index];
|
||||
if (!sample_rate) { // no valid sample rate try next
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
sample_rate >>= mpeg2; // mpeg 2 half rate
|
||||
sample_rate >>= mpeg25; // mpeg 2.5 quarter rate
|
||||
|
||||
bit_rate = BitRateTable[mpeg2 | mpeg25][layer][bit_rate_index];
|
||||
bit_rate *= 1000;
|
||||
switch (layer) {
|
||||
case 1:
|
||||
frame_size = (12 * bit_rate) / sample_rate;
|
||||
frame_size = (frame_size + padding) * 4;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
default:
|
||||
frame_size = (144 * bit_rate) / sample_rate;
|
||||
frame_size = frame_size + padding;
|
||||
break;
|
||||
}
|
||||
Debug(3,
|
||||
"audio: mpeg%s layer%d bitrate=%d samplerate=%d %d bytes\n",
|
||||
mpeg25 ? "2.5" : mpeg2 ? "2" : "1", layer, bit_rate,
|
||||
sample_rate, frame_size);
|
||||
if (i + frame_size < avpkt->size - 4) {
|
||||
if (data[i + frame_size] == 0xFF
|
||||
&& (data[i + frame_size + 1] & 0xFC) == 0xFC) {
|
||||
Debug(3, "audio: mpeg1/2 found at %d\n", i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// no valid frame size or no continuation, try next
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
** Play audio packet.
|
||||
**
|
||||
@@ -62,7 +183,8 @@ extern void AudioTest(void); // FIXME:
|
||||
** @param size size of PES packet
|
||||
** @param id PES packet type
|
||||
*/
|
||||
void PlayAudio(const uint8_t * data, int size, uint8_t id)
|
||||
void PlayAudio(const uint8_t * data, int size,
|
||||
__attribute__ ((unused)) uint8_t id)
|
||||
{
|
||||
int n;
|
||||
AVPacket avpkt[1];
|
||||
@@ -70,13 +192,16 @@ void PlayAudio(const uint8_t * data, int size, uint8_t id)
|
||||
if (BrokenThreadsAndPlugins) {
|
||||
return;
|
||||
}
|
||||
// PES header 0x00 0x00 0x01 ID
|
||||
// ID 0xBD 0xC0-0xCF
|
||||
|
||||
// channel switch: SetAudioChannelDevice: SetDigitalAudioDevice:
|
||||
|
||||
// Detect audio code
|
||||
// MPEG-PS mp2 MPEG1, MPEG2, AC3
|
||||
if (NewAudioStream) {
|
||||
// FIXME: does this clear the audio ringbuffer?
|
||||
CodecAudioClose(MyAudioDecoder);
|
||||
AudioCodecID = CODEC_ID_NONE;
|
||||
NewAudioStream = 0;
|
||||
}
|
||||
// PES header 0x00 0x00 0x01 ID
|
||||
// ID 0xBD 0xC0-0xCF
|
||||
|
||||
if (size < 9) {
|
||||
Error(_("[softhddev] invalid audio packet\n"));
|
||||
@@ -107,6 +232,9 @@ void PlayAudio(const uint8_t * data, int size, uint8_t id)
|
||||
Error(_("[softhddev] invalid audio packet\n"));
|
||||
return;
|
||||
}
|
||||
// Detect audio code
|
||||
// MPEG-PS mp2 MPEG1, MPEG2, AC3
|
||||
|
||||
// Syncword - 0x0B77
|
||||
if (data[0] == 0x0B && data[1] == 0x77) {
|
||||
if (!MyAudioDecoder) {
|
||||
@@ -137,9 +265,23 @@ void PlayAudio(const uint8_t * data, int size, uint8_t id)
|
||||
// no start package
|
||||
// FIXME: Nick/Viva sends this shit, need to find sync in packet
|
||||
// FIXME: otherwise it takes too long until sound appears
|
||||
|
||||
if (AudioCodecID == CODEC_ID_NONE) {
|
||||
Debug(3, "[softhddev]%s: ??? %d\n", __FUNCTION__, id);
|
||||
return;
|
||||
avpkt->data = (void *)data;
|
||||
avpkt->size = size;
|
||||
n = FindAudioSync(avpkt);
|
||||
if (n < 0) {
|
||||
return;
|
||||
}
|
||||
if (!MyAudioDecoder) {
|
||||
MyAudioDecoder = CodecAudioNewDecoder();
|
||||
}
|
||||
|
||||
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_MP2);
|
||||
AudioCodecID = CODEC_ID_MP2;
|
||||
data += n;
|
||||
size -= n;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,13 +326,13 @@ void SetVolumeDevice(int volume)
|
||||
|
||||
#include <alsa/iatomic.h> // portable atomic_t
|
||||
|
||||
uint32_t VideoSwitch;
|
||||
static int NewVideoStream; ///< new video stream
|
||||
uint32_t VideoSwitch; ///< debug video switch ticks
|
||||
static volatile char NewVideoStream; ///< new video stream
|
||||
static VideoDecoder *MyVideoDecoder; ///< video decoder
|
||||
static enum CodecID VideoCodecID; ///< current codec id
|
||||
|
||||
static const char *X11DisplayName; ///< x11 display name
|
||||
static volatile int Usr1Signal; ///< true got usr1 signal
|
||||
static volatile char Usr1Signal; ///< true got usr1 signal
|
||||
|
||||
/// video PES buffer default size
|
||||
#define VIDEO_BUFFER_SIZE (512 * 1024)
|
||||
@@ -200,8 +342,8 @@ static AVPacket VideoPacketRb[VIDEO_PACKET_MAX];
|
||||
static int VideoPacketWrite; ///< write pointer
|
||||
static int VideoPacketRead; ///< read pointer
|
||||
static atomic_t VideoPacketsFilled; ///< how many of the buffer is used
|
||||
static char VideoFreezed; ///< video freezed
|
||||
static char VideoClearBuffers; ///< clear video buffers
|
||||
static volatile char VideoFreezed; ///< video freezed
|
||||
static volatile char VideoClearBuffers; ///< clear video buffers
|
||||
|
||||
#ifdef DEBUG
|
||||
static int VideoMaxPacketSize; ///< biggest used packet buffer
|
||||
@@ -277,6 +419,9 @@ static void VideoEnqueue(int64_t pts, const void *data, int size)
|
||||
/ (VIDEO_BUFFER_SIZE / 2)) * (VIDEO_BUFFER_SIZE / 2));
|
||||
#ifdef DEBUG
|
||||
if (avpkt->size <= avpkt->stream_index + size) {
|
||||
fprintf(stderr, "%d %d %d\n", avpkt->size, avpkt->stream_index,
|
||||
size);
|
||||
fflush(stderr);
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
@@ -376,6 +521,7 @@ int VideoDecode(void)
|
||||
CodecVideoClose(MyVideoDecoder);
|
||||
goto skip;
|
||||
}
|
||||
goto skip;
|
||||
break;
|
||||
case CODEC_ID_MPEG2VIDEO:
|
||||
if (last_codec_id != CODEC_ID_MPEG2VIDEO) {
|
||||
@@ -434,6 +580,44 @@ static void StartVideo(void)
|
||||
VideoPacketInit();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
/**
|
||||
** Validate mpeg video packet.
|
||||
**
|
||||
** Function to validate a mpeg packet, not needed.
|
||||
*/
|
||||
static int ValidateMpeg(const uint8_t * data, int size)
|
||||
{
|
||||
int pes_l;
|
||||
|
||||
do {
|
||||
if (size < 9) {
|
||||
return -1;
|
||||
}
|
||||
if (data[0] || data[1] || data[2] != 0x01) {
|
||||
printf("%02x: %02x %02x %02x %02x %02x\n", data[-1], data[0],
|
||||
data[1], data[2], data[3], data[4]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pes_l = (data[4] << 8) | data[5];
|
||||
if (!pes_l) { // contains unknown length
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (6 + pes_l > size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
data += 6 + pes_l;
|
||||
size -= 6 + pes_l;
|
||||
} while (size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
** Play video packet.
|
||||
**
|
||||
@@ -463,7 +647,7 @@ int PlayVideo(const uint8_t * data, int size)
|
||||
if (!MyVideoDecoder) { // no x11 video started
|
||||
return size;
|
||||
}
|
||||
if (NewVideoStream) {
|
||||
if (NewVideoStream) { // channel switched
|
||||
Debug(3, "video: new stream %d\n", GetMsTicks() - VideoSwitch);
|
||||
// FIXME: hack to test results
|
||||
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
|
||||
@@ -482,13 +666,15 @@ int PlayVideo(const uint8_t * data, int size)
|
||||
}
|
||||
n = data[8]; // header size
|
||||
// wrong size
|
||||
if (size < 9 + n) {
|
||||
if (size < 9 + n + 4) {
|
||||
Error(_("[softhddev] invalid video packet\n"));
|
||||
return size;
|
||||
}
|
||||
check = data + 9 + n;
|
||||
|
||||
// FIXME: get pts/dts, when we need it
|
||||
// FIXME: hack to test results
|
||||
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
|
||||
return 0;
|
||||
}
|
||||
// get pts/dts
|
||||
|
||||
pts = AV_NOPTS_VALUE;
|
||||
if (data[7] & 0x80) {
|
||||
@@ -496,6 +682,10 @@ int PlayVideo(const uint8_t * data, int size)
|
||||
(int64_t) (data[9] & 0x0E) << 29 | data[10] << 22 | (data[11] &
|
||||
0xFE) << 14 | data[12] << 7 | (data[13] & 0xFE) >> 1;
|
||||
#ifdef DEBUG
|
||||
if (!(data[13] & 1) || !(data[11] & 1) || !(data[9] & 1)) {
|
||||
Error(_("[softhddev] invalid pts in video packet\n"));
|
||||
return size;
|
||||
}
|
||||
//Debug(3, "video: pts %#012" PRIx64 "\n", pts);
|
||||
if (data[13] != (((pts & 0x7F) << 1) | 1)) {
|
||||
abort();
|
||||
@@ -509,35 +699,36 @@ int PlayVideo(const uint8_t * data, int size)
|
||||
if (data[10] != ((pts >> 22) & 0xFF)) {
|
||||
abort();
|
||||
}
|
||||
if ((data[9] & 0x0F) != (((pts >> 30) << 1) | 1)) {
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// FIXME: no valid mpeg2/h264 detection yet
|
||||
|
||||
check = data + 9 + n;
|
||||
if (0) {
|
||||
printf("%02x: %02x %02x %02x %02x %02x\n", data[6], check[0], check[1],
|
||||
check[2], check[3], check[4]);
|
||||
}
|
||||
// PES_VIDEO_STREAM 0xE0 or PES start code
|
||||
if ((data[6] & 0xC0) != 0x80 || (!check[0] && !check[1]
|
||||
&& check[2] == 0x1)) {
|
||||
//(data[6] & 0xC0) != 0x80 ||
|
||||
if ((!check[0] && !check[1] && check[2] == 0x1)) {
|
||||
if (VideoCodecID == CODEC_ID_MPEG2VIDEO) {
|
||||
// FIXME: hack to test results
|
||||
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
|
||||
return 0;
|
||||
}
|
||||
VideoNextPacket(CODEC_ID_MPEG2VIDEO);
|
||||
} else {
|
||||
Debug(3, "video: mpeg2 detected\n");
|
||||
Debug(3, "video: mpeg2 detected ID %02x\n", check[3]);
|
||||
VideoCodecID = CODEC_ID_MPEG2VIDEO;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (ValidateMpeg(data, size)) {
|
||||
Debug(3, "softhddev/video: invalid mpeg2 video packet\n");
|
||||
}
|
||||
#endif
|
||||
// Access Unit Delimiter
|
||||
} else if (!check[0] && !check[1] && !check[2] && check[3] == 0x1
|
||||
&& check[4] == 0x09) {
|
||||
} else if ((data[6] & 0xC0) == 0x80 && !check[0] && !check[1]
|
||||
&& !check[2] && check[3] == 0x1 && check[4] == 0x09) {
|
||||
if (VideoCodecID == CODEC_ID_H264) {
|
||||
// FIXME: hack to test results
|
||||
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
|
||||
return 0;
|
||||
}
|
||||
VideoNextPacket(CODEC_ID_H264);
|
||||
} else {
|
||||
Debug(3, "video: h264 detected\n");
|
||||
@@ -550,11 +741,8 @@ int PlayVideo(const uint8_t * data, int size)
|
||||
return size;
|
||||
}
|
||||
if (VideoCodecID == CODEC_ID_MPEG2VIDEO) {
|
||||
// mpeg codec supports incomplete packages
|
||||
// FIXME: hack to test results
|
||||
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
|
||||
return 0;
|
||||
}
|
||||
// mpeg codec supports incomplete packets
|
||||
// waiting for a full complete packages, increases needed delays
|
||||
VideoNextPacket(CODEC_ID_MPEG2VIDEO);
|
||||
}
|
||||
}
|
||||
@@ -582,9 +770,7 @@ void SetPlayMode(void)
|
||||
}
|
||||
}
|
||||
if (MyAudioDecoder) {
|
||||
// FIXME: does this clear the audio ringbuffer?
|
||||
CodecAudioClose(MyAudioDecoder);
|
||||
AudioCodecID = CODEC_ID_NONE;
|
||||
NewAudioStream = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -881,10 +1067,12 @@ void Stop(void)
|
||||
// no it doesn't do a good thread cleanup
|
||||
if (MyVideoDecoder) {
|
||||
CodecVideoClose(MyVideoDecoder);
|
||||
// FIXME: CodecDelVideoDecoder(MyVideoDecoder);
|
||||
MyVideoDecoder = NULL;
|
||||
}
|
||||
if (MyAudioDecoder) {
|
||||
CodecAudioClose(MyAudioDecoder);
|
||||
// FIXME: CodecDelAudioDecoder(MyAudioDecoder);
|
||||
MyAudioDecoder = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
///
|
||||
/// @file softhddevice.cpp @brief A software HD device plugin for VDR.
|
||||
///
|
||||
/// Copyright (c) 2011 by Johns. All Rights Reserved.
|
||||
/// Copyright (c) 2011, 2012 by Johns. All Rights Reserved.
|
||||
///
|
||||
/// Contributor(s):
|
||||
///
|
||||
@@ -35,11 +35,12 @@
|
||||
#include "softhddevice.h"
|
||||
extern "C" {
|
||||
#include "video.h"
|
||||
extern void AudioPoller(void);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const char *const VERSION = "0.1.3";
|
||||
static const char *const VERSION = "0.1.5";
|
||||
static const char *const DESCRIPTION =
|
||||
trNOOP("A software and GPU emulated HD device");
|
||||
|
||||
@@ -332,6 +333,9 @@ class cSoftHdDevice:public cDevice
|
||||
virtual void GetOsdSize(int &, int &, double &);
|
||||
virtual int PlayVideo(const uchar *, int);
|
||||
//virtual int PlayTsVideo(const uchar *, int);
|
||||
#ifdef USE_OSS // FIXME: testing only oss
|
||||
virtual int PlayTsAudio(const uchar *, int);
|
||||
#endif
|
||||
virtual void SetAudioChannelDevice(int);
|
||||
virtual int GetAudioChannelDevice(void);
|
||||
virtual void SetDigitalAudioDevice(bool);
|
||||
@@ -569,6 +573,20 @@ int cSoftHdDevice::PlayTsVideo(const uchar * Data, int Length)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_OSS // FIXME: testing only oss
|
||||
///
|
||||
/// Play a TS audio packet.
|
||||
///
|
||||
/// misuse this function as audio poller
|
||||
///
|
||||
int cSoftHdDevice::PlayTsAudio(const uchar * data, int length)
|
||||
{
|
||||
AudioPoller();
|
||||
|
||||
return cDevice::PlayTsAudio(data,length);
|
||||
}
|
||||
#endif
|
||||
|
||||
uchar *cSoftHdDevice::GrabImage(int &size, bool jpeg, int quality, int sizex,
|
||||
int sizey)
|
||||
{
|
||||
|
||||
164
video.c
164
video.c
@@ -68,6 +68,10 @@
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
#ifndef HAVE_PTHREAD_NAME
|
||||
/// only available with newer glibc
|
||||
#define pthread_setname_np(thread, name)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_XLIB_XCB
|
||||
@@ -163,7 +167,11 @@ typedef enum _video_zoom_modes_
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#define CODEC_SURFACES_MAX 31 ///< maximal of surfaces
|
||||
|
||||
#define CODEC_SURFACES_DEFAULT (21+4) ///< default of surfaces
|
||||
// FIXME: video-xvba only supports 14
|
||||
#define xCODEC_SURFACES_DEFAULT 14 ///< default of surfaces
|
||||
|
||||
#define CODEC_SURFACES_MPEG2 3 ///< 1 decode, up to 2 references
|
||||
#define CODEC_SURFACES_MPEG4 3 ///< 1 decode, up to 2 references
|
||||
#define CODEC_SURFACES_H264 21 ///< 1 decode, up to 20 references
|
||||
@@ -756,6 +764,7 @@ struct _vaapi_decoder_
|
||||
|
||||
struct vaapi_context VaapiContext[1]; ///< ffmpeg VA-API context
|
||||
|
||||
int SurfacesNeeded; ///< number of surface to request
|
||||
int SurfaceUsedN; ///< number of used surfaces
|
||||
/// used surface ids
|
||||
VASurfaceID SurfacesUsed[CODEC_SURFACES_MAX];
|
||||
@@ -815,11 +824,16 @@ static void VaapiBlackSurface(VaapiDecoder * decoder);
|
||||
///
|
||||
static void VaapiCreateSurfaces(VaapiDecoder * decoder, int width, int height)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (!decoder->SurfacesNeeded) {
|
||||
Error(_("video/vaapi: surface needed not set\n"));
|
||||
decoder->SurfacesNeeded = 3 + VIDEO_SURFACES_MAX;
|
||||
}
|
||||
#endif
|
||||
Debug(3, "video/vaapi: %s: %dx%d * %d\n", __FUNCTION__, width, height,
|
||||
CODEC_SURFACES_DEFAULT);
|
||||
decoder->SurfacesNeeded);
|
||||
|
||||
// FIXME: allocate only the number of needed surfaces
|
||||
decoder->SurfaceFreeN = CODEC_SURFACES_DEFAULT;
|
||||
decoder->SurfaceFreeN = decoder->SurfacesNeeded;
|
||||
// VA_RT_FORMAT_YUV420 VA_RT_FORMAT_YUV422 VA_RT_FORMAT_YUV444
|
||||
if (vaCreateSurfaces(decoder->VaDisplay, width, height,
|
||||
VA_RT_FORMAT_YUV420, decoder->SurfaceFreeN,
|
||||
@@ -868,7 +882,7 @@ static void VaapiCreateSurfaces(VaapiDecoder * decoder, int width, int height)
|
||||
Error(_("video/vaapi: can't associate subpicture\n"));
|
||||
}
|
||||
for (i = 0; i < decoder->SurfaceFreeN; ++i) {
|
||||
Debug(3, "video/vaapi: associate %08x\n",
|
||||
Debug(4, "video/vaapi: associate %#010x surface\n",
|
||||
decoder->SurfacesFree[i]);
|
||||
}
|
||||
}
|
||||
@@ -988,6 +1002,9 @@ static void VaapiPrintFrames(const VaapiDecoder * decoder)
|
||||
Debug(3, "video/vaapi: %d missed, %d duped, %d dropped frames of %d\n",
|
||||
decoder->FramesMissed, decoder->FramesDuped, decoder->FramesDropped,
|
||||
decoder->FrameCounter);
|
||||
#ifndef DEBUG
|
||||
(void)decoder;
|
||||
#endif
|
||||
}
|
||||
|
||||
///
|
||||
@@ -1479,14 +1496,19 @@ static enum PixelFormat Vaapi_get_format(VaapiDecoder * decoder,
|
||||
// check profile
|
||||
switch (video_ctx->codec_id) {
|
||||
case CODEC_ID_MPEG2VIDEO:
|
||||
decoder->SurfacesNeeded =
|
||||
CODEC_SURFACES_MPEG2 + VIDEO_SURFACES_MAX;
|
||||
p = VaapiFindProfile(profiles, profile_n, VAProfileMPEG2Main);
|
||||
break;
|
||||
case CODEC_ID_MPEG4:
|
||||
case CODEC_ID_H263:
|
||||
decoder->SurfacesNeeded =
|
||||
CODEC_SURFACES_MPEG4 + VIDEO_SURFACES_MAX;
|
||||
p = VaapiFindProfile(profiles, profile_n,
|
||||
VAProfileMPEG4AdvancedSimple);
|
||||
break;
|
||||
case CODEC_ID_H264:
|
||||
decoder->SurfacesNeeded = CODEC_SURFACES_H264 + VIDEO_SURFACES_MAX;
|
||||
// try more simple formats, fallback to better
|
||||
if (video_ctx->profile == FF_PROFILE_H264_BASELINE) {
|
||||
p = VaapiFindProfile(profiles, profile_n,
|
||||
@@ -1503,9 +1525,11 @@ static enum PixelFormat Vaapi_get_format(VaapiDecoder * decoder,
|
||||
}
|
||||
break;
|
||||
case CODEC_ID_WMV3:
|
||||
decoder->SurfacesNeeded = CODEC_SURFACES_VC1 + VIDEO_SURFACES_MAX;
|
||||
p = VaapiFindProfile(profiles, profile_n, VAProfileVC1Main);
|
||||
break;
|
||||
case CODEC_ID_VC1:
|
||||
decoder->SurfacesNeeded = CODEC_SURFACES_VC1 + VIDEO_SURFACES_MAX;
|
||||
p = VaapiFindProfile(profiles, profile_n, VAProfileVC1Advanced);
|
||||
break;
|
||||
default:
|
||||
@@ -1620,6 +1644,7 @@ static enum PixelFormat Vaapi_get_format(VaapiDecoder * decoder,
|
||||
|
||||
slow_path:
|
||||
// no accelerated format found
|
||||
decoder->SurfacesNeeded = 1 + VIDEO_SURFACES_MAX;
|
||||
video_ctx->hwaccel_context = NULL;
|
||||
return avcodec_default_get_format(video_ctx, fmt);
|
||||
}
|
||||
@@ -1950,7 +1975,7 @@ static void VaapiQueueSurface(VaapiDecoder * decoder, VASurfaceID surface,
|
||||
++decoder->FramesDropped;
|
||||
Warning(_("video: output buffer full, dropping frame (%d/%d)\n"),
|
||||
decoder->FramesDropped, decoder->FrameCounter);
|
||||
if (!(decoder->FramesDisplayed % 100)) {
|
||||
if (!(decoder->FramesDisplayed % 300)) {
|
||||
VaapiPrintFrames(decoder);
|
||||
}
|
||||
if (softdec) { // software surfaces only
|
||||
@@ -2031,7 +2056,7 @@ static void VaapiQueueSurface(VaapiDecoder * decoder, VASurfaceID surface,
|
||||
% VIDEO_SURFACES_MAX;
|
||||
atomic_inc(&decoder->SurfacesFilled);
|
||||
|
||||
Debug(4, "video/vaapi: yy video surface %#x ready\n", surface);
|
||||
Debug(4, "video/vaapi: yy video surface %#010x ready\n", surface);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -2099,7 +2124,7 @@ static void VaapiBlackSurface(VaapiDecoder * decoder)
|
||||
start = GetMsTicks();
|
||||
}
|
||||
|
||||
Debug(4, "video/vaapi: yy black video surface %#x displayed\n",
|
||||
Debug(4, "video/vaapi: yy black video surface %#010x displayed\n",
|
||||
decoder->BlackSurface);
|
||||
sync = GetMsTicks();
|
||||
xcb_flush(Connection);
|
||||
@@ -2239,7 +2264,7 @@ static void VaapiCpuDeinterlace(VaapiDecoder * decoder, VASurfaceID surface)
|
||||
vaPutImage(decoder->VaDisplay, surface, image->image_id, 0, 0,
|
||||
image->width, image->height, 0, 0, image->width,
|
||||
image->height)) != VA_STATUS_SUCCESS) {
|
||||
Fatal("video/vaapi: can't put image %d!\n", status);
|
||||
Error("video/vaapi: can't put image %d!\n", status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2297,7 +2322,7 @@ static void VaapiCpuDeinterlace(VaapiDecoder * decoder, VASurfaceID surface)
|
||||
if (vaPutImage(VaDisplay, out1, img2->image_id, 0, 0, img2->width,
|
||||
img2->height, 0, 0, img2->width,
|
||||
img2->height) != VA_STATUS_SUCCESS) {
|
||||
Fatal("video/vaapi: can't put image!\n");
|
||||
Error("video/vaapi: can't put image!\n");
|
||||
}
|
||||
VaapiQueueSurface(decoder, out1, 1);
|
||||
if (0 && vaSyncSurface(decoder->VaDisplay, out1) != VA_STATUS_SUCCESS) {
|
||||
@@ -2308,7 +2333,7 @@ static void VaapiCpuDeinterlace(VaapiDecoder * decoder, VASurfaceID surface)
|
||||
if (vaPutImage(VaDisplay, out2, img3->image_id, 0, 0, img3->width,
|
||||
img3->height, 0, 0, img3->width,
|
||||
img3->height) != VA_STATUS_SUCCESS) {
|
||||
Fatal("video/vaapi: can't put image!\n");
|
||||
Error("video/vaapi: can't put image!\n");
|
||||
}
|
||||
VaapiQueueSurface(decoder, out2, 1);
|
||||
if (0 && vaSyncSurface(decoder->VaDisplay, out2) != VA_STATUS_SUCCESS) {
|
||||
@@ -2429,6 +2454,9 @@ static void VaapiRenderFrame(VaapiDecoder * decoder,
|
||||
|
||||
VaapiSetup(decoder, video_ctx);
|
||||
|
||||
// FIXME: bad interlace like hw-part
|
||||
// FIXME: aspect ratio
|
||||
|
||||
//
|
||||
// detect interlaced input
|
||||
//
|
||||
@@ -2447,7 +2475,7 @@ static void VaapiRenderFrame(VaapiDecoder * decoder,
|
||||
//
|
||||
if (vaMapBuffer(VaDisplay, decoder->Image->buf, &va_image_data)
|
||||
!= VA_STATUS_SUCCESS) {
|
||||
Fatal("video/vaapi: can't map the image!\n");
|
||||
Error(_("video/vaapi: can't map the image!\n"));
|
||||
}
|
||||
for (i = 0; (unsigned)i < decoder->Image->num_planes; ++i) {
|
||||
picture->data[i] = va_image_data + decoder->Image->offsets[i];
|
||||
@@ -2458,16 +2486,19 @@ static void VaapiRenderFrame(VaapiDecoder * decoder,
|
||||
width, height);
|
||||
|
||||
if (vaUnmapBuffer(VaDisplay, decoder->Image->buf) != VA_STATUS_SUCCESS) {
|
||||
Fatal("video/vaapi: can't unmap the image!\n");
|
||||
Error(_("video/vaapi: can't unmap the image!\n"));
|
||||
}
|
||||
// get a free surface and upload the image
|
||||
surface = VaapiGetSurface(decoder);
|
||||
Debug(4, "video/vaapi: video surface %#010x displayed\n", surface);
|
||||
Debug(4, "video/vaapi: buffer %dx%d <- %dx%d\n", decoder->Image->width,
|
||||
decoder->Image->height, width, height);
|
||||
|
||||
// FIXME: intel didn't support put image.
|
||||
if ((i = vaPutImage(VaDisplay, surface, decoder->Image->image_id, 0, 0,
|
||||
width, height, 0, 0, width, height)
|
||||
) != VA_STATUS_SUCCESS) {
|
||||
Fatal("video/vaapi: can't put image %d!\n", i);
|
||||
Error(_("video/vaapi: can't put image err:%d!\n"), i);
|
||||
}
|
||||
|
||||
VaapiQueueSurface(decoder, surface, 1);
|
||||
@@ -2559,7 +2590,7 @@ static void VaapiDisplayFrame(void)
|
||||
if (surface == VA_INVALID_ID) {
|
||||
printf(_("video/vaapi: invalid surface in ringbuffer\n"));
|
||||
}
|
||||
Debug(4, "video/vaapi: yy video surface %#x displayed\n", surface);
|
||||
Debug(4, "video/vaapi: yy video surface %#010x displayed\n", surface);
|
||||
#endif
|
||||
|
||||
start = GetMsTicks();
|
||||
@@ -2633,7 +2664,7 @@ static void VaapiSyncDisplayFrame(VaapiDecoder * decoder)
|
||||
decoder->FramesDuped++;
|
||||
Warning(_("video: display buffer empty, duping frame (%d/%d)\n"),
|
||||
decoder->FramesDuped, decoder->FrameCounter);
|
||||
if (!(decoder->FramesDisplayed % 333)) {
|
||||
if (!(decoder->FramesDisplayed % 300)) {
|
||||
VaapiPrintFrames(decoder);
|
||||
}
|
||||
}
|
||||
@@ -2697,7 +2728,7 @@ static void VaapiSyncRenderFrame(VaapiDecoder * decoder,
|
||||
++decoder->FramesDropped;
|
||||
Warning(_("video: dropping frame (%d/%d)\n"), decoder->FramesDropped,
|
||||
decoder->FrameCounter);
|
||||
if (!(decoder->FramesDisplayed % 100)) {
|
||||
if (!(decoder->FramesDisplayed % 300)) {
|
||||
VaapiPrintFrames(decoder);
|
||||
}
|
||||
decoder->DropNextFrame = 0;
|
||||
@@ -3103,6 +3134,7 @@ static int VdpauHqScalingMax; ///< highest supported scaling level
|
||||
static int VdpauTemporal; ///< temporal deinterlacer supported
|
||||
static int VdpauTemporalSpatial; ///< temporal spatial deint. supported
|
||||
static int VdpauInverseTelecine; ///< inverse telecine deint. supported
|
||||
static int VdpauNoiseReduction; ///< noise reduction supported
|
||||
static int VdpauSkipChroma; ///< skip chroma deint. supported
|
||||
|
||||
/// display surface ring buffer
|
||||
@@ -3332,6 +3364,9 @@ static void VdpauPrintFrames(const VdpauDecoder * decoder)
|
||||
Debug(3, "video/vdpau: %d missed, %d duped, %d dropped frames of %d\n",
|
||||
decoder->FramesMissed, decoder->FramesDuped, decoder->FramesDropped,
|
||||
decoder->FrameCounter);
|
||||
#ifndef DEBUG
|
||||
(void)decoder;
|
||||
#endif
|
||||
}
|
||||
|
||||
///
|
||||
@@ -3343,8 +3378,8 @@ static void VdpauMixerSetup(VdpauDecoder * decoder)
|
||||
{
|
||||
VdpStatus status;
|
||||
int i;
|
||||
VdpVideoMixerFeature features[13];
|
||||
VdpBool enables[13];
|
||||
VdpVideoMixerFeature features[14];
|
||||
VdpBool enables[14];
|
||||
int feature_n;
|
||||
VdpVideoMixerParameter paramaters[10];
|
||||
void const *values[10];
|
||||
@@ -3366,8 +3401,9 @@ static void VdpauMixerSetup(VdpauDecoder * decoder)
|
||||
if (VdpauInverseTelecine) {
|
||||
features[feature_n++] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE;
|
||||
}
|
||||
// FIXME:
|
||||
// VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION
|
||||
if (VdpauNoiseReduction) {
|
||||
features[feature_n++] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION;
|
||||
}
|
||||
// VDP_VIDEO_MIXER_FEATURE_SHARPNESS
|
||||
for (i = VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1;
|
||||
i <= VdpauHqScalingMax; ++i) {
|
||||
@@ -3426,6 +3462,12 @@ static void VdpauMixerSetup(VdpauDecoder * decoder)
|
||||
Debug(3, "video/vdpau: inverse telecine %s\n",
|
||||
enables[feature_n - 1] ? "enabled" : "disabled");
|
||||
}
|
||||
if (VdpauNoiseReduction) {
|
||||
enables[feature_n] = VDP_FALSE;
|
||||
features[feature_n++] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE;
|
||||
Debug(3, "video/vdpau: noise reduction %s\n",
|
||||
enables[feature_n - 1] ? "enabled" : "disabled");
|
||||
}
|
||||
for (i = VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1;
|
||||
i <= VdpauHqScalingMax; ++i) {
|
||||
enables[feature_n] =
|
||||
@@ -3440,6 +3482,11 @@ static void VdpauMixerSetup(VdpauDecoder * decoder)
|
||||
|
||||
/*
|
||||
FIXME:
|
||||
VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL
|
||||
VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL
|
||||
VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA
|
||||
VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA
|
||||
VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE
|
||||
VdpVideoMixerSetAttributeValues(decoder->Mixer, attribute_n,
|
||||
attributes, values);
|
||||
*/
|
||||
@@ -3862,6 +3909,16 @@ static void VideoVdpauInit(const char *display_name)
|
||||
VdpauInverseTelecine = flag;
|
||||
}
|
||||
|
||||
status =
|
||||
VdpauVideoMixerQueryFeatureSupport(VdpauDevice,
|
||||
VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION, &flag);
|
||||
if (status != VDP_STATUS_OK) {
|
||||
Error(_("video/vdpau: can't query feature '%s': %s\n"),
|
||||
"noise-reduction", VdpauGetErrorString(status));
|
||||
} else {
|
||||
VdpauNoiseReduction = flag;
|
||||
}
|
||||
|
||||
status =
|
||||
VdpauVideoMixerQueryFeatureSupport(VdpauDevice,
|
||||
VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE, &flag);
|
||||
@@ -4301,7 +4358,9 @@ static void VdpauQueueSurface(VdpauDecoder * decoder, VdpVideoSurface surface,
|
||||
Warning(_
|
||||
("video/vdpau: output buffer full, dropping frame (%d/%d)\n"),
|
||||
++decoder->FramesDropped, decoder->FrameCounter);
|
||||
VdpauPrintFrames(decoder);
|
||||
if (!(decoder->FramesDisplayed % 300)) {
|
||||
VdpauPrintFrames(decoder);
|
||||
}
|
||||
// software surfaces only
|
||||
if (softdec) {
|
||||
VdpauReleaseSurface(decoder, surface);
|
||||
@@ -4660,6 +4719,44 @@ static void VdpauMixVideo(VdpauDecoder * decoder)
|
||||
decoder->SurfaceRead);
|
||||
}
|
||||
|
||||
///
|
||||
/// Create and display a black empty surface.
|
||||
///
|
||||
/// @param decoder VDPAU hw decoder
|
||||
///
|
||||
static void VdpauBlackSurface(VdpauDecoder * decoder)
|
||||
{
|
||||
VdpStatus status;
|
||||
void *image;
|
||||
void const *data[1];
|
||||
uint32_t pitches[1];
|
||||
VdpRect dst_rect;
|
||||
|
||||
Debug(3, "video/vdpau: black surface\n");
|
||||
|
||||
// FIXME: clear video window area
|
||||
(void)decoder;
|
||||
|
||||
image = calloc(4, VideoWindowWidth * VideoWindowHeight);
|
||||
|
||||
dst_rect.x0 = 0;
|
||||
dst_rect.y0 = 0;
|
||||
dst_rect.x1 = dst_rect.x0 + VideoWindowWidth;
|
||||
dst_rect.y1 = dst_rect.y0 + VideoWindowHeight;
|
||||
data[0] = image;
|
||||
pitches[0] = VideoWindowWidth * 4;
|
||||
|
||||
status =
|
||||
VdpauOutputSurfacePutBitsNative(VdpauSurfacesRb[VdpauSurfaceIndex],
|
||||
data, pitches, &dst_rect);
|
||||
if (status != VDP_STATUS_OK) {
|
||||
Error(_("video/vdpau: output surface put bits failed: %s\n"),
|
||||
VdpauGetErrorString(status));
|
||||
}
|
||||
|
||||
free(image);
|
||||
}
|
||||
|
||||
///
|
||||
/// Advance displayed frame.
|
||||
///
|
||||
@@ -4689,7 +4786,7 @@ static void VdpauAdvanceFrame(void)
|
||||
Warning(_
|
||||
("video: display buffer empty, duping frame (%d/%d)\n"),
|
||||
decoder->FramesDuped, decoder->FrameCounter);
|
||||
if (!(decoder->FramesDisplayed % 333)) {
|
||||
if (!(decoder->FramesDisplayed % 300)) {
|
||||
VdpauPrintFrames(decoder);
|
||||
}
|
||||
decoder->SurfaceField = decoder->Interlaced;
|
||||
@@ -4736,7 +4833,12 @@ static void VdpauDisplayFrame(void)
|
||||
// FIXME: can be more than 1 frame long shown
|
||||
for (i = 0; i < VdpauDecoderN; ++i) {
|
||||
VdpauDecoders[i]->FramesMissed++;
|
||||
VdpauPrintFrames(VdpauDecoders[i]);
|
||||
Warning(_("video: missed frame (%d/%d)\n"),
|
||||
VdpauDecoders[i]->FramesMissed,
|
||||
VdpauDecoders[i]->FrameCounter);
|
||||
if (!(VdpauDecoders[i]->FramesDisplayed % 300)) {
|
||||
VdpauPrintFrames(VdpauDecoders[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
last_time = first_time;
|
||||
@@ -4755,8 +4857,8 @@ static void VdpauDisplayFrame(void)
|
||||
filled = atomic_read(&decoder->SurfacesFilled);
|
||||
// need 1 frame for progressive, 3 frames for interlaced
|
||||
if (filled < 1 + 2 * decoder->Interlaced) {
|
||||
// FIXME: render black surface
|
||||
// FIXME: or rewrite MixVideo to support less surfaces
|
||||
// FIXME: rewrite MixVideo to support less surfaces
|
||||
VdpauBlackSurface(decoder);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -4810,7 +4912,7 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder)
|
||||
decoder->FramesDuped++;
|
||||
Warning(_("video: display buffer empty, duping frame (%d/%d)\n"),
|
||||
decoder->FramesDuped, decoder->FrameCounter);
|
||||
if (!(decoder->FramesDisplayed % 333)) {
|
||||
if (!(decoder->FramesDisplayed % 300)) {
|
||||
VdpauPrintFrames(decoder);
|
||||
}
|
||||
}
|
||||
@@ -4875,7 +4977,7 @@ static void VdpauSyncRenderFrame(VdpauDecoder * decoder,
|
||||
++decoder->FramesDropped;
|
||||
Warning(_("video: dropping frame (%d/%d)\n"), decoder->FramesDropped,
|
||||
decoder->FrameCounter);
|
||||
if (!(decoder->FramesDisplayed % 100)) {
|
||||
if (!(decoder->FramesDisplayed % 300)) {
|
||||
VdpauPrintFrames(decoder);
|
||||
}
|
||||
decoder->DropNextFrame = 0;
|
||||
@@ -5648,6 +5750,7 @@ void VideoDisplayHandler(void)
|
||||
pthread_mutex_init(&VideoLockMutex, NULL);
|
||||
pthread_cond_init(&VideoWakeupCond, NULL);
|
||||
pthread_create(&VideoThread, NULL, VideoDisplayHandlerThread, NULL);
|
||||
pthread_setname_np(VideoThread, "softhddev video");
|
||||
//pthread_detach(VideoThread);
|
||||
}
|
||||
}
|
||||
@@ -5879,6 +5982,7 @@ struct vaapi_context *VideoGetVaapiContext(VideoHwDecoder * decoder)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef USE_VDPAU
|
||||
///
|
||||
/// Draw ffmpeg vdpau render state.
|
||||
///
|
||||
@@ -5888,7 +5992,6 @@ struct vaapi_context *VideoGetVaapiContext(VideoHwDecoder * decoder)
|
||||
void VideoDrawRenderState(VideoHwDecoder * decoder,
|
||||
struct vdpau_render_state *vrs)
|
||||
{
|
||||
#ifdef USE_VDPAU
|
||||
if (VideoVdpauEnabled) {
|
||||
VdpStatus status;
|
||||
uint32_t start;
|
||||
@@ -5906,17 +6009,18 @@ void VideoDrawRenderState(VideoHwDecoder * decoder,
|
||||
VdpauGetErrorString(status));
|
||||
}
|
||||
if (end - start > 35) {
|
||||
Debug(3, "video/vdpau: decoder render too slow %u ms\n",
|
||||
// report this
|
||||
Info(_("video/vdpau: decoder render too slow %u ms\n"),
|
||||
end - start);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
(void)decoder;
|
||||
(void)vrs;
|
||||
Error(_("video/vdpau: draw render state, without vdpau enabled\n"));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef USE_VIDEO_THREAD
|
||||
|
||||
|
||||
Reference in New Issue
Block a user