diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 5413ad79be..35e3a4bfe1 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -920,8 +920,7 @@ Input Commands that are Possibly Subject to Change ``--glsl-shader=file.glsl``. -Undocumented commands: ``tv-last-channel`` (TV/DVB only), -``ao-reload`` (experimental/internal). +Undocumented commands: ``ao-reload`` (experimental/internal). Hooks ~~~~~ @@ -1181,8 +1180,6 @@ Property list ``media-title`` If the currently played file has a ``title`` tag, use that. - Otherwise, if the media type is DVD, return the volume ID of DVD. - Otherwise, return the ``filename`` property. ``file-format`` @@ -1295,40 +1292,6 @@ Property list Current MKV edition number. Setting this property to a different value will restart playback. The number of the first edition is 0. -``disc-titles`` - Number of BD/DVD titles. - - This has a number of sub-properties. Replace ``N`` with the 0-based edition - index. - - ``disc-titles/count`` - Number of titles. - - ``disc-titles/id`` - Title ID as integer. Currently, this is the same as the title index. - - ``disc-titles/length`` - Length in seconds. Can be unavailable in a number of cases (currently - it works for libdvdnav only). - - When querying the property with the client API using ``MPV_FORMAT_NODE``, - or with Lua ``mp.get_property_native``, this will return a mpv_node with - the following contents: - - :: - - MPV_FORMAT_NODE_ARRAY - MPV_FORMAT_NODE_MAP (for each edition) - "id" MPV_FORMAT_INT64 - "length" MPV_FORMAT_DOUBLE - -``disc-title-list`` - List of BD/DVD titles. - -``disc-title`` (RW) - Current BD/DVD title number. Writing works only for ``dvdnav://`` and - ``bd://`` (and aliases for these). - ``chapters`` Number of chapters. @@ -1368,9 +1331,6 @@ Property list "title" MPV_FORMAT_STRING "default" MPV_FORMAT_FLAG -``angle`` (RW) - Current DVD angle. - ``metadata`` Metadata key/value pairs. @@ -1843,18 +1803,6 @@ Property list ``osd-par`` Last known OSD display pixel aspect (can be 0). -``program`` (W) - Switch TS program (write-only). - -``dvb-channel`` (W) - Pair of integers: card,channel of current DVB stream. - Can be switched to switch to another channel on the same card. - -``dvb-channel-name`` (RW) - Name of current DVB program. - On write, a channel-switch to the named channel on the same - card is performed. Can also be used for channel switching. - ``sub-text`` Return the current subtitle text. Formatting is stripped. If a subtitle is selected, but no text is currently visible, or the subtitle is not @@ -1862,9 +1810,6 @@ Property list This property is experimental and might be removed in the future. -``tv-brightness``, ``tv-contrast``, ``tv-saturation``, ``tv-hue`` (RW) - TV stuff. - ``playlist-pos`` (RW) Current position on playlist. The first entry is on position 0. Writing to the property will restart playback at the written entry. diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index c8e75556c0..dee217bcf2 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -12,8 +12,8 @@ Track Selection .. admonition:: Examples - - ``mpv dvd://1 --alang=hu,en`` chooses the Hungarian language track - on a DVD and falls back on English if Hungarian is not available. + - ``mpv file.mkv --alang=hu,en`` chooses the Hungarian language track + in a file and falls back on English if Hungarian is not available. - ``mpv --alang=jpn example.mkv`` plays a Matroska file with Japanese audio. @@ -25,8 +25,8 @@ Track Selection .. admonition:: Examples - - ``mpv dvd://1 --slang=hu,en`` chooses the Hungarian subtitle track on - a DVD and falls back on English if Hungarian is not available. + - ``mpv file.mkv --slang=hu,en`` chooses the Hungarian subtitle track on + in a file and falls back on English if Hungarian is not available. - ``mpv --slang=jpn example.mkv`` plays a Matroska file with Japanese subtitles. @@ -281,10 +281,8 @@ Playback Control This option does not prevent opening of paired subtitle files and such. Use ``--autoload-files=no`` to prevent this. - This option does not always work if you open non-files (for example using - ``dvd://directory`` would open a whole bunch of files in the given - directory). Prefixing the filename with ``./`` if it doesn't start with - a ``/`` will avoid this. + This option does not always work if you open non-files. Prefixing the + filename with ``./`` if it doesn't start with a ``/`` will avoid this. ``--loop-playlist=``, ``--loop-playlist`` Loops playback ``N`` times. A value of ``1`` plays it one time (default), @@ -2613,85 +2611,6 @@ Window ``never`` asks the window manager to never disable the compositor. - -Disc Devices ------------- - -``--cdrom-device=`` - Specify the CD-ROM device (default: ``/dev/cdrom``). - -``--dvd-device=`` - Specify the DVD device or .iso filename (default: ``/dev/dvd``). You can - also specify a directory that contains files previously copied directly - from a DVD (with e.g. vobcopy). - - .. admonition:: Example - - ``mpv dvd:// --dvd-device=/path/to/dvd/`` - -``--bluray-device=`` - (Blu-ray only) - Specify the Blu-ray disc location. Must be a directory with Blu-ray - structure. - - .. admonition:: Example - - ``mpv bd:// --bluray-device=/path/to/bd/`` - -``--cdda-...`` - These options can be used to tune the CD Audio reading feature of mpv. - -``--cdda-speed=`` - Set CD spin speed. - -``--cdda-paranoia=<0-2>`` - Set paranoia level. Values other than 0 seem to break playback of - anything but the first track. - - :0: disable checking (default) - :1: overlap checking only - :2: full data correction and verification - -``--cdda-sector-size=`` - Set atomic read size. - -``--cdda-overlap=`` - Force minimum overlap search during verification to sectors. - -``--cdda-toc-bias`` - Assume that the beginning offset of track 1 as reported in the TOC - will be addressed as LBA 0. Some discs need this for getting track - boundaries correctly. - -``--cdda-toc-offset=`` - Add ```` sectors to the values reported when addressing tracks. - May be negative. - -``--cdda-skip=`` - (Never) accept imperfect data reconstruction. - -``--cdda-cdtext=`` - Print CD text. This is disabled by default, because it ruins performance - with CD-ROM drives for unknown reasons. - -``--dvd-speed=`` - Try to limit DVD speed (default: 0, no change). DVD base speed is 1385 - kB/s, so an 8x drive can read at speeds up to 11080 kB/s. Slower speeds - make the drive more quiet. For watching DVDs, 2700 kB/s should be quiet and - fast enough. mpv resets the speed to the drive default value on close. - Values of at least 100 mean speed in kB/s. Values less than 100 mean - multiples of 1385 kB/s, i.e. ``--dvd-speed=8`` selects 11080 kB/s. - - .. note:: - - You need write access to the DVD device to change the speed. - -``--dvd-angle=`` - Some DVDs contain scenes that can be viewed from multiple angles. - This option tells mpv which angle to use (default: 1). - - - Equalizer --------- @@ -3085,8 +3004,7 @@ Input ``--input-cursor``, ``--no-input-cursor`` Permit mpv to receive pointer events reported by the video output - driver. Necessary to use the OSC, or to select the buttons in DVD menus. - Support depends on the VO in use. + driver. Necessary to use the OSC. Support depends on the VO in use. ``--input-media-keys=`` (OS X and Windows only) @@ -3648,191 +3566,6 @@ Terminal ``--msg-time`` Prepend timing information to each console message. - -TV --- - -``--tv-...`` - These options tune various properties of the TV capture module. For - watching TV with mpv, use ``tv://`` or ``tv://`` or - even ``tv://`` (see option ``tv-channels`` for ``channel_name`` - below) as a media URL. You can also use ``tv:///`` to start - watching a video from a composite or S-Video input (see option ``input`` for - details). - -``--tv-device=`` - Specify TV device (default: ``/dev/video0``). - -``--tv-channel=`` - Set tuner to channel. - -``--no-tv-audio`` - no sound - -``--tv-automute=<0-255> (v4l and v4l2 only)`` - If signal strength reported by device is less than this value, audio - and video will be muted. In most cases automute=100 will be enough. - Default is 0 (automute disabled). - -``--tv-driver=`` - See ``--tv=driver=help`` for a list of compiled-in TV input drivers. - available: dummy, v4l2 (default: autodetect) - -``--tv-input=`` - Specify input (default: 0 (TV), see console output for available - inputs). - -``--tv-freq=`` - Specify the frequency to set the tuner to (e.g. 511.250). Not - compatible with the channels parameter. - -``--tv-outfmt=`` - Specify the output format of the tuner with a preset value supported - by the V4L driver (YV12, UYVY, YUY2, I420) or an arbitrary format given - as hex value. - -``--tv-width=`` - output window width - -``--tv-height=`` - output window height - -``--tv-fps=`` - framerate at which to capture video (frames per second) - -``--tv-buffersize=`` - maximum size of the capture buffer in megabytes (default: dynamical) - -``--tv-norm=`` - See the console output for a list of all available norms. - - See also: ``--tv-normid``. - -``--tv-normid= (v4l2 only)`` - Sets the TV norm to the given numeric ID. The TV norm depends on the - capture card. See the console output for a list of available TV norms. - -``--tv-chanlist=`` - available: argentina, australia, china-bcast, europe-east, - europe-west, france, ireland, italy, japan-bcast, japan-cable, - newzealand, russia, southafrica, us-bcast, us-cable, us-cable-hrc - -``--tv-channels=-[=],-[=],...`` - Set names for channels. - - .. note:: - - If is an integer greater than 1000, it will be treated as - frequency (in kHz) rather than channel name from frequency table. - Use _ for spaces in names (or play with quoting ;-) ). The channel - names will then be written using OSD, and the input commands - ``tv_step_channel``, ``tv_set_channel`` and ``tv_last_channel`` - will be usable for a remote control. Not compatible with - the ``frequency`` parameter. - - .. note:: - - The channel number will then be the position in the 'channels' - list, beginning with 1. - - .. admonition:: Examples - - ``tv://1``, ``tv://TV1``, ``tv_set_channel 1``, - ``tv_set_channel TV1`` - -``--tv-[brightness|contrast|hue|saturation]=<-100-100>`` - Set the image equalizer on the card. - -``--tv-audiorate=`` - Set input audio sample rate. - -``--tv-forceaudio`` - Capture audio even if there are no audio sources reported by v4l. - -``--tv-alsa`` - Capture from ALSA. - -``--tv-amode=<0-3>`` - Choose an audio mode: - - :0: mono - :1: stereo - :2: language 1 - :3: language 2 - -``--tv-forcechan=<1-2>`` - By default, the count of recorded audio channels is determined - automatically by querying the audio mode from the TV card. This option - allows forcing stereo/mono recording regardless of the amode option - and the values returned by v4l. This can be used for troubleshooting - when the TV card is unable to report the current audio mode. - -``--tv-adevice=`` - Set an audio device. should be ``/dev/xxx`` for OSS and a - hardware ID for ALSA. You must replace any ':' by a '.' in the - hardware ID for ALSA. - -``--tv-audioid=`` - Choose an audio output of the capture card, if it has more than one. - -``--tv-[volume|bass|treble|balance]=<0-100>`` - These options set parameters of the mixer on the video capture card. - They will have no effect, if your card does not have one. For v4l2 50 - maps to the default value of the control, as reported by the driver. - -``--tv-gain=<0-100>`` - Set gain control for video devices (usually webcams) to the desired - value and switch off automatic control. A value of 0 enables automatic - control. If this option is omitted, gain control will not be modified. - -``--tv-immediatemode=`` - A value of 0 means capture and buffer audio and video together. A - value of 1 (default) means to do video capture only and let the audio - go through a loopback cable from the TV card to the sound card. - -``--tv-mjpeg`` - Use hardware MJPEG compression (if the card supports it). When using - this option, you do not need to specify the width and height of the - output window, because mpv will determine it automatically from - the decimation value (see below). - -``--tv-decimation=<1|2|4>`` - choose the size of the picture that will be compressed by hardware - MJPEG compression: - - :1: full size - - - 704x576 PAL - - 704x480 NTSC - - :2: medium size - - - 352x288 PAL - - 352x240 NTSC - - :4: small size - - - 176x144 PAL - - 176x120 NTSC - -``--tv-quality=<0-100>`` - Choose the quality of the JPEG compression (< 60 recommended for full - size). - -``--tv-scan-autostart`` - Begin channel scanning immediately after startup (default: disabled). - -``--tv-scan-period=<0.1-2.0>`` - Specify delay in seconds before switching to next channel (default: - 0.5). Lower values will cause faster scanning, but can detect inactive - TV channels as active. - -``--tv-scan-threshold=<1-100>`` - Threshold value for the signal strength (in percent), as reported by - the device (default: 50). A signal strength higher than this value will - indicate that the currently scanning channel is active. - - Cache ----- @@ -3978,45 +3711,6 @@ Network The bitrate as used is sent by the server, and there's no guarantee it's actually meaningful. -DVB ---- - -``--dvbin-card=<1-4>`` - Specifies using card number 1-4 (default: 1). - -``--dvbin-file=`` - Instructs mpv to read the channels list from ````. The default is - in the mpv configuration directory (usually ``~/.config/mpv``) with the - filename ``channels.conf.{sat,ter,cbl,atsc}`` (based on your card type) or - ``channels.conf`` as a last resort. - For DVB-S/2 cards, a VDR 1.7.x format channel list is recommended - as it allows tuning to DVB-S2 channels, enabling subtitles and - decoding the PMT (which largely improves the demuxing). - Classic mplayer format channel lists are still supported (without - these improvements), and for other card types, only limited VDR - format channel list support is implemented (patches welcome). - For channels with dynamic PID switching or incomplete - ``channels.conf``, ``--dvbin-full-transponder`` or the magic PID - ``8192`` are recommended. - -``--dvbin-timeout=<1-30>`` - Maximum number of seconds to wait when trying to tune a frequency before - giving up (default: 30). - -``--dvbin-full-transponder=`` - Apply no filters on program PIDs, only tune to frequency and pass full - transponder to demuxer. - The player frontend selects the streams from the full TS in this case, - so the program which is shown initially may not match the chosen channel. - Switching between the programs is possible by cycling the ``program`` - property. - This is useful to record multiple programs on a single transponder, - or to work around issues in the ``channels.conf``. - It is also recommended to use this for channels which switch PIDs - on-the-fly, e.g. for regional news. - - Default: ``no`` - ALSA audio output options ------------------------- diff --git a/demux/demux.c b/demux/demux.c index 45f472cfc9..c963f2f917 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -49,12 +49,10 @@ extern const struct demuxer_desc demuxer_desc_edl; extern const struct demuxer_desc demuxer_desc_cue; extern const demuxer_desc_t demuxer_desc_rawaudio; extern const demuxer_desc_t demuxer_desc_rawvideo; -extern const demuxer_desc_t demuxer_desc_tv; extern const demuxer_desc_t demuxer_desc_mf; extern const demuxer_desc_t demuxer_desc_matroska; extern const demuxer_desc_t demuxer_desc_lavf; extern const demuxer_desc_t demuxer_desc_playlist; -extern const demuxer_desc_t demuxer_desc_disc; extern const demuxer_desc_t demuxer_desc_rar; extern const demuxer_desc_t demuxer_desc_libarchive; extern const demuxer_desc_t demuxer_desc_null; @@ -65,19 +63,14 @@ extern const demuxer_desc_t demuxer_desc_timeline; * libraries and demuxers requiring binary support. */ const demuxer_desc_t *const demuxer_list[] = { - &demuxer_desc_disc, &demuxer_desc_edl, &demuxer_desc_cue, &demuxer_desc_rawaudio, &demuxer_desc_rawvideo, -#if HAVE_TV - &demuxer_desc_tv, -#endif &demuxer_desc_matroska, #if HAVE_LIBARCHIVE &demuxer_desc_libarchive, #endif - &demuxer_desc_rar, &demuxer_desc_lavf, &demuxer_desc_mf, &demuxer_desc_playlist, @@ -2309,7 +2302,6 @@ static struct demuxer *open_given_type(struct mpv_global *global, .access_references = opts->access_references, .events = DEMUX_EVENT_ALL, .duration = -1, - .extended_ctrls = stream->extended_ctrls, }; demuxer->seekable = stream->seekable; diff --git a/demux/demux.h b/demux/demux.h index 5b92e97f49..a7f4483418 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -32,8 +32,6 @@ enum demux_ctrl { DEMUXER_CTRL_SWITCHED_TRACKS = 1, - DEMUXER_CTRL_RESYNC, - DEMUXER_CTRL_IDENTIFY_PROGRAM, DEMUXER_CTRL_STREAM_CTRL, DEMUXER_CTRL_GET_READER_STATE, DEMUXER_CTRL_GET_BITRATE_STATS, // double[STREAM_TYPE_COUNT] @@ -201,7 +199,6 @@ typedef struct demuxer { bool fully_read; bool is_network; // opened directly from a network stream bool access_references; // allow opening other files/URLs - bool extended_ctrls; // supports some of BD/DVD/DVB/TV controls // Bitmask of DEMUX_EVENT_* int events; @@ -243,11 +240,6 @@ typedef struct demuxer { struct stream *stream; } demuxer_t; -typedef struct { - int progid; //program id - int aid, vid, sid; //audio, video and subtitle id -} demux_program_t; - void demux_free(struct demuxer *demuxer); void demux_cancel_and_free(struct demuxer *demuxer); diff --git a/demux/demux_disc.c b/demux/demux_disc.c deleted file mode 100644 index e5c63cea17..0000000000 --- a/demux/demux_disc.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * mpv 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with mpv. If not, see . - */ - -#include -#include -#include - -#include "common/common.h" -#include "common/msg.h" - -#include "stream/stream.h" -#include "video/mp_image.h" -#include "demux.h" -#include "stheader.h" - -#include "video/csputils.h" - -struct priv { - struct demuxer *slave; - // streams[slave_stream_index] == our_stream - struct sh_stream **streams; - int num_streams; - // This contains each DVD sub stream, or NULL. Needed because DVD packets - // can come arbitrarily late in the MPEG stream, so the slave demuxer - // might add the streams only later. - struct sh_stream *dvd_subs[32]; - // Used to rewrite the raw MPEG timestamps to playback time. - double base_time; // playback display start time of current segment - double base_dts; // packet DTS that maps to base_time - double last_dts; // DTS of previously demuxed packet - bool seek_reinit; // needs reinit after seek - - bool is_dvd, is_cdda; -}; - -// If the timestamp difference between subsequent packets is this big, assume -// a reset. It should be big enough to account for 1. low video framerates and -// large audio frames, and 2. bad interleaving. -#define DTS_RESET_THRESHOLD 5.0 - -static void reselect_streams(demuxer_t *demuxer) -{ - struct priv *p = demuxer->priv; - int num_slave = demux_get_num_stream(p->slave); - for (int n = 0; n < MPMIN(num_slave, p->num_streams); n++) { - if (p->streams[n]) { - demuxer_select_track(p->slave, demux_get_stream(p->slave, n), - MP_NOPTS_VALUE, demux_stream_is_selected(p->streams[n])); - } - } -} - -static void get_disc_lang(struct stream *stream, struct sh_stream *sh, bool dvd) -{ - struct stream_lang_req req = {.type = sh->type, .id = sh->demuxer_id}; - if (dvd && sh->type == STREAM_SUB) - req.id = req.id & 0x1F; // mpeg ID to index - stream_control(stream, STREAM_CTRL_GET_LANG, &req); - if (req.name[0]) - sh->lang = talloc_strdup(sh, req.name); -} - -static void add_dvd_streams(demuxer_t *demuxer) -{ - struct priv *p = demuxer->priv; - struct stream *stream = demuxer->stream; - if (!p->is_dvd) - return; - struct stream_dvd_info_req info; - if (stream_control(stream, STREAM_CTRL_GET_DVD_INFO, &info) > 0) { - for (int n = 0; n < MPMIN(32, info.num_subs); n++) { - struct sh_stream *sh = demux_alloc_sh_stream(STREAM_SUB); - sh->demuxer_id = n + 0x20; - sh->codec->codec = "dvd_subtitle"; - get_disc_lang(stream, sh, true); - // p->streams _must_ match with p->slave->streams, so we can't add - // it yet - it has to be done when the real stream appears, which - // could be right on start, or any time later. - p->dvd_subs[n] = sh; - - // emulate the extradata - struct mp_csp_params csp = MP_CSP_PARAMS_DEFAULTS; - struct mp_cmat cmatrix; - mp_get_csp_matrix(&csp, &cmatrix); - - char *s = talloc_strdup(sh, ""); - s = talloc_asprintf_append(s, "palette: "); - for (int i = 0; i < 16; i++) { - int color = info.palette[i]; - int y[3] = {(color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff}; - int c[3]; - mp_map_fixp_color(&cmatrix, 8, y, 8, c); - color = (c[2] << 16) | (c[1] << 8) | c[0]; - - if (i != 0) - s = talloc_asprintf_append(s, ", "); - s = talloc_asprintf_append(s, "%06x", color); - } - s = talloc_asprintf_append(s, "\n"); - - sh->codec->extradata = s; - sh->codec->extradata_size = strlen(s); - - demux_add_sh_stream(demuxer, sh); - } - } -} - -static void add_streams(demuxer_t *demuxer) -{ - struct priv *p = demuxer->priv; - - for (int n = p->num_streams; n < demux_get_num_stream(p->slave); n++) { - struct sh_stream *src = demux_get_stream(p->slave, n); - if (src->type == STREAM_SUB) { - struct sh_stream *sub = NULL; - if (src->demuxer_id >= 0x20 && src->demuxer_id <= 0x3F) - sub = p->dvd_subs[src->demuxer_id - 0x20]; - if (sub) { - assert(p->num_streams == n); // directly mapped - MP_TARRAY_APPEND(p, p->streams, p->num_streams, sub); - continue; - } - } - struct sh_stream *sh = demux_alloc_sh_stream(src->type); - assert(p->num_streams == n); // directly mapped - MP_TARRAY_APPEND(p, p->streams, p->num_streams, sh); - // Copy all stream fields that might be relevant - *sh->codec = *src->codec; - sh->demuxer_id = src->demuxer_id; - if (src->type == STREAM_VIDEO) { - double ar; - if (stream_control(demuxer->stream, STREAM_CTRL_GET_ASPECT_RATIO, &ar) - == STREAM_OK) - { - struct mp_image_params f = {.w = src->codec->disp_w, - .h = src->codec->disp_h}; - mp_image_params_set_dsize(&f, 1728 * ar, 1728); - sh->codec->par_w = f.p_w; - sh->codec->par_h = f.p_h; - } - } - get_disc_lang(demuxer->stream, sh, p->is_dvd); - demux_add_sh_stream(demuxer, sh); - } - reselect_streams(demuxer); -} - -static void d_seek(demuxer_t *demuxer, double seek_pts, int flags) -{ - struct priv *p = demuxer->priv; - - if (p->is_cdda) { - demux_seek(p->slave, seek_pts, flags); - return; - } - - if (flags & SEEK_FACTOR) { - double tmp = 0; - stream_control(demuxer->stream, STREAM_CTRL_GET_TIME_LENGTH, &tmp); - seek_pts *= tmp; - } - - MP_VERBOSE(demuxer, "seek to: %f\n", seek_pts); - - double seek_arg[] = {seek_pts, flags}; - stream_control(demuxer->stream, STREAM_CTRL_SEEK_TO_TIME, seek_arg); - demux_control(p->slave, DEMUXER_CTRL_RESYNC, NULL); - - p->seek_reinit = true; -} - -static void reset_pts(demuxer_t *demuxer) -{ - struct priv *p = demuxer->priv; - - double base; - if (stream_control(demuxer->stream, STREAM_CTRL_GET_CURRENT_TIME, &base) < 1) - base = 0; - - MP_VERBOSE(demuxer, "reset to time: %f\n", base); - - p->base_dts = p->last_dts = MP_NOPTS_VALUE; - p->base_time = base; - p->seek_reinit = false; -} - -static int d_fill_buffer(demuxer_t *demuxer) -{ - struct priv *p = demuxer->priv; - - struct demux_packet *pkt = demux_read_any_packet(p->slave); - if (!pkt) - return 0; - - demux_update(p->slave); - - if (p->seek_reinit) - reset_pts(demuxer); - - add_streams(demuxer); - if (pkt->stream >= p->num_streams) { // out of memory? - talloc_free(pkt); - return 0; - } - - struct sh_stream *sh = p->streams[pkt->stream]; - if (!demux_stream_is_selected(sh)) { - talloc_free(pkt); - return 1; - } - - if (p->is_cdda) { - demux_add_packet(sh, pkt); - return 1; - } - - MP_TRACE(demuxer, "ipts: %d %f %f\n", sh->type, pkt->pts, pkt->dts); - - if (sh->type == STREAM_SUB) { - if (p->base_dts == MP_NOPTS_VALUE) - MP_WARN(demuxer, "subtitle packet along PTS reset\n"); - } else if (pkt->dts != MP_NOPTS_VALUE) { - // Use the very first DTS to rebase the start time of the MPEG stream - // to the playback time. - if (p->base_dts == MP_NOPTS_VALUE) - p->base_dts = pkt->dts; - - if (p->last_dts == MP_NOPTS_VALUE) - p->last_dts = pkt->dts; - - if (fabs(p->last_dts - pkt->dts) >= DTS_RESET_THRESHOLD) { - MP_WARN(demuxer, "PTS discontinuity: %f->%f\n", p->last_dts, pkt->dts); - p->base_time += p->last_dts - p->base_dts; - p->base_dts = pkt->dts - pkt->duration; - } - p->last_dts = pkt->dts; - } - - if (p->base_dts != MP_NOPTS_VALUE) { - double delta = -p->base_dts + p->base_time; - if (pkt->pts != MP_NOPTS_VALUE) - pkt->pts += delta; - if (pkt->dts != MP_NOPTS_VALUE) - pkt->dts += delta; - } - - MP_TRACE(demuxer, "opts: %d %f %f\n", sh->type, pkt->pts, pkt->dts); - - demux_add_packet(sh, pkt); - return 1; -} - -static void add_stream_chapters(struct demuxer *demuxer) -{ - int num = 0; - if (stream_control(demuxer->stream, STREAM_CTRL_GET_NUM_CHAPTERS, &num) < 1) - return; - for (int n = 0; n < num; n++) { - double p = n; - if (stream_control(demuxer->stream, STREAM_CTRL_GET_CHAPTER_TIME, &p) < 1) - continue; - demuxer_add_chapter(demuxer, "", p, 0); - } -} - -static int d_open(demuxer_t *demuxer, enum demux_check check) -{ - struct priv *p = demuxer->priv = talloc_zero(demuxer, struct priv); - - if (check != DEMUX_CHECK_FORCE) - return -1; - - struct demuxer_params params = { - .force_format = "+lavf", - .does_not_own_stream = true, - }; - - struct stream *cur = demuxer->stream; - const char *sname = ""; - if (cur->info) - sname = cur->info->name; - - p->is_cdda = strcmp(sname, "cdda") == 0; - p->is_dvd = strcmp(sname, "dvd") == 0 || - strcmp(sname, "ifo") == 0 || - strcmp(sname, "dvdnav") == 0 || - strcmp(sname, "ifo_dvdnav") == 0; - - if (p->is_cdda) - params.force_format = "+rawaudio"; - - char *t = NULL; - stream_control(demuxer->stream, STREAM_CTRL_GET_DISC_NAME, &t); - if (t) { - mp_tags_set_str(demuxer->metadata, "TITLE", t); - talloc_free(t); - } - - // Initialize the playback time. We need to read _some_ data to get the - // correct stream-layer time (at least with libdvdnav). - stream_peek(demuxer->stream, 1); - reset_pts(demuxer); - - p->slave = demux_open(demuxer->stream, ¶ms, demuxer->global); - if (!p->slave) - return -1; - - // So that we don't miss initial packets of delayed subtitle streams. - demux_set_stream_autoselect(p->slave, true); - - // With cache enabled, the stream can be seekable. This causes demux_lavf.c - // (actually libavformat/mpegts.c) to seek sometimes when reading a packet. - // It does this to seek back a bit in case the current file position points - // into the middle of a packet. - if (!p->is_cdda) { - demuxer->stream->seekable = false; - - // Can be seekable even if the stream isn't. - demuxer->seekable = true; - } - - add_dvd_streams(demuxer); - add_streams(demuxer); - add_stream_chapters(demuxer); - - double len; - if (stream_control(demuxer->stream, STREAM_CTRL_GET_TIME_LENGTH, &len) >= 1) - demuxer->duration = len; - - demuxer->extended_ctrls = true; - - return 0; -} - -static void d_close(demuxer_t *demuxer) -{ - struct priv *p = demuxer->priv; - demux_free(p->slave); -} - -static int d_control(demuxer_t *demuxer, int cmd, void *arg) -{ - struct priv *p = demuxer->priv; - - switch (cmd) { - case DEMUXER_CTRL_RESYNC: - demux_flush(p->slave); - break; // relay to slave demuxer - case DEMUXER_CTRL_SWITCHED_TRACKS: - reselect_streams(demuxer); - return CONTROL_OK; - } - return demux_control(p->slave, cmd, arg); -} - -const demuxer_desc_t demuxer_desc_disc = { - .name = "disc", - .desc = "CD/DVD/BD wrapper", - .fill_buffer = d_fill_buffer, - .open = d_open, - .close = d_close, - .seek = d_seek, - .control = d_control, -}; diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 333d707028..e217c1b4d5 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -204,7 +204,6 @@ typedef struct lavf_priv { AVIOContext *pb; struct sh_stream **streams; // NULL for unknown streams int num_streams; - int cur_program; char *mime_type; double seek_delay; @@ -1080,79 +1079,8 @@ static int demux_lavf_control(demuxer_t *demuxer, int cmd, void *arg) switch (cmd) { case DEMUXER_CTRL_SWITCHED_TRACKS: - { select_tracks(demuxer, 0); return CONTROL_OK; - } - case DEMUXER_CTRL_IDENTIFY_PROGRAM: - { - demux_program_t *prog = arg; - AVProgram *program; - int p, i; - int start; - - add_new_streams(demuxer); - - prog->vid = prog->aid = prog->sid = -2; - if (priv->avfc->nb_programs < 1) - return CONTROL_FALSE; - - if (prog->progid == -1) { - p = 0; - while (p < priv->avfc->nb_programs && priv->avfc->programs[p]->id != priv->cur_program) - p++; - p = (p + 1) % priv->avfc->nb_programs; - } else { - for (i = 0; i < priv->avfc->nb_programs; i++) - if (priv->avfc->programs[i]->id == prog->progid) - break; - if (i == priv->avfc->nb_programs) - return CONTROL_FALSE; - p = i; - } - start = p; -redo: - prog->vid = prog->aid = prog->sid = -2; - program = priv->avfc->programs[p]; - for (i = 0; i < program->nb_stream_indexes; i++) { - struct sh_stream *stream = priv->streams[program->stream_index[i]]; - if (stream) { - switch (stream->type) { - case STREAM_VIDEO: - if (prog->vid == -2) - prog->vid = stream->demuxer_id; - break; - case STREAM_AUDIO: - if (prog->aid == -2) - prog->aid = stream->demuxer_id; - break; - case STREAM_SUB: - if (prog->sid == -2) - prog->sid = stream->demuxer_id; - break; - } - } - } - if (prog->progid == -1 && prog->vid == -2 && prog->aid == -2) { - p = (p + 1) % priv->avfc->nb_programs; - if (p == start) - return CONTROL_FALSE; - goto redo; - } - priv->cur_program = prog->progid = program->id; - - mp_tags_copy_from_av_dictionary(demuxer->metadata, priv->avfc->programs[p]->metadata); - update_metadata(demuxer); - // Enforce metadata update even if no explicit METADATA_UPDATED since we switched program. - demux_metadata_changed(demuxer); - - return CONTROL_OK; - } - case DEMUXER_CTRL_RESYNC: - stream_drop_buffers(priv->stream); - avio_flush(priv->avfc->pb); - avformat_flush(priv->avfc); - return CONTROL_OK; case DEMUXER_CTRL_REPLACE_STREAM: if (priv->own_stream) free_stream(priv->stream); diff --git a/demux/demux_rar.c b/demux/demux_rar.c deleted file mode 100644 index 7d9adfc28a..0000000000 --- a/demux/demux_rar.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * mpv 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with mpv. If not, see . - */ - -#include "common/common.h" -#include "common/playlist.h" -#include "stream/stream.h" -#include "stream/rar.h" -#include "demux.h" - -static int open_file(struct demuxer *demuxer, enum demux_check check) -{ - if (!demuxer->access_references) - return -1; - - if (RarProbe(demuxer->stream)) - return -1; - - int count; - rar_file_t **files; - if (RarParse(demuxer->stream, &count, &files)) - return -1; - - void *tmp = talloc_new(NULL); - talloc_steal(tmp, files); - - struct playlist *pl = talloc_zero(demuxer, struct playlist); - demuxer->playlist = pl; - - // make it load rar:// - pl->disable_safety = true; - - char *prefix = mp_url_escape(tmp, demuxer->stream->url, "~|"); - for (int n = 0; n < count; n++) { - // stream_rar.c does the real work - playlist_add_file(pl, - talloc_asprintf(tmp, "rar://%s|%s", prefix, files[n]->name)); - RarFileDelete(files[n]); - } - - demuxer->filetype = "rar"; - demuxer->fully_read = true; - - talloc_free(tmp); - return 0; -} - -const struct demuxer_desc demuxer_desc_rar = { - .name = "rar", - .desc = "Rar archive file", - .open = open_file, -}; diff --git a/demux/demux_tv.c b/demux/demux_tv.c deleted file mode 100644 index 79cff5d79d..0000000000 --- a/demux/demux_tv.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (C) 2001 Alex Beregszaszi - * - * Feb 19, 2002: Significant rewrites by Charles R. Henrich (henrich@msu.edu) - * to add support for audio, and bktr *BSD support. - * - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include - -#include "common/common.h" -#include "common/msg.h" - -#include "options/m_option.h" -#include "options/m_config.h" -#include "options/options.h" - -#include "demux.h" -#include "codec_tags.h" - -#include "audio/format.h" -#include "osdep/endian.h" - -#include "stream/stream.h" -#include "stream/tv.h" - -static int demux_open_tv(demuxer_t *demuxer, enum demux_check check) -{ - tvi_handle_t *tvh; - const tvi_functions_t *funcs; - - if (check > DEMUX_CHECK_REQUEST) - return -1; - - if (!demuxer->stream->info || strcmp(demuxer->stream->info->name, "tv") != 0) - return -1; - - tv_param_t *params = mp_get_config_group(demuxer, demuxer->global, - &tv_params_conf); - bstr urlparams = bstr0(demuxer->stream->path); - bstr channel, input; - bstr_split_tok(urlparams, "/", &channel, &input); - if (channel.len) { - talloc_free(params->channel); - params->channel = bstrto0(NULL, channel); - } - if (input.len) { - bstr r; - params->input = bstrtoll(input, &r, 0); - if (r.len) { - MP_ERR(demuxer->stream, "invalid input: '%.*s'\n", BSTR_P(input)); - return -1; - } - } - - assert(demuxer->priv==NULL); - if(!(tvh=tv_begin(params, demuxer->log))) return -1; - if (!tvh->functions->init(tvh->priv)) return -1; - - tvh->demuxer = demuxer; - - if (!open_tv(tvh)){ - tv_uninit(tvh); - return -1; - } - funcs = tvh->functions; - demuxer->priv=tvh; - - struct sh_stream *sh_v = demux_alloc_sh_stream(STREAM_VIDEO); - - /* get IMAGE FORMAT */ - int fourcc; - funcs->control(tvh->priv, TVI_CONTROL_VID_GET_FORMAT, &fourcc); - if (fourcc == MP_FOURCC_MJPEG || fourcc == MP_FOURCC_JPEG) { - sh_v->codec->codec = "mjpeg"; - } else { - sh_v->codec->codec = "rawvideo"; - sh_v->codec->codec_tag = fourcc; - } - - /* set FPS and FRAMETIME */ - - if(!sh_v->codec->fps) - { - float tmp; - if (funcs->control(tvh->priv, TVI_CONTROL_VID_GET_FPS, &tmp) != TVI_CONTROL_TRUE) - sh_v->codec->fps = 25.0f; /* on PAL */ - else sh_v->codec->fps = tmp; - } - - if (tvh->tv_param->fps != -1.0f) - sh_v->codec->fps = tvh->tv_param->fps; - - /* If playback only mode, go to immediate mode, fail silently */ - if(tvh->tv_param->immediate == 1) - { - funcs->control(tvh->priv, TVI_CONTROL_IMMEDIATE, 0); - tvh->tv_param->audio = 0; - } - - /* set width */ - funcs->control(tvh->priv, TVI_CONTROL_VID_GET_WIDTH, &sh_v->codec->disp_w); - - /* set height */ - funcs->control(tvh->priv, TVI_CONTROL_VID_GET_HEIGHT, &sh_v->codec->disp_h); - - demux_add_sh_stream(demuxer, sh_v); - - demuxer->seekable = 0; - - /* here comes audio init */ - if (tvh->tv_param->audio && funcs->control(tvh->priv, TVI_CONTROL_IS_AUDIO, 0) == TVI_CONTROL_TRUE) - { - int audio_format; - - /* yeah, audio is present */ - - funcs->control(tvh->priv, TVI_CONTROL_AUD_SET_SAMPLERATE, - &tvh->tv_param->audiorate); - - if (funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_FORMAT, &audio_format) != TVI_CONTROL_TRUE) - goto no_audio; - - switch(audio_format) - { - // This is the only format any of the current inputs generate. - case AF_FORMAT_S16: - break; - default: - MP_ERR(tvh, "Audio type '%s' unsupported!\n", - af_fmt_to_str(audio_format)); - goto no_audio; - } - - struct sh_stream *sh_a = demux_alloc_sh_stream(STREAM_AUDIO); - - funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_SAMPLERATE, - &sh_a->codec->samplerate); - int nchannels = sh_a->codec->channels.num; - funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_CHANNELS, - &nchannels); - mp_chmap_from_channels(&sh_a->codec->channels, nchannels); - - // s16ne - mp_set_pcm_codec(sh_a->codec, true, false, 16, BYTE_ORDER == BIG_ENDIAN); - - demux_add_sh_stream(demuxer, sh_a); - - MP_VERBOSE(tvh, " TV audio: %d channels, %d bits, %d Hz\n", - nchannels, 16, sh_a->codec->samplerate); - } -no_audio: - - if(!(funcs->start(tvh->priv))){ - // start failed :( - tv_uninit(tvh); - return -1; - } - - /* set color eq */ - tv_set_color_options(tvh, TV_COLOR_BRIGHTNESS, tvh->tv_param->brightness); - tv_set_color_options(tvh, TV_COLOR_HUE, tvh->tv_param->hue); - tv_set_color_options(tvh, TV_COLOR_SATURATION, tvh->tv_param->saturation); - tv_set_color_options(tvh, TV_COLOR_CONTRAST, tvh->tv_param->contrast); - - if(tvh->tv_param->gain!=-1) - if(funcs->control(tvh->priv,TVI_CONTROL_VID_SET_GAIN,&tvh->tv_param->gain)!=TVI_CONTROL_TRUE) - MP_WARN(tvh, "Unable to set gain control!\n"); - - demuxer->extended_ctrls = true; - - return 0; -} - -static void demux_close_tv(demuxer_t *demuxer) -{ - tvi_handle_t *tvh=(tvi_handle_t*)(demuxer->priv); - if (!tvh) return; - tv_uninit(tvh); - free(tvh); - demuxer->priv=NULL; -} - -static int demux_tv_fill_buffer(demuxer_t *demux) -{ - tvi_handle_t *tvh=(tvi_handle_t*)(demux->priv); - demux_packet_t* dp; - unsigned int len=0; - struct sh_stream *want_audio = NULL, *want_video = NULL; - - int num_streams = demux_get_num_stream(demux); - for (int n = 0; n < num_streams; n++) { - struct sh_stream *sh = demux_get_stream(demux, n); - if (!demux_has_packet(sh) && demux_stream_is_selected(sh)) { - if (sh->type == STREAM_AUDIO) - want_audio = sh; - if (sh->type == STREAM_VIDEO) - want_video = sh; - } - } - - /* ================== ADD AUDIO PACKET =================== */ - - if (want_audio && tvh->tv_param->audio && - tvh->functions->control(tvh->priv, - TVI_CONTROL_IS_AUDIO, 0) == TVI_CONTROL_TRUE) - { - len = tvh->functions->get_audio_framesize(tvh->priv); - - dp=new_demux_packet(len); - if (dp) { - dp->keyframe = true; - dp->pts=tvh->functions->grab_audio_frame(tvh->priv, dp->buffer,len); - demux_add_packet(want_audio, dp); - } - } - - /* ================== ADD VIDEO PACKET =================== */ - - if (want_video && tvh->functions->control(tvh->priv, - TVI_CONTROL_IS_VIDEO, 0) == TVI_CONTROL_TRUE) - { - len = tvh->functions->get_video_framesize(tvh->priv); - dp=new_demux_packet(len); - if (dp) { - dp->keyframe = true; - dp->pts=tvh->functions->grab_video_frame(tvh->priv, dp->buffer, len); - demux_add_packet(want_video, dp); - } - } - - if (tvh->tv_param->scan) tv_scan(tvh); - return 1; -} - -static int demux_tv_control(demuxer_t *demuxer, int cmd, void *arg) -{ - tvi_handle_t *tvh=(tvi_handle_t*)(demuxer->priv); - if (cmd != DEMUXER_CTRL_STREAM_CTRL) - return CONTROL_UNKNOWN; - struct demux_ctrl_stream_ctrl *ctrl = arg; - ctrl->res = tv_stream_control(tvh, ctrl->ctrl, ctrl->arg); - return CONTROL_OK; -} - -const demuxer_desc_t demuxer_desc_tv = { - .name = "tv", - .desc = "TV card demuxer", - .fill_buffer = demux_tv_fill_buffer, - .control = demux_tv_control, - .open = demux_open_tv, - .close = demux_close_tv, -}; diff --git a/options/options.c b/options/options.c index 2548759ddb..44200bda98 100644 --- a/options/options.c +++ b/options/options.c @@ -55,9 +55,6 @@ static void print_version(struct mp_log *log) mp_print_version(log, true); } -extern const struct m_sub_options tv_params_conf; -extern const struct m_sub_options stream_cdda_conf; -extern const struct m_sub_options stream_dvb_conf; extern const struct m_sub_options stream_lavf_conf; extern const struct m_sub_options sws_conf; extern const struct m_sub_options drm_conf; @@ -278,22 +275,6 @@ const struct m_sub_options mp_osd_render_sub_opts = { .change_flags = UPDATE_OSD, }; -#undef OPT_BASE_STRUCT -#define OPT_BASE_STRUCT struct dvd_opts - -const struct m_sub_options dvd_conf = { - .opts = (const struct m_option[]){ - OPT_STRING("dvd-device", device, M_OPT_FILE), - OPT_INT("dvd-speed", speed, 0), - OPT_INTRANGE("dvd-angle", angle, 0, 1, 99), - {0} - }, - .size = sizeof(struct dvd_opts), - .defaults = &(const struct dvd_opts){ - .angle = 1, - }, -}; - #undef OPT_BASE_STRUCT #define OPT_BASE_STRUCT struct filter_opts @@ -386,16 +367,10 @@ const m_option_t mp_opts[] = { // ------------------------- stream options -------------------- -#if HAVE_DVDREAD || HAVE_DVDNAV - OPT_SUBSTRUCT("", dvd_opts, dvd_conf, 0), -#endif /* HAVE_DVDREAD */ OPT_INTPAIR("chapter", chapterrange, 0, .deprecation_message = "instead of " "--chapter=A-B use --start=#A --end=#B+1"), OPT_CHOICE_OR_INT("edition", edition_id, 0, 0, 8190, ({"auto", -1})), -#if HAVE_LIBBLURAY - OPT_STRING("bluray-device", bluray_device, M_OPT_FILE), -#endif /* HAVE_LIBBLURAY */ // ------------------------- demuxer options -------------------- @@ -447,11 +422,6 @@ const m_option_t mp_opts[] = { OPT_STRINGLIST("display-tags", display_tags, 0), -#if HAVE_CDDA - OPT_SUBSTRUCT("cdda", stream_cdda_opts, stream_cdda_conf, 0), - OPT_STRING("cdrom-device", cdrom_device, M_OPT_FILE), -#endif - // demuxer.c - select audio/sub file/demuxer OPT_PATHLIST("audio-files", audio_files, 0), OPT_CLI_ALIAS("audio-file", "audio-files-append"), @@ -467,12 +437,6 @@ const m_option_t mp_opts[] = { OPT_DOUBLE("mf-fps", mf_fps, 0), OPT_STRING("mf-type", mf_type, 0), -#if HAVE_TV - OPT_SUBSTRUCT("tv", tv_params, tv_params_conf, 0), -#endif /* HAVE_TV */ -#if HAVE_DVBIN - OPT_SUBSTRUCT("dvbin", stream_dvb_opts, stream_dvb_conf, 0), -#endif OPT_SUBSTRUCT("", stream_lavf_opts, stream_lavf_conf, 0), // ------------------------- a-v sync options -------------------- @@ -763,7 +727,6 @@ const m_option_t mp_opts[] = { OPT_REPLACED("cursor-autohide-delay", "cursor-autohide"), OPT_REPLACED("delay", "audio-delay"), OPT_REMOVED("dumpstream", "use --stream-dump="), - OPT_REPLACED("dvdangle", "dvd-angle"), OPT_REPLACED("endpos", "length"), OPT_REPLACED("font", "osd-font"), OPT_REPLACED("forcedsubsonly", "sub-forced-only"), diff --git a/options/options.h b/options/options.h index a6532b4458..0dc06a8f84 100644 --- a/options/options.h +++ b/options/options.h @@ -284,15 +284,8 @@ typedef struct MPOpts { int w32_priority; - struct tv_params *tv_params; - struct pvr_params *stream_pvr_opts; - struct cdda_params *stream_cdda_opts; - struct dvb_params *stream_dvb_opts; struct stream_lavf_params *stream_lavf_opts; - char *cdrom_device; - char *bluray_device; - double mf_fps; char *mf_type; diff --git a/options/parse_commandline.c b/options/parse_commandline.c index d2eb01966c..a9f7f7c533 100644 --- a/options/parse_commandline.c +++ b/options/parse_commandline.c @@ -220,41 +220,7 @@ int m_config_parse_mp_command_line(m_config_t *config, struct playlist *files, void *tmp = talloc_new(NULL); bstr file = p.arg; char *file0 = bstrdup0(tmp, p.arg); -#if HAVE_GPL - // expand DVD filename entries like dvd://1-3 into component titles - if (bstr_startswith0(file, "dvd://")) { - int offset = 6; - char *splitpos = strstr(file0 + offset, "-"); - if (splitpos != NULL) { - char *endpos; - int start_title = strtol(file0 + offset, &endpos, 10); - int end_title; - //entries like dvd://-2 imply start at title 1 - if (start_title < 0) { - end_title = abs(start_title); - start_title = 1; - } else - end_title = strtol(splitpos + 1, &endpos, 10); - - #define dvd_range(a) (a >= 0 && a < 255) - if (dvd_range(start_title) && dvd_range(end_title) - && (start_title < end_title)) { - for (int j = start_title; j <= end_title; j++) { - char *f = talloc_asprintf(tmp, "dvd://%d%s", j, - endpos); - playlist_add_file(files, f); - } - } else - MP_ERR(config, "Invalid play entry %s\n", file0); - - } else // dvd:// or dvd://x entry - playlist_add_file(files, file0); - } else { - process_non_option(files, file0); - } -#else process_non_option(files, file0); -#endif talloc_free(tmp); } } diff --git a/player/command.c b/player/command.c index ab9a09fcac..b852e19225 100644 --- a/player/command.c +++ b/player/command.c @@ -901,39 +901,6 @@ static int mp_property_playback_time(void *ctx, struct m_property *prop, return property_time(action, arg, get_playback_time(mpctx)); } -/// Current BD/DVD title (RW) -static int mp_property_disc_title(void *ctx, struct m_property *prop, - int action, void *arg) -{ - MPContext *mpctx = ctx; - struct demuxer *d = mpctx->demuxer; - if (!d || !d->extended_ctrls) - return M_PROPERTY_UNAVAILABLE; - unsigned int title = -1; - switch (action) { - case M_PROPERTY_GET: - if (demux_stream_control(d, STREAM_CTRL_GET_CURRENT_TITLE, &title) < 0) - return M_PROPERTY_UNAVAILABLE; - *(int*)arg = title; - return M_PROPERTY_OK; - case M_PROPERTY_GET_TYPE: - *(struct m_option *)arg = (struct m_option){ - .type = CONF_TYPE_INT, - .flags = M_OPT_MIN, - .min = -1, - }; - return M_PROPERTY_OK; - case M_PROPERTY_SET: - title = *(int*)arg; - if (demux_stream_control(d, STREAM_CTRL_SET_CURRENT_TITLE, &title) < 0) - return M_PROPERTY_NOT_IMPLEMENTED; - if (!mpctx->stop_play) - mpctx->stop_play = PT_CURRENT_ENTRY; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - /// Current chapter (RW) static int mp_property_chapter(void *ctx, struct m_property *prop, int action, void *arg) @@ -1216,53 +1183,6 @@ static int property_list_editions(void *ctx, struct m_property *prop, get_edition_entry, mpctx); } -/// Number of titles in BD/DVD -static int mp_property_disc_titles(void *ctx, struct m_property *prop, - int action, void *arg) -{ - MPContext *mpctx = ctx; - struct demuxer *demuxer = mpctx->demuxer; - unsigned int num_titles; - if (!demuxer || !demuxer->extended_ctrls || - demux_stream_control(demuxer, STREAM_CTRL_GET_NUM_TITLES, - &num_titles) < 1) - return M_PROPERTY_UNAVAILABLE; - return m_property_int_ro(action, arg, num_titles); -} - -static int get_disc_title_entry(int item, int action, void *arg, void *ctx) -{ - struct MPContext *mpctx = ctx; - struct demuxer *demuxer = mpctx->demuxer; - - double len = item; - if (demux_stream_control(demuxer, STREAM_CTRL_GET_TITLE_LENGTH, &len) < 1) - len = -1; - - struct m_sub_property props[] = { - {"id", SUB_PROP_INT(item)}, - {"length", {.type = CONF_TYPE_TIME}, {.time = len}, - .unavailable = len < 0}, - {0} - }; - - return m_property_read_sub(props, action, arg); -} - -static int mp_property_list_disc_titles(void *ctx, struct m_property *prop, - int action, void *arg) -{ - MPContext *mpctx = ctx; - struct demuxer *demuxer = mpctx->demuxer; - unsigned int num_titles; - if (!demuxer || !demuxer->extended_ctrls || - demux_stream_control(demuxer, STREAM_CTRL_GET_NUM_TITLES, - &num_titles) < 1) - return M_PROPERTY_UNAVAILABLE; - return m_property_read_list(action, arg, num_titles, - get_disc_title_entry, mpctx); -} - /// Number of chapters in file static int mp_property_chapters(void *ctx, struct m_property *prop, int action, void *arg) @@ -1286,67 +1206,6 @@ static int mp_property_editions(void *ctx, struct m_property *prop, return m_property_int_ro(action, arg, demuxer->num_editions); } -/// Current dvd angle (RW) -static int mp_property_angle(void *ctx, struct m_property *prop, - int action, void *arg) -{ - MPContext *mpctx = ctx; - struct demuxer *demuxer = mpctx->demuxer; - if (!demuxer || !demuxer->extended_ctrls) - return M_PROPERTY_UNAVAILABLE; - - int ris, angles = -1, angle = 1; - - ris = demux_stream_control(demuxer, STREAM_CTRL_GET_NUM_ANGLES, &angles); - if (ris == STREAM_UNSUPPORTED) - return M_PROPERTY_UNAVAILABLE; - - ris = demux_stream_control(demuxer, STREAM_CTRL_GET_ANGLE, &angle); - if (ris == STREAM_UNSUPPORTED) - return -1; - - if (angle < 0 || angles <= 1) - return M_PROPERTY_UNAVAILABLE; - - switch (action) { - case M_PROPERTY_GET: - *(int *) arg = angle; - return M_PROPERTY_OK; - case M_PROPERTY_PRINT: { - *(char **) arg = talloc_asprintf(NULL, "%d/%d", angle, angles); - return M_PROPERTY_OK; - } - case M_PROPERTY_SET: - angle = *(int *)arg; - if (angle < 0 || angle > angles) - return M_PROPERTY_ERROR; - - demux_flush(demuxer); - ris = demux_stream_control(demuxer, STREAM_CTRL_SET_ANGLE, &angle); - if (ris == STREAM_OK) { - demux_control(demuxer, DEMUXER_CTRL_RESYNC, NULL); - demux_flush(demuxer); - } - - reset_audio_state(mpctx); - reset_video_state(mpctx); - mp_wakeup_core(mpctx); - - return ris == STREAM_OK ? M_PROPERTY_OK : M_PROPERTY_ERROR; - case M_PROPERTY_GET_TYPE: { - struct m_option opt = { - .type = CONF_TYPE_INT, - .flags = CONF_RANGE, - .min = 1, - .max = angles, - }; - *(struct m_option *)arg = opt; - return M_PROPERTY_OK; - } - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - static int get_tag_entry(int item, int action, void *arg, void *ctx) { struct mp_tags *tags = ctx; @@ -2232,63 +2091,6 @@ static int mp_property_video(void *ctx, struct m_property *prop, return property_switch_track(prop, action, arg, ctx, 0, STREAM_VIDEO); } -static struct track *find_track_by_demuxer_id(MPContext *mpctx, - enum stream_type type, - int demuxer_id) -{ - for (int n = 0; n < mpctx->num_tracks; n++) { - struct track *track = mpctx->tracks[n]; - if (track->type == type && track->demuxer_id == demuxer_id) - return track; - } - return NULL; -} - -static int mp_property_program(void *ctx, struct m_property *prop, - int action, void *arg) -{ - MPContext *mpctx = ctx; - demux_program_t prog = {0}; - - struct demuxer *demuxer = mpctx->demuxer; - if (!demuxer || !mpctx->playback_initialized) - return M_PROPERTY_UNAVAILABLE; - - switch (action) { - case M_PROPERTY_SWITCH: - case M_PROPERTY_SET: - if (action == M_PROPERTY_SET && arg) - prog.progid = *((int *) arg); - else - prog.progid = -1; - if (demux_control(demuxer, DEMUXER_CTRL_IDENTIFY_PROGRAM, &prog) == - CONTROL_UNKNOWN) - return M_PROPERTY_ERROR; - - if (prog.aid < 0 && prog.vid < 0) { - MP_ERR(mpctx, "Selected program contains no audio or video streams!\n"); - return M_PROPERTY_ERROR; - } - mp_switch_track(mpctx, STREAM_VIDEO, - find_track_by_demuxer_id(mpctx, STREAM_VIDEO, prog.vid), 0); - mp_switch_track(mpctx, STREAM_AUDIO, - find_track_by_demuxer_id(mpctx, STREAM_AUDIO, prog.aid), 0); - mp_switch_track(mpctx, STREAM_SUB, - find_track_by_demuxer_id(mpctx, STREAM_VIDEO, prog.sid), 0); - print_track_list(mpctx, "Program switched:"); - return M_PROPERTY_OK; - case M_PROPERTY_GET_TYPE: - *(struct m_option *)arg = (struct m_option){ - .type = CONF_TYPE_INT, - .flags = CONF_RANGE, - .min = -1, - .max = (1 << 16) - 1, - }; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - static int mp_property_hwdec(void *ctx, struct m_property *prop, int action, void *arg) { @@ -2998,163 +2800,6 @@ static int mp_property_cursor_autohide(void *ctx, struct m_property *prop, return r; } -static int prop_stream_ctrl(struct MPContext *mpctx, int ctrl, void *arg) -{ - if (!mpctx->demuxer || !mpctx->demuxer->extended_ctrls) - return M_PROPERTY_UNAVAILABLE; - int r = demux_stream_control(mpctx->demuxer, ctrl, arg); - switch (r) { - case STREAM_OK: return M_PROPERTY_OK; - case STREAM_UNSUPPORTED: return M_PROPERTY_UNAVAILABLE; - default: return M_PROPERTY_ERROR; - } -} - -static int mp_property_tv_norm(void *ctx, struct m_property *prop, - int action, void *arg) -{ - switch (action) { - case M_PROPERTY_SET: - return prop_stream_ctrl(ctx, STREAM_CTRL_TV_SET_NORM, *(char **)arg); - case M_PROPERTY_SWITCH: - return prop_stream_ctrl(ctx, STREAM_CTRL_TV_STEP_NORM, NULL); - case M_PROPERTY_GET_TYPE: - *(struct m_option *)arg = (struct m_option){.type = CONF_TYPE_STRING}; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -static int mp_property_tv_scan(void *ctx, struct m_property *prop, - int action, void *arg) -{ - switch (action) { - case M_PROPERTY_SET: - return prop_stream_ctrl(ctx, STREAM_CTRL_TV_SET_SCAN, arg); - case M_PROPERTY_GET_TYPE: - *(struct m_option *)arg = (struct m_option){.type = CONF_TYPE_FLAG}; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -/// TV color settings (RW) -static int mp_property_tv_color(void *ctx, struct m_property *prop, - int action, void *arg) -{ - int req[2] = {(intptr_t)prop->priv}; - switch (action) { - case M_PROPERTY_SET: - req[1] = *(int *)arg; - return prop_stream_ctrl(ctx, STREAM_CTRL_SET_TV_COLORS, req); - case M_PROPERTY_GET: { - int r = prop_stream_ctrl(ctx, STREAM_CTRL_GET_TV_COLORS, req); - if (r == M_PROPERTY_OK) - *(int *)arg = req[1]; - return r; - } - case M_PROPERTY_GET_TYPE: - *(struct m_option *)arg = (struct m_option){ - .type = CONF_TYPE_INT, - .flags = M_OPT_RANGE, - .min = -100, - .max = 100, - }; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -static int mp_property_tv_freq(void *ctx, struct m_property *prop, - int action, void *arg) -{ - switch (action) { - case M_PROPERTY_SET: - return prop_stream_ctrl(ctx, STREAM_CTRL_SET_TV_FREQ, arg); - case M_PROPERTY_GET: - return prop_stream_ctrl(ctx, STREAM_CTRL_GET_TV_FREQ, arg); - case M_PROPERTY_GET_TYPE: - *(struct m_option *)arg = (struct m_option){.type = CONF_TYPE_FLOAT}; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -static int mp_property_tv_channel(void *ctx, struct m_property *prop, - int action, void *arg) -{ - switch (action) { - case M_PROPERTY_GET_TYPE: - *(struct m_option *)arg = (struct m_option){.type = CONF_TYPE_STRING}; - return M_PROPERTY_OK; - case M_PROPERTY_SET: - return prop_stream_ctrl(ctx, STREAM_CTRL_TV_SET_CHAN, *(char **)arg); - case M_PROPERTY_GET: - return prop_stream_ctrl(ctx, STREAM_CTRL_TV_GET_CHAN, arg); - case M_PROPERTY_SWITCH: { - struct m_property_switch_arg *sa = arg; - int dir = sa->inc >= 0 ? 1 : -1; - return prop_stream_ctrl(ctx, STREAM_CTRL_TV_STEP_CHAN, &dir); - } - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -static int mp_property_dvb_channel(void *ctx, struct m_property *prop, - int action, void *arg) -{ - MPContext *mpctx = ctx; - int r; - switch (action) { - case M_PROPERTY_SET: - r = prop_stream_ctrl(mpctx, STREAM_CTRL_DVB_SET_CHANNEL, arg); - if (r == M_PROPERTY_OK && !mpctx->stop_play) - mpctx->stop_play = PT_CURRENT_ENTRY; - return r; - case M_PROPERTY_SWITCH: { - struct m_property_switch_arg *sa = arg; - int dir = sa->inc >= 0 ? 1 : -1; - r = prop_stream_ctrl(mpctx, STREAM_CTRL_DVB_STEP_CHANNEL, &dir); - if (r == M_PROPERTY_OK && !mpctx->stop_play) - mpctx->stop_play = PT_CURRENT_ENTRY; - return r; - } - case M_PROPERTY_GET_TYPE: - *(struct m_option *)arg = (struct m_option){.type = &m_option_type_intpair}; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -static int mp_property_dvb_channel_name(void *ctx, struct m_property *prop, - int action, void *arg) -{ - MPContext *mpctx = ctx; - int r; - switch (action) { - case M_PROPERTY_SET: - r = prop_stream_ctrl(mpctx, STREAM_CTRL_DVB_SET_CHANNEL_NAME, arg); - if (r == M_PROPERTY_OK && !mpctx->stop_play) - mpctx->stop_play = PT_CURRENT_ENTRY; - return r; - case M_PROPERTY_SWITCH: { - struct m_property_switch_arg *sa = arg; - int dir = sa->inc >= 0 ? 1 : -1; - r = prop_stream_ctrl(mpctx, STREAM_CTRL_DVB_STEP_CHANNEL, &dir); - if (r == M_PROPERTY_OK && !mpctx->stop_play) - mpctx->stop_play = PT_CURRENT_ENTRY; - return r; - } - case M_PROPERTY_GET: { - return prop_stream_ctrl(mpctx, STREAM_CTRL_DVB_GET_CHANNEL_NAME, arg); - } - case M_PROPERTY_GET_TYPE: - *(struct m_option *)arg = (struct m_option){.type = CONF_TYPE_STRING}; - return M_PROPERTY_OK; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - static int mp_property_playlist_pos_x(void *ctx, struct m_property *prop, int action, void *arg, int base) { @@ -3752,13 +3397,10 @@ static const struct m_property mp_properties_base[] = { {"audio-pts", mp_property_audio_pts}, {"playtime-remaining", mp_property_playtime_remaining}, {"playback-time", mp_property_playback_time}, - {"disc-title", mp_property_disc_title}, {"chapter", mp_property_chapter}, {"edition", mp_property_edition}, - {"disc-titles", mp_property_disc_titles}, {"chapters", mp_property_chapters}, {"editions", mp_property_editions}, - {"angle", mp_property_angle}, {"metadata", mp_property_metadata}, {"filtered-metadata", mp_property_filtered_metadata}, {"chapter-metadata", mp_property_chapter_metadata}, @@ -3785,7 +3427,6 @@ static const struct m_property mp_properties_base[] = { {"chapter-list", mp_property_list_chapters}, {"track-list", property_list_tracks}, {"edition-list", property_list_editions}, - {"disc-title-list", mp_property_list_disc_titles}, {"playlist", mp_property_playlist}, {"playlist-pos", mp_property_playlist_pos}, @@ -3832,7 +3473,6 @@ static const struct m_property mp_properties_base[] = { {"estimated-vf-fps", mp_property_vf_fps}, {"video-aspect", mp_property_aspect}, {"vid", mp_property_video}, - {"program", mp_property_program}, {"hwdec", mp_property_hwdec}, {"hwdec-current", mp_property_hwdec_current}, {"hwdec-interop", mp_property_hwdec_interop}, @@ -3871,19 +3511,6 @@ static const struct m_property mp_properties_base[] = { PROPERTY_BITRATE("audio-bitrate", false, STREAM_AUDIO), PROPERTY_BITRATE("sub-bitrate", false, STREAM_SUB), -#define PROPERTY_TV_COLOR(name, type) \ - {name, mp_property_tv_color, (void *)(intptr_t)type} - PROPERTY_TV_COLOR("tv-brightness", TV_COLOR_BRIGHTNESS), - PROPERTY_TV_COLOR("tv-contrast", TV_COLOR_CONTRAST), - PROPERTY_TV_COLOR("tv-saturation", TV_COLOR_SATURATION), - PROPERTY_TV_COLOR("tv-hue", TV_COLOR_HUE), - {"tv-freq", mp_property_tv_freq}, - {"tv-norm", mp_property_tv_norm}, - {"tv-scan", mp_property_tv_scan}, - {"tv-channel", mp_property_tv_channel}, - {"dvb-channel", mp_property_dvb_channel}, - {"dvb-channel-name", mp_property_dvb_channel_name}, - {"cursor-autohide", mp_property_cursor_autohide}, {"window-minimized", mp_property_win_minimized}, @@ -5379,19 +5006,6 @@ static void cmd_show_progress(void *p) mp_wakeup_core(mpctx); } -static void cmd_tv_last_channel(void *p) -{ - struct mp_cmd_ctx *cmd = p; - struct MPContext *mpctx = cmd->mpctx; - - if (!mpctx->demuxer || !mpctx->demuxer->extended_ctrls) { - cmd->success = false; - return; - } - - demux_stream_control(mpctx->demuxer, STREAM_CTRL_TV_LAST_CHAN, NULL); -} - static void cmd_track_add(void *p) { struct mp_cmd_ctx *cmd = p; @@ -6026,8 +5640,6 @@ const struct mp_cmd_def mp_cmds[] = { .abort_on_playback_end = true, }, - { "tv-last-channel", cmd_tv_last_channel, }, - { "screenshot", cmd_screenshot, { OPT_FLAGS("flags", v.i, 0, diff --git a/player/configfiles.c b/player/configfiles.c index 8a7e6d7111..6657693ec5 100644 --- a/player/configfiles.c +++ b/player/configfiles.c @@ -174,11 +174,6 @@ static char *mp_get_playback_resume_config_filename(struct MPContext *mpctx, realpath = mp_path_join(tmp, cwd, fname); } } - if (bstr_startswith0(bfname, "dvd://") && opts->dvd_opts && opts->dvd_opts->device) - realpath = talloc_asprintf(tmp, "%s - %s", realpath, opts->dvd_opts->device); - if ((bstr_startswith0(bfname, "br://") || bstr_startswith0(bfname, "bd://") || - bstr_startswith0(bfname, "bluray://")) && opts->bluray_device) - realpath = talloc_asprintf(tmp, "%s - %s", realpath, opts->bluray_device); uint8_t md5[16]; av_md5_sum(md5, realpath, strlen(realpath)); char *conf = talloc_strdup(tmp, ""); diff --git a/stream/ai_alsa1x.c b/stream/ai_alsa1x.c deleted file mode 100644 index 8f2b774faf..0000000000 --- a/stream/ai_alsa1x.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include -#include -#include - -#include "config.h" - -#include -#include "audio_in.h" -#include "common/msg.h" - -int ai_alsa_setup(audio_in_t *ai) -{ - snd_pcm_hw_params_t *params; - snd_pcm_sw_params_t *swparams; - snd_pcm_uframes_t buffer_size, period_size; - int err; - int dir; - unsigned int rate; - - snd_pcm_hw_params_alloca(¶ms); - snd_pcm_sw_params_alloca(&swparams); - - err = snd_pcm_hw_params_any(ai->alsa.handle, params); - if (err < 0) { - MP_ERR(ai, "Broken configuration for this PCM: no configurations available.\n"); - return -1; - } - - err = snd_pcm_hw_params_set_access(ai->alsa.handle, params, - SND_PCM_ACCESS_RW_INTERLEAVED); - if (err < 0) { - MP_ERR(ai, "Access type not available.\n"); - return -1; - } - - err = snd_pcm_hw_params_set_format(ai->alsa.handle, params, SND_PCM_FORMAT_S16); - if (err < 0) { - MP_ERR(ai, "Sample format not available.\n"); - return -1; - } - - err = snd_pcm_hw_params_set_channels(ai->alsa.handle, params, ai->req_channels); - if (err < 0) { - snd_pcm_hw_params_get_channels(params, &ai->channels); - MP_ERR(ai, "Channel count not available - reverting to default: %d\n", - ai->channels); - } else { - ai->channels = ai->req_channels; - } - - dir = 0; - rate = ai->req_samplerate; - err = snd_pcm_hw_params_set_rate_near(ai->alsa.handle, params, &rate, &dir); - if (err < 0) { - MP_ERR(ai, "Cannot set samplerate.\n"); - } - ai->samplerate = rate; - - dir = 0; - ai->alsa.buffer_time = 1000000; - err = snd_pcm_hw_params_set_buffer_time_near(ai->alsa.handle, params, - &ai->alsa.buffer_time, &dir); - if (err < 0) { - MP_ERR(ai, "Cannot set buffer time.\n"); - } - - dir = 0; - ai->alsa.period_time = ai->alsa.buffer_time / 4; - err = snd_pcm_hw_params_set_period_time_near(ai->alsa.handle, params, - &ai->alsa.period_time, &dir); - if (err < 0) { - MP_ERR(ai, "Cannot set period time.\n"); - } - - err = snd_pcm_hw_params(ai->alsa.handle, params); - if (err < 0) { - MP_ERR(ai, "Unable to install hardware parameters: %s", snd_strerror(err)); - snd_pcm_hw_params_dump(params, ai->alsa.log); - return -1; - } - - dir = -1; - snd_pcm_hw_params_get_period_size(params, &period_size, &dir); - snd_pcm_hw_params_get_buffer_size(params, &buffer_size); - ai->alsa.chunk_size = period_size; - if (period_size == buffer_size) { - MP_ERR(ai, "Can't use period equal to buffer size (%u == %lu)\n", ai->alsa.chunk_size, (long)buffer_size); - return -1; - } - - snd_pcm_sw_params_current(ai->alsa.handle, swparams); - err = snd_pcm_sw_params_set_avail_min(ai->alsa.handle, swparams, ai->alsa.chunk_size); - - err = snd_pcm_sw_params_set_start_threshold(ai->alsa.handle, swparams, 0); - err = snd_pcm_sw_params_set_stop_threshold(ai->alsa.handle, swparams, buffer_size); - - if (snd_pcm_sw_params(ai->alsa.handle, swparams) < 0) { - MP_ERR(ai, "Unable to install software parameters:\n"); - snd_pcm_sw_params_dump(swparams, ai->alsa.log); - return -1; - } - - if (mp_msg_test(ai->log, MSGL_V)) { - snd_pcm_dump(ai->alsa.handle, ai->alsa.log); - } - - ai->alsa.bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16); - ai->alsa.bits_per_frame = ai->alsa.bits_per_sample * ai->channels; - ai->blocksize = ai->alsa.chunk_size * ai->alsa.bits_per_frame / 8; - ai->samplesize = ai->alsa.bits_per_sample; - ai->bytes_per_sample = ai->alsa.bits_per_sample/8; - - return 0; -} - -int ai_alsa_init(audio_in_t *ai) -{ - int err; - - const char *device = ai->alsa.device; - if (!device) - device = "default"; - - err = snd_pcm_open(&ai->alsa.handle, device, SND_PCM_STREAM_CAPTURE, 0); - if (err < 0) { - MP_ERR(ai, "Error opening audio: %s\n", snd_strerror(err)); - return -1; - } - - err = snd_output_stdio_attach(&ai->alsa.log, stderr, 0); - - if (err < 0) { - return -1; - } - - err = ai_alsa_setup(ai); - - return err; -} - -#ifndef timersub -#define timersub(a, b, result) \ -do { \ - (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((result)->tv_usec < 0) { \ - --(result)->tv_sec; \ - (result)->tv_usec += 1000000; \ - } \ -} while (0) -#endif - -int ai_alsa_xrun(audio_in_t *ai) -{ - snd_pcm_status_t *status; - int res; - - snd_pcm_status_alloca(&status); - if ((res = snd_pcm_status(ai->alsa.handle, status))<0) { - MP_ERR(ai, "ALSA status error: %s", snd_strerror(res)); - return -1; - } - if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { - struct timeval now, diff, tstamp; - gettimeofday(&now, 0); - snd_pcm_status_get_trigger_tstamp(status, &tstamp); - timersub(&now, &tstamp, &diff); - MP_ERR(ai, "ALSA xrun!!! (at least %.3f ms long)\n", - diff.tv_sec * 1000 + diff.tv_usec / 1000.0); - if (mp_msg_test(ai->log, MSGL_V)) { - MP_ERR(ai, "ALSA Status:\n"); - snd_pcm_status_dump(status, ai->alsa.log); - } - if ((res = snd_pcm_prepare(ai->alsa.handle))<0) { - MP_ERR(ai, "ALSA xrun: prepare error: %s", snd_strerror(res)); - return -1; - } - return 0; /* ok, data should be accepted again */ - } - MP_ERR(ai, "ALSA read/write error"); - return -1; -} diff --git a/stream/ai_oss.c b/stream/ai_oss.c deleted file mode 100644 index bc22691be5..0000000000 --- a/stream/ai_oss.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include -#include - -#include "config.h" - -#include -#include -#include -#include - -#include - -#include "osdep/io.h" - -#include "audio_in.h" -#include "common/common.h" -#include "common/msg.h" - -int ai_oss_set_samplerate(audio_in_t *ai) -{ - int tmp = ai->req_samplerate; - if (ioctl(ai->oss.audio_fd, SNDCTL_DSP_SPEED, &tmp) == -1) return -1; - ai->samplerate = tmp; - return 0; -} - -int ai_oss_set_channels(audio_in_t *ai) -{ - int err; - int ioctl_param; - - if (ai->req_channels > 2) - { - ioctl_param = ai->req_channels; - MP_VERBOSE(ai, "ioctl dsp channels: %d\n", - err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_CHANNELS, &ioctl_param)); - if (err < 0) { - MP_ERR(ai, "Unable to set channel count: %d\n", - ai->req_channels); - return -1; - } - ai->channels = ioctl_param; - } - else - { - ioctl_param = (ai->req_channels == 2); - MP_VERBOSE(ai, "ioctl dsp stereo: %d (req: %d)\n", - err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_STEREO, &ioctl_param), - ioctl_param); - if (err < 0) { - MP_ERR(ai, "Unable to set stereo: %d\n", - ai->req_channels == 2); - return -1; - } - ai->channels = ioctl_param ? 2 : 1; - } - return 0; -} - -int ai_oss_init(audio_in_t *ai) -{ - int err; - int ioctl_param; - - const char *device = ai->oss.device; - if (!device) - device = "/dev/dsp"; - - ai->oss.audio_fd = open(device, O_RDONLY | O_CLOEXEC); - if (ai->oss.audio_fd < 0) - { - MP_ERR(ai, "Unable to open '%s': %s\n", device, mp_strerror(errno)); - return -1; - } - - ioctl_param = 0 ; - MP_VERBOSE(ai, "ioctl dsp getfmt: %d\n", - ioctl(ai->oss.audio_fd, SNDCTL_DSP_GETFMTS, &ioctl_param)); - - MP_VERBOSE(ai, "Supported formats: %x\n", ioctl_param); - if (!(ioctl_param & AFMT_S16_NE)) - MP_ERR(ai, "unsupported format\n"); - - ioctl_param = AFMT_S16_NE; - MP_VERBOSE(ai, "ioctl dsp setfmt: %d\n", - err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_SETFMT, &ioctl_param)); - if (err < 0) { - MP_ERR(ai, "Unable to set audio format."); - return -1; - } - - if (ai_oss_set_channels(ai) < 0) return -1; - - ioctl_param = ai->req_samplerate; - MP_VERBOSE(ai, "ioctl dsp speed: %d\n", - err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_SPEED, &ioctl_param)); - if (err < 0) { - MP_ERR(ai, "Unable to set samplerate: %d\n", - ai->req_samplerate); - return -1; - } - ai->samplerate = ioctl_param; - - MP_VERBOSE(ai, "ioctl dsp trigger: %d\n", - ioctl(ai->oss.audio_fd, SNDCTL_DSP_GETTRIGGER, &ioctl_param)); - MP_VERBOSE(ai, "trigger: %x\n", ioctl_param); - ioctl_param = PCM_ENABLE_INPUT; - MP_VERBOSE(ai, "ioctl dsp trigger: %d\n", - err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_SETTRIGGER, &ioctl_param)); - if (err < 0) { - MP_ERR(ai, "Unable to set trigger: %d\n", - PCM_ENABLE_INPUT); - } - - ai->blocksize = 0; - MP_VERBOSE(ai, "ioctl dsp getblocksize: %d\n", - err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_GETBLKSIZE, &ai->blocksize)); - if (err < 0) { - MP_ERR(ai, "Unable to get block size!\n"); - } - MP_VERBOSE(ai, "blocksize: %d\n", ai->blocksize); - - // correct the blocksize to a reasonable value - if (ai->blocksize <= 0) { - ai->blocksize = 4096*ai->channels*2; - MP_ERR(ai, "Audio block size is zero, setting to %d!\n", ai->blocksize); - } else if (ai->blocksize < 4096*ai->channels*2) { - ai->blocksize *= 4096*ai->channels*2/ai->blocksize; - MP_ERR(ai, "Audio block size too low, setting to %d!\n", ai->blocksize); - } - - ai->samplesize = 16; - ai->bytes_per_sample = 2; - - return 0; -} diff --git a/stream/ai_sndio.c b/stream/ai_sndio.c deleted file mode 100644 index 10e95cea62..0000000000 --- a/stream/ai_sndio.c +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include - -#include "config.h" - -#include -#include "audio_in.h" -#include "common/msg.h" - -int ai_sndio_setup(audio_in_t *ai) -{ - struct sio_par par; - - sio_initpar(&par); - - par.bits = 16; - par.sig = 1; - par.le = SIO_LE_NATIVE; - par.rchan = ai->req_channels; - par.rate = ai->req_samplerate; - par.appbufsz = ai->req_samplerate; /* 1 sec */ - - if (!sio_setpar(ai->sndio.hdl, &par) || !sio_getpar(ai->sndio.hdl, &par)) { - MP_ERR(ai, "could not configure sndio audio"); - return -1; - } - - ai->channels = par.rchan; - ai->samplerate = par.rate; - ai->samplesize = par.bits; - ai->bytes_per_sample = par.bps; - ai->blocksize = par.round * par.bps; - - return 0; -} - -int ai_sndio_init(audio_in_t *ai) -{ - int err; - - const char *device = ai->sndio.device; - if (!device) - device = "default"; - if ((ai->sndio.hdl = sio_open(device, SIO_REC, 0)) == NULL) { - MP_ERR(ai, "could not open sndio audio"); - return -1; - } - - err = ai_sndio_setup(ai); - - return err; -} diff --git a/stream/audio_in.c b/stream/audio_in.c deleted file mode 100644 index 8ed92767c1..0000000000 --- a/stream/audio_in.c +++ /dev/null @@ -1,298 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include -#include -#include - -#include "config.h" - -#include "audio_in.h" -#include "common/common.h" -#include "common/msg.h" -#include -#include - -// sanitizes ai structure before calling other functions -int audio_in_init(audio_in_t *ai, struct mp_log *log, int type) -{ - ai->type = type; - ai->setup = 0; - ai->log = log; - - ai->channels = -1; - ai->samplerate = -1; - ai->blocksize = -1; - ai->bytes_per_sample = -1; - ai->samplesize = -1; - - switch (ai->type) { -#if HAVE_ALSA - case AUDIO_IN_ALSA: - ai->alsa.handle = NULL; - ai->alsa.log = NULL; - ai->alsa.device = NULL; - return 0; -#endif -#if HAVE_OSS_AUDIO - case AUDIO_IN_OSS: - ai->oss.audio_fd = -1; - ai->oss.device = NULL; - return 0; -#endif -#if HAVE_SNDIO - case AUDIO_IN_SNDIO: - ai->sndio.hdl = NULL; - ai->sndio.device = NULL; - return 0; -#endif - default: - return -1; - } -} - -int audio_in_setup(audio_in_t *ai) -{ - - switch (ai->type) { -#if HAVE_ALSA - case AUDIO_IN_ALSA: - if (ai_alsa_init(ai) < 0) return -1; - ai->setup = 1; - return 0; -#endif -#if HAVE_OSS_AUDIO - case AUDIO_IN_OSS: - if (ai_oss_init(ai) < 0) return -1; - ai->setup = 1; - return 0; -#endif -#if HAVE_SNDIO - case AUDIO_IN_SNDIO: - if (ai_sndio_init(ai) < 0) return -1; - ai->setup = 1; - return 0; -#endif - default: - return -1; - } -} - -int audio_in_set_samplerate(audio_in_t *ai, int rate) -{ - switch (ai->type) { -#if HAVE_ALSA - case AUDIO_IN_ALSA: - ai->req_samplerate = rate; - if (!ai->setup) return 0; - if (ai_alsa_setup(ai) < 0) return -1; - return ai->samplerate; -#endif -#if HAVE_OSS_AUDIO - case AUDIO_IN_OSS: - ai->req_samplerate = rate; - if (!ai->setup) return 0; - if (ai_oss_set_samplerate(ai) < 0) return -1; - return ai->samplerate; -#endif -#if HAVE_SNDIO - case AUDIO_IN_SNDIO: - ai->req_samplerate = rate; - if (!ai->setup) return 0; - if (ai_sndio_setup(ai) < 0) return -1; - return ai->samplerate; -#endif - default: - return -1; - } -} - -int audio_in_set_channels(audio_in_t *ai, int channels) -{ - switch (ai->type) { -#if HAVE_ALSA - case AUDIO_IN_ALSA: - ai->req_channels = channels; - if (!ai->setup) return 0; - if (ai_alsa_setup(ai) < 0) return -1; - return ai->channels; -#endif -#if HAVE_OSS_AUDIO - case AUDIO_IN_OSS: - ai->req_channels = channels; - if (!ai->setup) return 0; - if (ai_oss_set_channels(ai) < 0) return -1; - return ai->channels; -#endif -#if HAVE_SNDIO - case AUDIO_IN_SNDIO: - ai->req_channels = channels; - if (!ai->setup) return 0; - if (ai_sndio_setup(ai) < 0) return -1; - return ai->channels; -#endif - default: - return -1; - } -} - -int audio_in_set_device(audio_in_t *ai, char *device) -{ -#if HAVE_ALSA - int i; -#endif - if (ai->setup) return -1; - switch (ai->type) { -#if HAVE_ALSA - case AUDIO_IN_ALSA: - free(ai->alsa.device); - ai->alsa.device = strdup(device); - if (ai->alsa.device) { - /* mplayer could not handle colons in arguments */ - for (i = 0; i < (int)strlen(ai->alsa.device); i++) { - if (ai->alsa.device[i] == '.') ai->alsa.device[i] = ':'; - } - } - return 0; -#endif -#if HAVE_OSS_AUDIO - case AUDIO_IN_OSS: - free(ai->oss.device); - ai->oss.device = strdup(device); - return 0; -#endif -#if HAVE_SNDIO - case AUDIO_IN_SNDIO: - if (ai->sndio.device) free(ai->sndio.device); - ai->sndio.device = strdup(device); - return 0; -#endif - default: - return -1; - } -} - -int audio_in_uninit(audio_in_t *ai) -{ - if (ai->setup) { - switch (ai->type) { -#if HAVE_ALSA - case AUDIO_IN_ALSA: - if (ai->alsa.log) - snd_output_close(ai->alsa.log); - if (ai->alsa.handle) { - snd_pcm_close(ai->alsa.handle); - } - ai->setup = 0; - return 0; -#endif -#if HAVE_OSS_AUDIO - case AUDIO_IN_OSS: - close(ai->oss.audio_fd); - ai->setup = 0; - return 0; -#endif -#if HAVE_SNDIO - case AUDIO_IN_SNDIO: - if (ai->sndio.hdl) - sio_close(ai->sndio.hdl); - ai->setup = 0; - return 0; -#endif - } - } - return -1; -} - -int audio_in_start_capture(audio_in_t *ai) -{ - switch (ai->type) { -#if HAVE_ALSA - case AUDIO_IN_ALSA: - return snd_pcm_start(ai->alsa.handle); -#endif -#if HAVE_OSS_AUDIO - case AUDIO_IN_OSS: - return 0; -#endif -#if HAVE_SNDIO - case AUDIO_IN_SNDIO: - if (!sio_start(ai->sndio.hdl)) - return -1; - return 0; -#endif - default: - return -1; - } -} - -int audio_in_read_chunk(audio_in_t *ai, unsigned char *buffer) -{ - int ret; - - switch (ai->type) { -#if HAVE_ALSA - case AUDIO_IN_ALSA: - ret = snd_pcm_readi(ai->alsa.handle, buffer, ai->alsa.chunk_size); - if (ret != ai->alsa.chunk_size) { - if (ret < 0) { - MP_ERR(ai, "\nError reading audio: %s\n", snd_strerror(ret)); - if (ret == -EPIPE) { - if (ai_alsa_xrun(ai) == 0) { - MP_ERR(ai, "Recovered from cross-run, some frames may be left out!\n"); - } else { - MP_ERR(ai, "Fatal error, cannot recover!\n"); - } - } - } else { - MP_ERR(ai, "\nNot enough audio samples!\n"); - } - return -1; - } - return ret; -#endif -#if HAVE_OSS_AUDIO - case AUDIO_IN_OSS: - ret = read(ai->oss.audio_fd, buffer, ai->blocksize); - if (ret != ai->blocksize) { - if (ret < 0) { - MP_ERR(ai, "\nError reading audio: %s\n", mp_strerror(errno)); - - } else { - MP_ERR(ai, "\nNot enough audio samples!\n"); - } - return -1; - } - return ret; -#endif -#if HAVE_SNDIO - case AUDIO_IN_SNDIO: - ret = sio_read(ai->sndio.hdl, buffer, ai->blocksize); - if (ret != ai->blocksize) { - if (ret < 0) { - MP_ERR(ai, "\nError reading audio: %s\n", mp_strerror(errno)); - } else { - MP_ERR(ai, "\nNot enough audio samples!\n"); - } - return -1; - } - return ret; -#endif - default: - return -1; - } -} diff --git a/stream/audio_in.h b/stream/audio_in.h deleted file mode 100644 index 6b714f7306..0000000000 --- a/stream/audio_in.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#ifndef MPLAYER_AUDIO_IN_H -#define MPLAYER_AUDIO_IN_H - -#define AUDIO_IN_ALSA 1 -#define AUDIO_IN_OSS 2 -#define AUDIO_IN_SNDIO 3 - -#include "config.h" - -#if !HAVE_GPL -#error GPL only -#endif - -struct mp_log; - -#if HAVE_ALSA -#include - -typedef struct { - char *device; - - snd_pcm_t *handle; - snd_output_t *log; - int buffer_time, period_time, chunk_size; - size_t bits_per_sample, bits_per_frame; -} ai_alsa_t; -#endif - -#if HAVE_OSS_AUDIO -typedef struct { - char *device; - - int audio_fd; -} ai_oss_t; -#endif - -#if HAVE_SNDIO -#include - -typedef struct { - char *device; - - struct sio_hdl *hdl; -} ai_sndio_t; -#endif - -typedef struct -{ - struct mp_log *log; - int type; - int setup; - - /* requested values */ - int req_channels; - int req_samplerate; - - /* real values read-only */ - int channels; - int samplerate; - int blocksize; - int bytes_per_sample; - int samplesize; - -#if HAVE_ALSA - ai_alsa_t alsa; -#endif -#if HAVE_OSS_AUDIO - ai_oss_t oss; -#endif -#if HAVE_SNDIO - ai_sndio_t sndio; -#endif -} audio_in_t; - -int audio_in_init(audio_in_t *ai, struct mp_log *log, int type); -int audio_in_setup(audio_in_t *ai); -int audio_in_set_device(audio_in_t *ai, char *device); -int audio_in_set_samplerate(audio_in_t *ai, int rate); -int audio_in_set_channels(audio_in_t *ai, int channels); -int audio_in_uninit(audio_in_t *ai); -int audio_in_start_capture(audio_in_t *ai); -int audio_in_read_chunk(audio_in_t *ai, unsigned char *buffer); - -#if HAVE_ALSA -int ai_alsa_setup(audio_in_t *ai); -int ai_alsa_init(audio_in_t *ai); -int ai_alsa_xrun(audio_in_t *ai); -#endif - -#if HAVE_OSS_AUDIO -int ai_oss_set_samplerate(audio_in_t *ai); -int ai_oss_set_channels(audio_in_t *ai); -int ai_oss_init(audio_in_t *ai); -#endif - -#if HAVE_SNDIO -int ai_sndio_setup(audio_in_t *ai); -int ai_sndio_init(audio_in_t *ai); -#endif - -#endif /* MPLAYER_AUDIO_IN_H */ diff --git a/stream/dvb_tune.c b/stream/dvb_tune.c deleted file mode 100644 index d9b350f876..0000000000 --- a/stream/dvb_tune.c +++ /dev/null @@ -1,809 +0,0 @@ -/* dvbtune - tune.c - - Copyright (C) Dave Chapman 2001,2002 - Copyright (C) Rozhuk Ivan 2016 - 2017 - - Modified for use with MPlayer, for details see the changelog at - http://svn.mplayerhq.hu/mplayer/trunk/ - $Id$ - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - Or, point your browser to http://www.gnu.org/copyleft/gpl.html - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "osdep/io.h" -#include "dvbin.h" -#include "dvb_tune.h" -#include "common/msg.h" - -/* Keep in sync with enum fe_delivery_system. */ -static const char *dvb_delsys_str[] = { - "UNDEFINED", - "DVB-C ANNEX A", - "DVB-C ANNEX B", - "DVB-T", - "DSS", - "DVB-S", - "DVB-S2", - "DVB-H", - "ISDBT", - "ISDBS", - "ISDBC", - "ATSC", - "ATSCMH", - "DTMB", - "CMMB", - "DAB", - "DVB-T2", - "TURBO", - "DVB-C ANNEX C", - NULL -}; - -const char *get_dvb_delsys(unsigned int delsys) -{ - if (SYS_DVB__COUNT__ <= delsys) - return dvb_delsys_str[0]; - return dvb_delsys_str[delsys]; -} - -unsigned int dvb_get_tuner_delsys_mask(int fe_fd, struct mp_log *log) -{ - unsigned int ret_mask = 0, delsys; - struct dtv_property prop[1]; - struct dtv_properties cmdseq = {.num = 1, .props = prop}; - struct dvb_frontend_info fe_info; - -#ifdef DVB_USE_S2API - /* S2API is the DVB API new since 2.6.28. - It allows to query frontends with multiple delivery systems. */ - mp_verbose(log, "Querying tuner frontend type via DVBv5 API for frontend FD %d\n", - fe_fd); - prop[0].cmd = DTV_ENUM_DELSYS; - if (ioctl(fe_fd, FE_GET_PROPERTY, &cmdseq) < 0) { - mp_err(log, "DVBv5: FE_GET_PROPERTY(DTV_ENUM_DELSYS) error: %d, FD: %d\n\n", errno, fe_fd); - goto old_api; - } - unsigned int i, delsys_count = prop[0].u.buffer.len; - mp_verbose(log, "DVBv5: Number of supported delivery systems: %d\n", delsys_count); - if (delsys_count == 0) { - mp_err(log, "DVBv5: Frontend FD %d returned no delivery systems!\n", fe_fd); - goto old_api; - } - for (i = 0; i < delsys_count; i++) { - delsys = (unsigned int)prop[0].u.buffer.data[i]; - DELSYS_SET(ret_mask, delsys); - mp_verbose(log, "DVBv5: Tuner frontend type seems to be %s\n", get_dvb_delsys(delsys)); - } - - return ret_mask; - -old_api: -#endif - mp_verbose(log, "Querying tuner frontend type via pre-DVBv5 API for frontend FD %d\n", - fe_fd); - - memset(&fe_info, 0x00, sizeof(struct dvb_frontend_info)); - if (ioctl(fe_fd, FE_GET_INFO, &fe_info) < 0) { - mp_err(log, "DVBv3: FE_GET_INFO error: %d, FD: %d\n\n", errno, fe_fd); - return ret_mask; - } - /* Try to get kernel DVB API version. */ - prop[0].cmd = DTV_API_VERSION; - if (ioctl(fe_fd, FE_GET_PROPERTY, &cmdseq) < 0) { - prop[0].u.data = 0x0300; /* Fail, assume 3.0 */ - } - - mp_verbose(log, "DVBv3: Queried tuner frontend type of device named '%s', FD: %d\n", - fe_info.name, fe_fd); - switch (fe_info.type) { - case FE_OFDM: - DELSYS_SET(ret_mask, SYS_DVBT); - if (prop[0].u.data < 0x0500) - break; - if (FE_CAN_2G_MODULATION & fe_info.caps) { - DELSYS_SET(ret_mask, SYS_DVBT2); - } - break; - case FE_QPSK: - DELSYS_SET(ret_mask, SYS_DVBS); - if (prop[0].u.data < 0x0500) - break; - if (FE_CAN_2G_MODULATION & fe_info.caps) { - DELSYS_SET(ret_mask, SYS_DVBS2); - } -#if 0 /* Not used now. */ - if (FE_CAN_TURBO_FEC & fe_info.caps) { - DELSYS_SET(ret_mask, SYS_TURBO); - } -#endif - break; - case FE_QAM: - DELSYS_SET(ret_mask, SYS_DVBC_ANNEX_A); - DELSYS_SET(ret_mask, SYS_DVBC_ANNEX_C); - break; -#ifdef DVB_ATSC - case FE_ATSC: - if ((FE_CAN_8VSB | FE_CAN_16VSB) & fe_info.caps) { - DELSYS_SET(ret_mask, SYS_ATSC); - } - if ((FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO) & fe_info.caps) { - DELSYS_SET(ret_mask, SYS_DVBC_ANNEX_B); - } - break; -#endif - default: - mp_err(log, "DVBv3: Unknown tuner frontend type: %d\n", fe_info.type); - return ret_mask; - } - - for (delsys = 0; delsys < SYS_DVB__COUNT__; delsys ++) { - if (!DELSYS_IS_SET(ret_mask, delsys)) - continue; /* Skip unsupported. */ - mp_verbose(log, "DVBv3: Tuner frontend type seems to be %s\n", get_dvb_delsys(delsys)); - } - - return ret_mask; -} - -int dvb_open_devices(dvb_priv_t *priv, unsigned int adapter, - unsigned int frontend, unsigned int demux_cnt) -{ - unsigned int i; - char frontend_dev[PATH_MAX], dvr_dev[PATH_MAX], demux_dev[PATH_MAX]; - dvb_state_t* state = priv->state; - - snprintf(frontend_dev, sizeof(frontend_dev), "/dev/dvb/adapter%u/frontend%u", adapter, frontend); - snprintf(dvr_dev, sizeof(dvr_dev), "/dev/dvb/adapter%u/dvr0", adapter); - snprintf(demux_dev, sizeof(demux_dev), "/dev/dvb/adapter%u/demux0", adapter); - MP_VERBOSE(priv, "DVB_OPEN_DEVICES: frontend: %s\n", frontend_dev); - state->fe_fd = open(frontend_dev, O_RDWR | O_NONBLOCK | O_CLOEXEC); - if (state->fe_fd < 0) { - MP_ERR(priv, "ERROR OPENING FRONTEND DEVICE %s: ERRNO %d\n", - frontend_dev, errno); - return 0; - } - state->demux_fds_cnt = 0; - MP_VERBOSE(priv, "DVB_OPEN_DEVICES(%d)\n", demux_cnt); - for (i = 0; i < demux_cnt; i++) { - state->demux_fds[i] = open(demux_dev, O_RDWR | O_NONBLOCK | O_CLOEXEC); - if (state->demux_fds[i] < 0) { - MP_ERR(priv, "ERROR OPENING DEMUX 0: %d\n", errno); - return 0; - } else { - MP_VERBOSE(priv, "OPEN(%d), file %s: FD=%d, CNT=%d\n", i, demux_dev, - state->demux_fds[i], state->demux_fds_cnt); - state->demux_fds_cnt++; - } - } - - state->dvr_fd = open(dvr_dev, O_RDONLY | O_NONBLOCK | O_CLOEXEC); - if (state->dvr_fd < 0) { - MP_ERR(priv, "ERROR OPENING DVR DEVICE %s: %d\n", dvr_dev, errno); - return 0; - } - - return 1; -} - - -int dvb_fix_demuxes(dvb_priv_t *priv, unsigned int cnt) -{ - int i; - char demux_dev[PATH_MAX]; - - dvb_state_t* state = priv->state; - - snprintf(demux_dev, sizeof(demux_dev), "/dev/dvb/adapter%d/demux0", - state->adapters[state->cur_adapter].devno); - MP_VERBOSE(priv, "FIX %d -> %d\n", state->demux_fds_cnt, cnt); - if (state->demux_fds_cnt >= cnt) { - for (i = state->demux_fds_cnt - 1; i >= (int)cnt; i--) { - MP_VERBOSE(priv, "FIX, CLOSE fd(%d): %d\n", i, state->demux_fds[i]); - close(state->demux_fds[i]); - } - state->demux_fds_cnt = cnt; - } else { - for (i = state->demux_fds_cnt; i < cnt; i++) { - state->demux_fds[i] = open(demux_dev, - O_RDWR | O_NONBLOCK | O_CLOEXEC); - MP_VERBOSE(priv, "FIX, OPEN fd(%d): %d\n", i, state->demux_fds[i]); - if (state->demux_fds[i] < 0) { - MP_ERR(priv, "ERROR OPENING DEMUX 0: %d\n", errno); - return 0; - } else - state->demux_fds_cnt++; - } - } - - return 1; -} - -int dvb_set_ts_filt(dvb_priv_t *priv, int fd, uint16_t pid, - dmx_pes_type_t pestype) -{ - int i; - struct dmx_pes_filter_params pesFilterParams; - - pesFilterParams.pid = pid; - pesFilterParams.input = DMX_IN_FRONTEND; - pesFilterParams.output = DMX_OUT_TS_TAP; - pesFilterParams.pes_type = pestype; - pesFilterParams.flags = DMX_IMMEDIATE_START; - - { - int buffersize = 256 * 1024; - if (ioctl(fd, DMX_SET_BUFFER_SIZE, buffersize) < 0) - MP_ERR(priv, "ERROR IN DMX_SET_BUFFER_SIZE %i for fd %d: ERRNO: %d\n", - pid, fd, errno); - } - - errno = 0; - if ((i = ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams)) < 0) { - MP_ERR(priv, "ERROR IN SETTING DMX_FILTER %i for fd %d: ERRNO: %d\n", - pid, fd, errno); - return 0; - } - - MP_VERBOSE(priv, "SET PES FILTER ON PID %d to fd %d, RESULT: %d, ERRNO: %d\n", - pid, fd, i, errno); - return 1; -} - -int dvb_get_pmt_pid(dvb_priv_t *priv, int devno, int service_id) -{ - /* We need special filters on the demux, - so open one locally, and close also here. */ - char demux_dev[PATH_MAX]; - snprintf(demux_dev, sizeof(demux_dev), "/dev/dvb/adapter%d/demux0", devno); - - struct dmx_sct_filter_params fparams; - - memset(&fparams, 0x00, sizeof(fparams)); - fparams.pid = 0; - fparams.filter.filter[0] = 0x00; - fparams.filter.mask[0] = 0xff; - fparams.timeout = 0; - fparams.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC; - - int pat_fd; - if ((pat_fd = open(demux_dev, O_RDWR)) < 0) { - MP_ERR(priv, "Opening PAT DEMUX failed, error: %d", errno); - return -1; - } - - if (ioctl(pat_fd, DMX_SET_FILTER, &fparams) < 0) { - MP_ERR(priv, "ioctl DMX_SET_FILTER failed, error: %d", errno); - close(pat_fd); - return -1; - } - - int bytes_read; - int section_length; - unsigned char buft[4096]; - unsigned char *bufptr = buft; - - int pmt_pid = -1; - - bool pat_read = false; - while (!pat_read) { - if (((bytes_read = - read(pat_fd, bufptr, - sizeof(buft))) < 0) && errno == EOVERFLOW) - bytes_read = read(pat_fd, bufptr, sizeof(buft)); - if (bytes_read < 0) { - MP_ERR(priv, "PAT: read_sections: read error: %d", errno); - close(pat_fd); - return -1; - } - - section_length = ((bufptr[1] & 0x0f) << 8) | bufptr[2]; - if (bytes_read != section_length + 3) - continue; - - bufptr += 8; - section_length -= 8; - - /* assumes one section contains the whole pat */ - pat_read = true; - while (section_length > 0) { - int this_service_id = (bufptr[0] << 8) | bufptr[1]; - if (this_service_id == service_id) { - pmt_pid = ((bufptr[2] & 0x1f) << 8) | bufptr[3]; - section_length = 0; - } - bufptr += 4; - section_length -= 4; - } - } - close(pat_fd); - - return pmt_pid; -} - -static void print_status(dvb_priv_t *priv, fe_status_t festatus) -{ - MP_VERBOSE(priv, "FE_STATUS:"); - if (festatus & FE_HAS_SIGNAL) - MP_VERBOSE(priv, " FE_HAS_SIGNAL"); - if (festatus & FE_TIMEDOUT) - MP_VERBOSE(priv, " FE_TIMEDOUT"); - if (festatus & FE_HAS_LOCK) - MP_VERBOSE(priv, " FE_HAS_LOCK"); - if (festatus & FE_HAS_CARRIER) - MP_VERBOSE(priv, " FE_HAS_CARRIER"); - if (festatus & FE_HAS_VITERBI) - MP_VERBOSE(priv, " FE_HAS_VITERBI"); - if (festatus & FE_HAS_SYNC) - MP_VERBOSE(priv, " FE_HAS_SYNC"); - MP_VERBOSE(priv, "\n"); -} - -static int check_status(dvb_priv_t *priv, int fd_frontend, int tmout) -{ - int32_t strength; - fe_status_t festatus; - struct pollfd pfd[1]; - int ok = 0, locks = 0; - time_t tm1, tm2; - - pfd[0].fd = fd_frontend; - pfd[0].events = POLLPRI; - - MP_VERBOSE(priv, "Getting frontend status\n"); - tm1 = tm2 = time((time_t *) NULL); - while (!ok) { - festatus = 0; - if (poll(pfd, 1, tmout * 1000) > 0) { - if (pfd[0].revents & POLLPRI) { - if (ioctl(fd_frontend, FE_READ_STATUS, &festatus) >= 0) { - if (festatus & FE_HAS_LOCK) - locks++; - } - } - } - usleep(10000); - tm2 = time((time_t *) NULL); - if ((festatus & FE_TIMEDOUT) || (locks >= 2) || (tm2 - tm1 >= tmout)) - ok = 1; - } - - if (festatus & FE_HAS_LOCK) { - strength = 0; - if (ioctl(fd_frontend, FE_READ_BER, &strength) >= 0) - MP_VERBOSE(priv, "Bit error rate: %d\n", strength); - - strength = 0; - if (ioctl(fd_frontend, FE_READ_SIGNAL_STRENGTH, &strength) >= 0) - MP_VERBOSE(priv, "Signal strength: %d\n", strength); - - strength = 0; - if (ioctl(fd_frontend, FE_READ_SNR, &strength) >= 0) - MP_VERBOSE(priv, "SNR: %d\n", strength); - - strength = 0; - if (ioctl(fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &strength) >= 0) - MP_VERBOSE(priv, "UNC: %d\n", strength); - - print_status(priv, festatus); - } else { - MP_ERR(priv, "Not able to lock to the signal on the given frequency, " - "timeout: %d\n", tmout); - return -1; - } - return 0; -} - -struct diseqc_cmd { - struct dvb_diseqc_master_cmd cmd; - uint32_t wait; -}; - -static int diseqc_send_msg(int fd, fe_sec_voltage_t v, struct diseqc_cmd *cmd, - fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b) -{ - if (ioctl(fd, FE_SET_TONE, SEC_TONE_OFF) < 0) - return -1; - if (ioctl(fd, FE_SET_VOLTAGE, v) < 0) - return -1; - usleep(15 * 1000); - if (ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &cmd->cmd) < 0) - return -1; - usleep(cmd->wait * 1000); - usleep(15 * 1000); - if (ioctl(fd, FE_DISEQC_SEND_BURST, b) < 0) - return -1; - usleep(15 * 1000); - if (ioctl(fd, FE_SET_TONE, t) < 0) - return -1; - usleep(100000); - - return 0; -} - -/* digital satellite equipment control, - * specification is available from http://www.eutelsat.com/ - */ -static int do_diseqc(int secfd, int sat_no, int polv, int hi_lo) -{ - struct diseqc_cmd cmd = { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 }; - - /* param: high nibble: reset bits, low nibble set bits, - * bits are: option, position, polarizaion, band - */ - cmd.cmd.msg[3] = 0xf0 | (((sat_no * 4) & 0x0f) | (hi_lo ? 1 : 0) | (polv ? 0 : 2)); - - return diseqc_send_msg(secfd, polv ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18, - &cmd, hi_lo ? SEC_TONE_ON : SEC_TONE_OFF, - ((sat_no / 4) % 2) ? SEC_MINI_B : SEC_MINI_A); -} - -#ifdef DVB_USE_S2API -static int dvbv5_tune(dvb_priv_t *priv, int fd_frontend, - unsigned int delsys, struct dtv_properties* cmdseq) -{ - MP_VERBOSE(priv, "Tuning via S2API, channel is %s.\n", - get_dvb_delsys(delsys)); - MP_VERBOSE(priv, "Dumping raw tuning commands and values:\n"); - for (int i = 0; i < cmdseq->num; ++i) { - MP_VERBOSE(priv, "%02d: 0x%x(%d) => 0x%x(%d)\n", - i, cmdseq->props[i].cmd, cmdseq->props[i].cmd, - cmdseq->props[i].u.data, cmdseq->props[i].u.data); - } - if (ioctl(fd_frontend, FE_SET_PROPERTY, cmdseq) < 0) { - MP_ERR(priv, "ERROR tuning channel\n"); - return -1; - } - return 0; -} -#endif - -static int tune_it(dvb_priv_t *priv, int fd_frontend, unsigned int delsys, - unsigned int freq, unsigned int srate, char pol, - int stream_id, - fe_spectral_inversion_t specInv, unsigned int diseqc, - fe_modulation_t modulation, - fe_code_rate_t HP_CodeRate, - fe_transmit_mode_t TransmissionMode, - fe_guard_interval_t guardInterval, - fe_bandwidth_t bandwidth, - fe_code_rate_t LP_CodeRate, fe_hierarchy_t hier, - int timeout) -{ - int hi_lo = 0, bandwidth_hz = 0; - dvb_state_t* state = priv->state; - struct dvb_frontend_parameters feparams; - - - MP_VERBOSE(priv, "TUNE_IT, fd_frontend %d, %s freq %lu, srate %lu, " - "pol %c, diseqc %u\n", fd_frontend, - get_dvb_delsys(delsys), - (long unsigned int)freq, (long unsigned int)srate, - (pol > ' ' ? pol : '-'), diseqc); - - MP_VERBOSE(priv, "Using %s adapter %d\n", - get_dvb_delsys(delsys), - state->adapters[state->cur_adapter].devno); - - { - /* discard stale QPSK events */ - struct dvb_frontend_event ev; - while (true) { - if (ioctl(fd_frontend, FE_GET_EVENT, &ev) < 0) - break; - } - } - - /* Prepare params, be verbose. */ - switch (delsys) { - case SYS_DVBT2: -#ifndef DVB_USE_S2API - MP_ERR(priv, "ERROR: Can not tune to T2 channel, S2-API not " - "available, will tune to DVB-T!\n"); -#endif - /* PASSTROUTH. */ - case SYS_DVBT: - if (freq < 1000000) - freq *= 1000UL; - switch (bandwidth) { - case BANDWIDTH_5_MHZ: - bandwidth_hz = 5000000; - break; - case BANDWIDTH_6_MHZ: - bandwidth_hz = 6000000; - break; - case BANDWIDTH_7_MHZ: - bandwidth_hz = 7000000; - break; - case BANDWIDTH_8_MHZ: - bandwidth_hz = 8000000; - break; - case BANDWIDTH_10_MHZ: - bandwidth_hz = 10000000; - break; - case BANDWIDTH_AUTO: - if (freq < 474000000) { - bandwidth_hz = 7000000; - } else { - bandwidth_hz = 8000000; - } - break; - default: - bandwidth_hz = 0; - break; - } - - MP_VERBOSE(priv, "tuning %s to %d Hz, bandwidth: %d\n", - get_dvb_delsys(delsys), freq, bandwidth_hz); - break; - case SYS_DVBS2: -#ifndef DVB_USE_S2API - MP_ERR(priv, "ERROR: Can not tune to S2 channel, S2-API not " - "available, will tune to DVB-S!\n"); -#endif - /* PASSTROUTH. */ - case SYS_DVBS: - if (freq > 2200000) { - // this must be an absolute frequency - if (freq < SLOF) { - freq -= LOF1; - hi_lo = 0; - } else { - freq -= LOF2; - hi_lo = 1; - } - } - MP_VERBOSE(priv, "tuning %s to Freq: %u, Pol: %c Srate: %d, " - "22kHz: %s, LNB: %d\n", get_dvb_delsys(delsys), freq, - pol, srate, hi_lo ? "on" : "off", diseqc); - - if (do_diseqc(fd_frontend, diseqc, (pol == 'V' ? 1 : 0), hi_lo) == 0) { - MP_VERBOSE(priv, "DISEQC setting succeeded\n"); - } else { - MP_ERR(priv, "DISEQC setting failed\n"); - return -1; - } - - break; - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - MP_VERBOSE(priv, "tuning %s to %d, srate=%d\n", - get_dvb_delsys(delsys), freq, srate); - break; -#ifdef DVB_ATSC - case SYS_ATSC: - case SYS_DVBC_ANNEX_B: - MP_VERBOSE(priv, "tuning %s to %d, modulation=%d\n", - get_dvb_delsys(delsys), freq, modulation); - break; -#endif - default: - MP_VERBOSE(priv, "Unknown FE type. Aborting\n"); - return 0; - } - -#ifdef DVB_USE_S2API - /* S2API is the DVB API new since 2.6.28. - * It is needed to tune to new delivery systems, e.g. DVB-S2. - * It takes a struct with a list of pairs of command + parameter. - */ - - /* Reset before tune. */ - struct dtv_property p_clear[] = { - { .cmd = DTV_CLEAR }, - }; - struct dtv_properties cmdseq_clear = { - .num = 1, - .props = p_clear - }; - if (ioctl(fd_frontend, FE_SET_PROPERTY, &cmdseq_clear) < 0) { - MP_ERR(priv, "FE_SET_PROPERTY DTV_CLEAR failed\n"); - } - - /* Tune. */ - switch (delsys) { - case SYS_DVBS: - case SYS_DVBS2: - { - struct dtv_property p[] = { - { .cmd = DTV_DELIVERY_SYSTEM, .u.data = delsys }, - { .cmd = DTV_FREQUENCY, .u.data = freq }, - { .cmd = DTV_MODULATION, .u.data = modulation }, - { .cmd = DTV_SYMBOL_RATE, .u.data = srate }, - { .cmd = DTV_INNER_FEC, .u.data = HP_CodeRate }, - { .cmd = DTV_INVERSION, .u.data = specInv }, - { .cmd = DTV_ROLLOFF, .u.data = ROLLOFF_AUTO }, - { .cmd = DTV_PILOT, .u.data = PILOT_AUTO }, - { .cmd = DTV_TUNE }, - }; - struct dtv_properties cmdseq = { - .num = sizeof(p) / sizeof(p[0]), - .props = p - }; - if (dvbv5_tune(priv, fd_frontend, delsys, &cmdseq) != 0) { - goto old_api; - } - } - break; - case SYS_DVBT: - case SYS_DVBT2: - { - struct dtv_property p[] = { - { .cmd = DTV_DELIVERY_SYSTEM, .u.data = delsys }, - { .cmd = DTV_FREQUENCY, .u.data = freq }, - { .cmd = DTV_MODULATION, .u.data = modulation }, - { .cmd = DTV_SYMBOL_RATE, .u.data = srate }, - { .cmd = DTV_CODE_RATE_HP, .u.data = HP_CodeRate }, - { .cmd = DTV_CODE_RATE_LP, .u.data = LP_CodeRate }, - { .cmd = DTV_INVERSION, .u.data = specInv }, - { .cmd = DTV_BANDWIDTH_HZ, .u.data = bandwidth_hz }, - { .cmd = DTV_TRANSMISSION_MODE, .u.data = TransmissionMode }, - { .cmd = DTV_GUARD_INTERVAL, .u.data = guardInterval }, - { .cmd = DTV_HIERARCHY, .u.data = hier }, - { .cmd = DTV_STREAM_ID, .u.data = stream_id }, - { .cmd = DTV_TUNE }, - }; - struct dtv_properties cmdseq = { - .num = sizeof(p) / sizeof(p[0]), - .props = p - }; - if (dvbv5_tune(priv, fd_frontend, delsys, &cmdseq) != 0) { - goto old_api; - } - } - break; - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - { - struct dtv_property p[] = { - { .cmd = DTV_DELIVERY_SYSTEM, .u.data = delsys }, - { .cmd = DTV_FREQUENCY, .u.data = freq }, - { .cmd = DTV_MODULATION, .u.data = modulation }, - { .cmd = DTV_SYMBOL_RATE, .u.data = srate }, - { .cmd = DTV_INNER_FEC, .u.data = HP_CodeRate }, - { .cmd = DTV_INVERSION, .u.data = specInv }, - { .cmd = DTV_TUNE }, - }; - struct dtv_properties cmdseq = { - .num = sizeof(p) / sizeof(p[0]), - .props = p - }; - if (dvbv5_tune(priv, fd_frontend, delsys, &cmdseq) != 0) { - goto old_api; - } - } - break; -#ifdef DVB_ATSC - case SYS_ATSC: - case SYS_DVBC_ANNEX_B: - { - struct dtv_property p[] = { - { .cmd = DTV_DELIVERY_SYSTEM, .u.data = delsys }, - { .cmd = DTV_FREQUENCY, .u.data = freq }, - { .cmd = DTV_INVERSION, .u.data = specInv }, - { .cmd = DTV_MODULATION, .u.data = modulation }, - { .cmd = DTV_TUNE }, - }; - struct dtv_properties cmdseq = { - .num = sizeof(p) / sizeof(p[0]), - .props = p - }; - if (dvbv5_tune(priv, fd_frontend, delsys, &cmdseq) != 0) { - goto old_api; - } - } - break; -#endif - } - - int tune_status = check_status(priv, fd_frontend, timeout); - if (tune_status != 0) { - MP_ERR(priv, "ERROR locking to channel when tuning with S2API, clearing and falling back to DVBv3-tuning.\n"); - if (ioctl(fd_frontend, FE_SET_PROPERTY, &cmdseq_clear) < 0) { - MP_ERR(priv, "FE_SET_PROPERTY DTV_CLEAR failed\n"); - } - goto old_api; - } else { - return tune_status; - } - -old_api: -#endif - - MP_VERBOSE(priv, "Tuning via DVB-API version 3.\n"); - - if (stream_id != NO_STREAM_ID_FILTER && stream_id != 0) { - MP_ERR(priv, "DVB-API version 3 does not support stream_id (PLP).\n"); - return -1; - } - memset(&feparams, 0x00, sizeof(feparams)); - feparams.frequency = freq; - feparams.inversion = specInv; - - switch (delsys) { - case SYS_DVBT: - case SYS_DVBT2: - feparams.u.ofdm.bandwidth = bandwidth; - feparams.u.ofdm.code_rate_HP = HP_CodeRate; - feparams.u.ofdm.code_rate_LP = LP_CodeRate; - feparams.u.ofdm.constellation = modulation; - feparams.u.ofdm.transmission_mode = TransmissionMode; - feparams.u.ofdm.guard_interval = guardInterval; - feparams.u.ofdm.hierarchy_information = hier; - break; - case SYS_DVBS: - case SYS_DVBS2: - feparams.u.qpsk.symbol_rate = srate; - feparams.u.qpsk.fec_inner = HP_CodeRate; - break; - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - feparams.u.qam.symbol_rate = srate; - feparams.u.qam.fec_inner = HP_CodeRate; - feparams.u.qam.modulation = modulation; - break; -#ifdef DVB_ATSC - case SYS_ATSC: - case SYS_DVBC_ANNEX_B: - feparams.u.vsb.modulation = modulation; - break; -#endif - } - - if (ioctl(fd_frontend, FE_SET_FRONTEND, &feparams) < 0) { - MP_ERR(priv, "ERROR tuning channel\n"); - return -1; - } - - return check_status(priv, fd_frontend, timeout); -} - -int dvb_tune(dvb_priv_t *priv, unsigned int delsys, - int freq, char pol, int srate, int diseqc, - int stream_id, fe_spectral_inversion_t specInv, - fe_modulation_t modulation, fe_guard_interval_t guardInterval, - fe_transmit_mode_t TransmissionMode, fe_bandwidth_t bandWidth, - fe_code_rate_t HP_CodeRate, - fe_code_rate_t LP_CodeRate, fe_hierarchy_t hier, - int timeout) -{ - MP_INFO(priv, "dvb_tune %s Freq: %lu\n", - get_dvb_delsys(delsys), (long unsigned int) freq); - - dvb_state_t* state = priv->state; - - int ris = tune_it(priv, state->fe_fd, delsys, freq, srate, pol, - stream_id, specInv, diseqc, modulation, - HP_CodeRate, TransmissionMode, guardInterval, - bandWidth, LP_CodeRate, hier, timeout); - - if (ris != 0) - MP_INFO(priv, "dvb_tune, TUNING FAILED\n"); - - return ris == 0; -} diff --git a/stream/dvb_tune.h b/stream/dvb_tune.h deleted file mode 100644 index d7a790171f..0000000000 --- a/stream/dvb_tune.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_DVB_TUNE_H -#define MPLAYER_DVB_TUNE_H - -#include "dvbin.h" - -struct mp_log; - - -const char *get_dvb_delsys(unsigned int delsys); -unsigned int dvb_get_tuner_delsys_mask(int fe_fd, struct mp_log *log); -int dvb_open_devices(dvb_priv_t *priv, unsigned int adapter, - unsigned int frontend, unsigned int demux_cnt); -int dvb_fix_demuxes(dvb_priv_t *priv, unsigned int cnt); -int dvb_set_ts_filt(dvb_priv_t *priv, int fd, uint16_t pid, dmx_pes_type_t pestype); -int dvb_get_pmt_pid(dvb_priv_t *priv, int card, int service_id); -int dvb_tune(dvb_priv_t *priv, unsigned int delsys, - int freq, char pol, int srate, int diseqc, - int stream_id, fe_spectral_inversion_t specInv, - fe_modulation_t modulation, fe_guard_interval_t guardInterval, - fe_transmit_mode_t TransmissionMode, fe_bandwidth_t bandWidth, - fe_code_rate_t HP_CodeRate, fe_code_rate_t LP_CodeRate, - fe_hierarchy_t hier, int timeout); - -#endif /* MPLAYER_DVB_TUNE_H */ diff --git a/stream/dvbin.h b/stream/dvbin.h deleted file mode 100644 index 01a70588a5..0000000000 --- a/stream/dvbin.h +++ /dev/null @@ -1,186 +0,0 @@ -/* Imported from the dvbstream project - * - * Modified for use with MPlayer, for details see the changelog at - * http://svn.mplayerhq.hu/mplayer/trunk/ - * $Id$ - */ - -#ifndef MPLAYER_DVBIN_H -#define MPLAYER_DVBIN_H - -#include "config.h" -#include "stream.h" - -#if !HAVE_GPL -#error GPL only -#endif - -#define SLOF (11700 * 1000UL) -#define LOF1 (9750 * 1000UL) -#define LOF2 (10600 * 1000UL) - -#include -#include -#include -#include -#include -#include - -#define MAX_ADAPTERS 16 -#define MAX_FRONTENDS 8 - -#undef DVB_ATSC -#if defined(DVB_API_VERSION_MINOR) - -/* kernel headers >=2.6.28 have version 5. - * - * Version 5 is also called S2API, it adds support for tuning to S2 channels - * and is extensible for future delivery systems. Old API is deprecated. - * StreamID-implementation only supported since API >=5.2. - * At least DTV_ENUM_DELSYS requires 5.5. - */ - -#if (DVB_API_VERSION == 5 && DVB_API_VERSION_MINOR >= 5) -#define DVB_USE_S2API 1 - -// This had a different name until API 5.8. -#ifndef DTV_STREAM_ID -#define DTV_STREAM_ID DTV_ISDBS_TS_ID -#endif -#endif - -// This is only defined, for convenience, since API 5.8. -#ifndef NO_STREAM_ID_FILTER -#define NO_STREAM_ID_FILTER (~0U) -#endif - -#if (DVB_API_VERSION == 3 && DVB_API_VERSION_MINOR >= 1) || DVB_API_VERSION == 5 -#define DVB_ATSC 1 -#endif - -#endif - -#define DVB_CHANNEL_LOWER -1 -#define DVB_CHANNEL_HIGHER 1 - -#ifndef DMX_FILTER_SIZE -#define DMX_FILTER_SIZE 32 -#endif - -typedef struct { - char *name; - unsigned int freq, srate, diseqc; - char pol; - unsigned int tpid, dpid1, dpid2, progid, ca, pids[DMX_FILTER_SIZE], pids_cnt; - bool is_dvb_x2; /* Used only in dvb_get_channels() and parse_vdr_par_string(), use delsys. */ - unsigned int frontend; - unsigned int delsys; - unsigned int stream_id; - unsigned int service_id; - fe_spectral_inversion_t inv; - fe_modulation_t mod; - fe_transmit_mode_t trans; - fe_bandwidth_t bw; - fe_guard_interval_t gi; - fe_code_rate_t cr, cr_lp; - fe_hierarchy_t hier; -} dvb_channel_t; - -typedef struct { - unsigned int NUM_CHANNELS; - unsigned int current; - dvb_channel_t *channels; -} dvb_channels_list_t; - -typedef struct { - int devno; - unsigned int delsys_mask[MAX_FRONTENDS]; - dvb_channels_list_t *list; -} dvb_adapter_config_t; - -typedef struct { - unsigned int adapters_count; - dvb_adapter_config_t *adapters; - unsigned int cur_adapter; - unsigned int cur_frontend; - - int fe_fd; - int dvr_fd; - int demux_fd[3], demux_fds[DMX_FILTER_SIZE], demux_fds_cnt; - - int is_on; - int retry; - int timeout; - unsigned int last_freq; - bool switching_channel; - bool stream_used; -} dvb_state_t; - -typedef struct { - struct mp_log *log; - - dvb_state_t *state; - - char *cfg_prog; - int cfg_devno; - int cfg_timeout; - char *cfg_file; - - int cfg_full_transponder; -} dvb_priv_t; - - -/* Keep in sync with enum fe_delivery_system. */ -#ifndef DVB_USE_S2API -# define SYS_DVBC_ANNEX_A 1 -# define SYS_DVBC_ANNEX_B 1 -# define SYS_DVBT 3 -# define SYS_DVBS 5 -# define SYS_DVBS2 6 -# define SYS_ATSC 11 -# define SYS_DVBT2 16 -# define SYS_DVBC_ANNEX_C 18 -#endif -#define SYS_DVB__COUNT__ (SYS_DVBC_ANNEX_C + 1) - - -#define DELSYS_BIT(__bit) (((unsigned int)1) << (__bit)) - -#define DELSYS_SET(__mask, __bit) \ - (__mask) |= DELSYS_BIT((__bit)) - -#define DELSYS_IS_SET(__mask, __bit) \ - (0 != ((__mask) & DELSYS_BIT((__bit)))) - - -#ifdef DVB_ATSC -#define DELSYS_SUPP_MASK \ - ( \ - DELSYS_BIT(SYS_DVBC_ANNEX_A) | \ - DELSYS_BIT(SYS_DVBT) | \ - DELSYS_BIT(SYS_DVBS) | \ - DELSYS_BIT(SYS_DVBS2) | \ - DELSYS_BIT(SYS_ATSC) | \ - DELSYS_BIT(SYS_DVBC_ANNEX_B) | \ - DELSYS_BIT(SYS_DVBT2) | \ - DELSYS_BIT(SYS_DVBC_ANNEX_C) \ - ) -#else -#define DELSYS_SUPP_MASK \ - ( \ - DELSYS_BIT(SYS_DVBC_ANNEX_A) | \ - DELSYS_BIT(SYS_DVBT) | \ - DELSYS_BIT(SYS_DVBS) | \ - DELSYS_BIT(SYS_DVBS2) | \ - DELSYS_BIT(SYS_DVBT2) | \ - DELSYS_BIT(SYS_DVBC_ANNEX_C) \ - ) -#endif - - -int dvb_step_channel(stream_t *, int); -int dvb_set_channel(stream_t *, unsigned int, unsigned int); -dvb_state_t *dvb_get_state(stream_t *); -void dvb_free_state(dvb_state_t *); - -#endif /* MPLAYER_DVBIN_H */ diff --git a/stream/frequencies.c b/stream/frequencies.c deleted file mode 100644 index 2e4027c680..0000000000 --- a/stream/frequencies.c +++ /dev/null @@ -1,1212 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include -#include - -#include "frequencies.h" - -/* --------------------------------------------------------------------- */ - -/* US broadcast */ -static const struct CHANLIST ntsc_bcast[] = { - { "2", 55250 }, - { "3", 61250 }, - { "4", 67250 }, - { "5", 77250 }, - { "6", 83250 }, - { "7", 175250 }, - { "8", 181250 }, - { "9", 187250 }, - { "10", 193250 }, - { "11", 199250 }, - { "12", 205250 }, - { "13", 211250 }, - { "14", 471250 }, - { "15", 477250 }, - { "16", 483250 }, - { "17", 489250 }, - { "18", 495250 }, - { "19", 501250 }, - { "20", 507250 }, - { "21", 513250 }, - { "22", 519250 }, - { "23", 525250 }, - { "24", 531250 }, - { "25", 537250 }, - { "26", 543250 }, - { "27", 549250 }, - { "28", 555250 }, - { "29", 561250 }, - { "30", 567250 }, - { "31", 573250 }, - { "32", 579250 }, - { "33", 585250 }, - { "34", 591250 }, - { "35", 597250 }, - { "36", 603250 }, - { "37", 609250 }, - { "38", 615250 }, - { "39", 621250 }, - { "40", 627250 }, - { "41", 633250 }, - { "42", 639250 }, - { "43", 645250 }, - { "44", 651250 }, - { "45", 657250 }, - { "46", 663250 }, - { "47", 669250 }, - { "48", 675250 }, - { "49", 681250 }, - { "50", 687250 }, - { "51", 693250 }, - { "52", 699250 }, - { "53", 705250 }, - { "54", 711250 }, - { "55", 717250 }, - { "56", 723250 }, - { "57", 729250 }, - { "58", 735250 }, - { "59", 741250 }, - { "60", 747250 }, - { "61", 753250 }, - { "62", 759250 }, - { "63", 765250 }, - { "64", 771250 }, - { "65", 777250 }, - { "66", 783250 }, - { "67", 789250 }, - { "68", 795250 }, - { "69", 801250 }, - - { "70", 807250 }, - { "71", 813250 }, - { "72", 819250 }, - { "73", 825250 }, - { "74", 831250 }, - { "75", 837250 }, - { "76", 843250 }, - { "77", 849250 }, - { "78", 855250 }, - { "79", 861250 }, - { "80", 867250 }, - { "81", 873250 }, - { "82", 879250 }, - { "83", 885250 }, -}; - -/* US cable */ -static const struct CHANLIST ntsc_cable[] = { - { "1", 73250 }, - { "2", 55250 }, - { "3", 61250 }, - { "4", 67250 }, - { "5", 77250 }, - { "6", 83250 }, - { "7", 175250 }, - { "8", 181250 }, - { "9", 187250 }, - { "10", 193250 }, - { "11", 199250 }, - { "12", 205250 }, - - { "13", 211250 }, - { "14", 121250 }, - { "15", 127250 }, - { "16", 133250 }, - { "17", 139250 }, - { "18", 145250 }, - { "19", 151250 }, - { "20", 157250 }, - - { "21", 163250 }, - { "22", 169250 }, - { "23", 217250 }, - { "24", 223250 }, - { "25", 229250 }, - { "26", 235250 }, - { "27", 241250 }, - { "28", 247250 }, - { "29", 253250 }, - { "30", 259250 }, - { "31", 265250 }, - { "32", 271250 }, - { "33", 277250 }, - { "34", 283250 }, - { "35", 289250 }, - { "36", 295250 }, - { "37", 301250 }, - { "38", 307250 }, - { "39", 313250 }, - { "40", 319250 }, - { "41", 325250 }, - { "42", 331250 }, - { "43", 337250 }, - { "44", 343250 }, - { "45", 349250 }, - { "46", 355250 }, - { "47", 361250 }, - { "48", 367250 }, - { "49", 373250 }, - { "50", 379250 }, - { "51", 385250 }, - { "52", 391250 }, - { "53", 397250 }, - { "54", 403250 }, - { "55", 409250 }, - { "56", 415250 }, - { "57", 421250 }, - { "58", 427250 }, - { "59", 433250 }, - { "60", 439250 }, - { "61", 445250 }, - { "62", 451250 }, - { "63", 457250 }, - { "64", 463250 }, - { "65", 469250 }, - { "66", 475250 }, - { "67", 481250 }, - { "68", 487250 }, - { "69", 493250 }, - - { "70", 499250 }, - { "71", 505250 }, - { "72", 511250 }, - { "73", 517250 }, - { "74", 523250 }, - { "75", 529250 }, - { "76", 535250 }, - { "77", 541250 }, - { "78", 547250 }, - { "79", 553250 }, - { "80", 559250 }, - { "81", 565250 }, - { "82", 571250 }, - { "83", 577250 }, - { "84", 583250 }, - { "85", 589250 }, - { "86", 595250 }, - { "87", 601250 }, - { "88", 607250 }, - { "89", 613250 }, - { "90", 619250 }, - { "91", 625250 }, - { "92", 631250 }, - { "93", 637250 }, - { "94", 643250 }, - { "95", 91250 }, - { "96", 97250 }, - { "97", 103250 }, - { "98", 109250 }, - { "99", 115250 }, - { "100", 649250 }, - { "101", 655250 }, - { "102", 661250 }, - { "103", 667250 }, - { "104", 673250 }, - { "105", 679250 }, - { "106", 685250 }, - { "107", 691250 }, - { "108", 697250 }, - { "109", 703250 }, - { "110", 709250 }, - { "111", 715250 }, - { "112", 721250 }, - { "113", 727250 }, - { "114", 733250 }, - { "115", 739250 }, - { "116", 745250 }, - { "117", 751250 }, - { "118", 757250 }, - { "119", 763250 }, - { "120", 769250 }, - { "121", 775250 }, - { "122", 781250 }, - { "123", 787250 }, - { "124", 793250 }, - { "125", 799250 }, - - { "T7", 8250 }, - { "T8", 14250 }, - { "T9", 20250 }, - { "T10", 26250 }, - { "T11", 32250 }, - { "T12", 38250 }, - { "T13", 44250 }, - { "T14", 50250 } -}; - -/* US HRC */ -static const struct CHANLIST ntsc_hrc[] = { - { "1", 72000 }, - { "2", 54000 }, - { "3", 60000 }, - { "4", 66000 }, - { "5", 78000 }, - { "6", 84000 }, - { "7", 174000 }, - { "8", 180000 }, - { "9", 186000 }, - { "10", 192000 }, - { "11", 198000 }, - { "12", 204000 }, - - { "13", 210000 }, - { "14", 120000 }, - { "15", 126000 }, - { "16", 132000 }, - { "17", 138000 }, - { "18", 144000 }, - { "19", 150000 }, - { "20", 156000 }, - - { "21", 162000 }, - { "22", 168000 }, - { "23", 216000 }, - { "24", 222000 }, - { "25", 228000 }, - { "26", 234000 }, - { "27", 240000 }, - { "28", 246000 }, - { "29", 252000 }, - { "30", 258000 }, - { "31", 264000 }, - { "32", 270000 }, - { "33", 276000 }, - { "34", 282000 }, - { "35", 288000 }, - { "36", 294000 }, - { "37", 300000 }, - { "38", 306000 }, - { "39", 312000 }, - { "40", 318000 }, - { "41", 324000 }, - { "42", 330000 }, - { "43", 336000 }, - { "44", 342000 }, - { "45", 348000 }, - { "46", 354000 }, - { "47", 360000 }, - { "48", 366000 }, - { "49", 372000 }, - { "50", 378000 }, - { "51", 384000 }, - { "52", 390000 }, - { "53", 396000 }, - { "54", 402000 }, - { "55", 408000 }, - { "56", 414000 }, - { "57", 420000 }, - { "58", 426000 }, - { "59", 432000 }, - { "60", 438000 }, - { "61", 444000 }, - { "62", 450000 }, - { "63", 456000 }, - { "64", 462000 }, - { "65", 468000 }, - { "66", 474000 }, - { "67", 480000 }, - { "68", 486000 }, - { "69", 492000 }, - - { "70", 498000 }, - { "71", 504000 }, - { "72", 510000 }, - { "73", 516000 }, - { "74", 522000 }, - { "75", 528000 }, - { "76", 534000 }, - { "77", 540000 }, - { "78", 546000 }, - { "79", 552000 }, - { "80", 558000 }, - { "81", 564000 }, - { "82", 570000 }, - { "83", 576000 }, - { "84", 582000 }, - { "85", 588000 }, - { "86", 594000 }, - { "87", 600000 }, - { "88", 606000 }, - { "89", 612000 }, - { "90", 618000 }, - { "91", 624000 }, - { "92", 630000 }, - { "93", 636000 }, - { "94", 642000 }, - { "95", 900000 }, - { "96", 960000 }, - { "97", 102000 }, - { "98", 108000 }, - { "99", 114000 }, - { "100", 648000 }, - { "101", 654000 }, - { "102", 660000 }, - { "103", 666000 }, - { "104", 672000 }, - { "105", 678000 }, - { "106", 684000 }, - { "107", 690000 }, - { "108", 696000 }, - { "109", 702000 }, - { "110", 708000 }, - { "111", 714000 }, - { "112", 720000 }, - { "113", 726000 }, - { "114", 732000 }, - { "115", 738000 }, - { "116", 744000 }, - { "117", 750000 }, - { "118", 756000 }, - { "119", 762000 }, - { "120", 768000 }, - { "121", 774000 }, - { "122", 780000 }, - { "123", 786000 }, - { "124", 792000 }, - { "125", 798000 }, - - { "T7", 7000 }, - { "T8", 13000 }, - { "T9", 19000 }, - { "T10", 25000 }, - { "T11", 31000 }, - { "T12", 37000 }, - { "T13", 43000 }, - { "T14", 49000 }, -}; - -/* --------------------------------------------------------------------- */ - -/* JP broadcast */ -static const struct CHANLIST ntsc_bcast_jp[] = { - { "1", 91250 }, - { "2", 97250 }, - { "3", 103250 }, - { "4", 171250 }, - { "5", 177250 }, - { "6", 183250 }, - { "7", 189250 }, - { "8", 193250 }, - { "9", 199250 }, - { "10", 205250 }, - { "11", 211250 }, - { "12", 217250 }, - - { "13", 471250 }, - { "14", 477250 }, - { "15", 483250 }, - { "16", 489250 }, - { "17", 495250 }, - { "18", 501250 }, - { "19", 507250 }, - { "20", 513250 }, - { "21", 519250 }, - { "22", 525250 }, - { "23", 531250 }, - { "24", 537250 }, - { "25", 543250 }, - { "26", 549250 }, - { "27", 555250 }, - { "28", 561250 }, - { "29", 567250 }, - { "30", 573250 }, - { "31", 579250 }, - { "32", 585250 }, - { "33", 591250 }, - { "34", 597250 }, - { "35", 603250 }, - { "36", 609250 }, - { "37", 615250 }, - { "38", 621250 }, - { "39", 627250 }, - { "40", 633250 }, - { "41", 639250 }, - { "42", 645250 }, - { "43", 651250 }, - { "44", 657250 }, - - { "45", 663250 }, - { "46", 669250 }, - { "47", 675250 }, - { "48", 681250 }, - { "49", 687250 }, - { "50", 693250 }, - { "51", 699250 }, - { "52", 705250 }, - { "53", 711250 }, - { "54", 717250 }, - { "55", 723250 }, - { "56", 729250 }, - { "57", 735250 }, - { "58", 741250 }, - { "59", 747250 }, - { "60", 753250 }, - { "61", 759250 }, - { "62", 765250 }, -}; - -/* JP cable */ -static const struct CHANLIST ntsc_cable_jp[] = { - { "13", 109250 }, - { "14", 115250 }, - { "15", 121250 }, - { "16", 127250 }, - { "17", 133250 }, - { "18", 139250 }, - { "19", 145250 }, - { "20", 151250 }, - - { "21", 157250 }, - { "22", 165250 }, - { "23", 223250 }, - { "24", 231250 }, - { "25", 237250 }, - { "26", 243250 }, - { "27", 249250 }, - { "28", 253250 }, - { "29", 259250 }, - { "30", 265250 }, - { "31", 271250 }, - { "32", 277250 }, - { "33", 283250 }, - { "34", 289250 }, - { "35", 295250 }, - { "36", 301250 }, - { "37", 307250 }, - { "38", 313250 }, - { "39", 319250 }, - { "40", 325250 }, - { "41", 331250 }, - { "42", 337250 }, - { "43", 343250 }, - { "44", 349250 }, - { "45", 355250 }, - { "46", 361250 }, - { "47", 367250 }, - { "48", 373250 }, - { "49", 379250 }, - { "50", 385250 }, - { "51", 391250 }, - { "52", 397250 }, - { "53", 403250 }, - { "54", 409250 }, - { "55", 415250 }, - { "56", 421250 }, - { "57", 427250 }, - { "58", 433250 }, - { "59", 439250 }, - { "60", 445250 }, - { "61", 451250 }, - { "62", 457250 }, - { "63", 463250 }, -}; - -/* --------------------------------------------------------------------- */ - -/* australia */ -static const struct CHANLIST pal_australia[] = { - { "0", 46250 }, - { "1", 57250 }, - { "2", 64250 }, - { "3", 86250 }, - { "4", 95250 }, - { "5", 102250 }, - { "5A", 138250 }, - { "6", 175250 }, - { "7", 182250 }, - { "8", 189250 }, - { "9", 196250 }, - { "10", 209250 }, - { "11", 216250 }, - { "28", 527250 }, - { "29", 534250 }, - { "30", 541250 }, - { "31", 548250 }, - { "32", 555250 }, - { "33", 562250 }, - { "34", 569250 }, - { "35", 576250 }, - { "36", 591250 }, - { "39", 604250 }, - { "40", 611250 }, - { "41", 618250 }, - { "42", 625250 }, - { "43", 632250 }, - { "44", 639250 }, - { "45", 646250 }, - { "46", 653250 }, - { "47", 660250 }, - { "48", 667250 }, - { "49", 674250 }, - { "50", 681250 }, - { "51", 688250 }, - { "52", 695250 }, - { "53", 702250 }, - { "54", 709250 }, - { "55", 716250 }, - { "56", 723250 }, - { "57", 730250 }, - { "58", 737250 }, - { "59", 744250 }, - { "60", 751250 }, - { "61", 758250 }, - { "62", 765250 }, - { "63", 772250 }, - { "64", 779250 }, - { "65", 786250 }, - { "66", 793250 }, - { "67", 800250 }, - { "68", 807250 }, - { "69", 814250 }, -}; - -/* --------------------------------------------------------------------- */ -/* europe */ - -/* CCIR frequencies */ - -#define FREQ_CCIR_I_III \ - { "E2", 48250 }, \ - { "E3", 55250 }, \ - { "E4", 62250 }, \ - \ - { "S01", 69250 }, \ - { "S02", 76250 }, \ - { "S03", 83250 }, \ - \ - { "E5", 175250 }, \ - { "E6", 182250 }, \ - { "E7", 189250 }, \ - { "E8", 196250 }, \ - { "E9", 203250 }, \ - { "E10", 210250 }, \ - { "E11", 217250 }, \ - { "E12", 224250 } - -#define FREQ_CCIR_SL_SH \ - { "SE1", 105250 }, \ - { "SE2", 112250 }, \ - { "SE3", 119250 }, \ - { "SE4", 126250 }, \ - { "SE5", 133250 }, \ - { "SE6", 140250 }, \ - { "SE7", 147250 }, \ - { "SE8", 154250 }, \ - { "SE9", 161250 }, \ - { "SE10", 168250 }, \ - \ - { "SE11", 231250 }, \ - { "SE12", 238250 }, \ - { "SE13", 245250 }, \ - { "SE14", 252250 }, \ - { "SE15", 259250 }, \ - { "SE16", 266250 }, \ - { "SE17", 273250 }, \ - { "SE18", 280250 }, \ - { "SE19", 287250 }, \ - { "SE20", 294250 } - -#define FREQ_CCIR_H \ - { "S21", 303250 }, \ - { "S22", 311250 }, \ - { "S23", 319250 }, \ - { "S24", 327250 }, \ - { "S25", 335250 }, \ - { "S26", 343250 }, \ - { "S27", 351250 }, \ - { "S28", 359250 }, \ - { "S29", 367250 }, \ - { "S30", 375250 }, \ - { "S31", 383250 }, \ - { "S32", 391250 }, \ - { "S33", 399250 }, \ - { "S34", 407250 }, \ - { "S35", 415250 }, \ - { "S36", 423250 }, \ - { "S37", 431250 }, \ - { "S38", 439250 }, \ - { "S39", 447250 }, \ - { "S40", 455250 }, \ - { "S41", 463250 } - -/* OIRT frequencies */ - -#define FREQ_OIRT_I_III \ - { "R1", 49750 }, \ - { "R2", 59250 }, \ - \ - { "R3", 77250 }, \ - { "R4", 85250 }, \ - { "R5", 93250 }, \ - \ - { "R6", 175250 }, \ - { "R7", 183250 }, \ - { "R8", 191250 }, \ - { "R9", 199250 }, \ - { "R10", 207250 }, \ - { "R11", 215250 }, \ - { "R12", 223250 } - -#define FREQ_OIRT_SL_SH \ - { "SR1", 111250 }, \ - { "SR2", 119250 }, \ - { "SR3", 127250 }, \ - { "SR4", 135250 }, \ - { "SR5", 143250 }, \ - { "SR6", 151250 }, \ - { "SR7", 159250 }, \ - { "SR8", 167250 }, \ - \ - { "SR11", 231250 }, \ - { "SR12", 239250 }, \ - { "SR13", 247250 }, \ - { "SR14", 255250 }, \ - { "SR15", 263250 }, \ - { "SR16", 271250 }, \ - { "SR17", 279250 }, \ - { "SR18", 287250 }, \ - { "SR19", 295250 } - -#define FREQ_UHF \ - { "21", 471250 }, \ - { "22", 479250 }, \ - { "23", 487250 }, \ - { "24", 495250 }, \ - { "25", 503250 }, \ - { "26", 511250 }, \ - { "27", 519250 }, \ - { "28", 527250 }, \ - { "29", 535250 }, \ - { "30", 543250 }, \ - { "31", 551250 }, \ - { "32", 559250 }, \ - { "33", 567250 }, \ - { "34", 575250 }, \ - { "35", 583250 }, \ - { "36", 591250 }, \ - { "37", 599250 }, \ - { "38", 607250 }, \ - { "39", 615250 }, \ - { "40", 623250 }, \ - { "41", 631250 }, \ - { "42", 639250 }, \ - { "43", 647250 }, \ - { "44", 655250 }, \ - { "45", 663250 }, \ - { "46", 671250 }, \ - { "47", 679250 }, \ - { "48", 687250 }, \ - { "49", 695250 }, \ - { "50", 703250 }, \ - { "51", 711250 }, \ - { "52", 719250 }, \ - { "53", 727250 }, \ - { "54", 735250 }, \ - { "55", 743250 }, \ - { "56", 751250 }, \ - { "57", 759250 }, \ - { "58", 767250 }, \ - { "59", 775250 }, \ - { "60", 783250 }, \ - { "61", 791250 }, \ - { "62", 799250 }, \ - { "63", 807250 }, \ - { "64", 815250 }, \ - { "65", 823250 }, \ - { "66", 831250 }, \ - { "67", 839250 }, \ - { "68", 847250 }, \ - { "69", 855250 } - -static const struct CHANLIST europe_west[] = { - FREQ_CCIR_I_III, - FREQ_CCIR_SL_SH, - FREQ_CCIR_H, - FREQ_UHF -}; - -static const struct CHANLIST europe_east[] = { - FREQ_OIRT_I_III, - FREQ_OIRT_SL_SH, - FREQ_CCIR_I_III, - FREQ_CCIR_SL_SH, - FREQ_CCIR_H, - FREQ_UHF -}; - -static const struct CHANLIST pal_italy[] = { - { "A", 53750 }, - { "B", 62250 }, - { "C", 82250 }, - { "D", 175250 }, - { "E", 183750 }, - { "F", 192250 }, - { "G", 201250 }, - { "H", 210250 }, - { "H1", 217250 }, - { "H2", 224250 }, - FREQ_UHF -}; - -static const struct CHANLIST pal_ireland[] = { - { "A0", 45750 }, - { "A1", 48000 }, - { "A2", 53750 }, - { "A3", 56000 }, - { "A4", 61750 }, - { "A5", 64000 }, - { "A6", 175250 }, - { "A7", 176000 }, - { "A8", 183250 }, - { "A9", 184000 }, - { "A10", 191250 }, - { "A11", 192000 }, - { "A12", 199250 }, - { "A13", 200000 }, - { "A14", 207250 }, - { "A15", 208000 }, - { "A16", 215250 }, - { "A17", 216000 }, - { "A18", 224000 }, - { "A19", 232000 }, - { "A20", 248000 }, - { "A21", 256000 }, - { "A22", 264000 }, - { "A23", 272000 }, - { "A24", 280000 }, - { "A25", 288000 }, - { "A26", 296000 }, - { "A27", 304000 }, - { "A28", 312000 }, - { "A29", 320000 }, - { "A30", 344000 }, - { "A31", 352000 }, - { "A32", 408000 }, - { "A33", 416000 }, - { "A34", 448000 }, - { "A35", 480000 }, - { "A36", 520000 }, - FREQ_UHF, -}; - -static const struct CHANLIST secam_france[] = { - { "K01", 47750 }, - { "K02", 55750 }, - { "K03", 60500 }, - { "K04", 63750 }, - { "K05", 176000 }, - { "K06", 184000 }, - { "K07", 192000 }, - { "K08", 200000 }, - { "K09", 208000 }, - { "K10", 216000 }, - { "KB", 116750 }, - { "KC", 128750 }, - { "KD", 140750 }, - { "KE", 159750 }, - { "KF", 164750 }, - { "KG", 176750 }, - { "KH", 188750 }, - { "KI", 200750 }, - { "KJ", 212750 }, - { "KK", 224750 }, - { "KL", 236750 }, - { "KM", 248750 }, - { "KN", 260750 }, - { "KO", 272750 }, - { "KP", 284750 }, - { "KQ", 296750 }, - { "H01", 303250 }, - { "H02", 311250 }, - { "H03", 319250 }, - { "H04", 327250 }, - { "H05", 335250 }, - { "H06", 343250 }, - { "H07", 351250 }, - { "H08", 359250 }, - { "H09", 367250 }, - { "H10", 375250 }, - { "H11", 383250 }, - { "H12", 391250 }, - { "H13", 399250 }, - { "H14", 407250 }, - { "H15", 415250 }, - { "H16", 423250 }, - { "H17", 431250 }, - { "H18", 439250 }, - { "H19", 447250 }, - FREQ_UHF, -}; - -/* --------------------------------------------------------------------- */ - -static const struct CHANLIST pal_newzealand[] = { - { "1", 45250 }, - { "2", 55250 }, - { "3", 62250 }, - { "4", 175250 }, - { "5", 182250 }, - { "6", 189250 }, - { "7", 196250 }, - { "8", 203250 }, - { "9", 210250 }, - { "10", 217250 }, - { "11", 224250 }, - FREQ_UHF, -}; - -/* --------------------------------------------------------------------- */ - -/* China broadcast */ -static const struct CHANLIST pal_bcast_cn[] = { - { "1", 49750 }, - { "2", 57750 }, - { "3", 65750 }, - { "4", 77250 }, - { "5", 85250 }, - { "6", 112250 }, - { "7", 120250 }, - { "8", 128250 }, - { "9", 136250 }, - { "10", 144250 }, - { "11", 152250 }, - { "12", 160250 }, - { "13", 168250 }, - { "14", 176250 }, - { "15", 184250 }, - { "16", 192250 }, - { "17", 200250 }, - { "18", 208250 }, - { "19", 216250 }, - { "20", 224250 }, - { "21", 232250 }, - { "22", 240250 }, - { "23", 248250 }, - { "24", 256250 }, - { "25", 264250 }, - { "26", 272250 }, - { "27", 280250 }, - { "28", 288250 }, - { "29", 296250 }, - { "30", 304250 }, - { "31", 312250 }, - { "32", 320250 }, - { "33", 328250 }, - { "34", 336250 }, - { "35", 344250 }, - { "36", 352250 }, - { "37", 360250 }, - { "38", 368250 }, - { "39", 376250 }, - { "40", 384250 }, - { "41", 392250 }, - { "42", 400250 }, - { "43", 408250 }, - { "44", 416250 }, - { "45", 424250 }, - { "46", 432250 }, - { "47", 440250 }, - { "48", 448250 }, - { "49", 456250 }, - { "50", 463250 }, - { "51", 471250 }, - { "52", 479250 }, - { "53", 487250 }, - { "54", 495250 }, - { "55", 503250 }, - { "56", 511250 }, - { "57", 519250 }, - { "58", 527250 }, - { "59", 535250 }, - { "60", 543250 }, - { "61", 551250 }, - { "62", 559250 }, - { "63", 607250 }, - { "64", 615250 }, - { "65", 623250 }, - { "66", 631250 }, - { "67", 639250 }, - { "68", 647250 }, - { "69", 655250 }, - { "70", 663250 }, - { "71", 671250 }, - { "72", 679250 }, - { "73", 687250 }, - { "74", 695250 }, - { "75", 703250 }, - { "76", 711250 }, - { "77", 719250 }, - { "78", 727250 }, - { "79", 735250 }, - { "80", 743250 }, - { "81", 751250 }, - { "82", 759250 }, - { "83", 767250 }, - { "84", 775250 }, - { "85", 783250 }, - { "86", 791250 }, - { "87", 799250 }, - { "88", 807250 }, - { "89", 815250 }, - { "90", 823250 }, - { "91", 831250 }, - { "92", 839250 }, - { "93", 847250 }, - { "94", 855250 }, -}; - -/* --------------------------------------------------------------------- */ -/* South Africa Broadcast */ - -static const struct CHANLIST pal_bcast_za[] ={ - { "1", 175250 }, - { "2", 183250 }, - { "3", 191250 }, - { "4", 199250 }, - { "5", 207250 }, - { "6", 215250 }, - { "7", 223250 }, - { "8", 231250 }, - FREQ_UHF -}; - -/* --------------------------------------------------------------------- */ - -static const struct CHANLIST argentina[] = { - { "001", 56250 }, - { "002", 62250 }, - { "003", 68250 }, - { "004", 78250 }, - { "005", 84250 }, - { "006", 176250 }, - { "007", 182250 }, - { "008", 188250 }, - { "009", 194250 }, - { "010", 200250 }, - { "011", 206250 }, - { "012", 212250 }, - { "013", 122250 }, - { "014", 128250 }, - { "015", 134250 }, - { "016", 140250 }, - { "017", 146250 }, - { "018", 152250 }, - { "019", 158250 }, - { "020", 164250 }, - { "021", 170250 }, - { "022", 218250 }, - { "023", 224250 }, - { "024", 230250 }, - { "025", 236250 }, - { "026", 242250 }, - { "027", 248250 }, - { "028", 254250 }, - { "029", 260250 }, - { "030", 266250 }, - { "031", 272250 }, - { "032", 278250 }, - { "033", 284250 }, - { "034", 290250 }, - { "035", 296250 }, - { "036", 302250 }, - { "037", 308250 }, - { "038", 314250 }, - { "039", 320250 }, - { "040", 326250 }, - { "041", 332250 }, - { "042", 338250 }, - { "043", 344250 }, - { "044", 350250 }, - { "045", 356250 }, - { "046", 362250 }, - { "047", 368250 }, - { "048", 374250 }, - { "049", 380250 }, - { "050", 386250 }, - { "051", 392250 }, - { "052", 398250 }, - { "053", 404250 }, - { "054", 410250 }, - { "055", 416250 }, - { "056", 422250 }, - { "057", 428250 }, - { "058", 434250 }, - { "059", 440250 }, - { "060", 446250 }, - { "061", 452250 }, - { "062", 458250 }, - { "063", 464250 }, - { "064", 470250 }, - { "065", 476250 }, - { "066", 482250 }, - { "067", 488250 }, - { "068", 494250 }, - { "069", 500250 }, - { "070", 506250 }, - { "071", 512250 }, - { "072", 518250 }, - { "073", 524250 }, - { "074", 530250 }, - { "075", 536250 }, - { "076", 542250 }, - { "077", 548250 }, - { "078", 554250 }, - { "079", 560250 }, - { "080", 566250 }, - { "081", 572250 }, - { "082", 578250 }, - { "083", 584250 }, - { "084", 590250 }, - { "085", 596250 }, - { "086", 602250 }, - { "087", 608250 }, - { "088", 614250 }, - { "089", 620250 }, - { "090", 626250 }, - { "091", 632250 }, - { "092", 638250 }, - { "093", 644250 }, -}; - -/* --------------------------------------------------------------------- */ - -static const struct CHANLIST russia[] = { - {"1", 49750 }, - {"2", 59250 }, - {"3", 77250 }, - {"4", 85250 }, - {"5", 93250 }, - {"SK1", 111250 }, - {"SK2", 119250 }, - {"SK3", 127250 }, - {"SK4", 135250 }, - {"SK5", 143250 }, - {"SK6", 151250 }, - {"SK7", 159250 }, - {"SK8", 167250 }, - {"6", 175250 }, - {"7", 183250 }, - {"8", 191250 }, - {"9", 199250 }, - {"10", 207250 }, - {"11", 215250 }, - {"12", 223250 }, - {"SK11", 231250 }, - {"SK12", 239250 }, - {"SK13", 247250 }, - {"SK14", 255250 }, - {"SK15", 263250 }, - {"SK16", 271250 }, - {"SK17", 279250 }, - {"SK18", 287250 }, - {"S19", 295250 }, - {"S20", 303250 }, - {"S21", 311250 }, - {"S22", 319250 }, - {"S23", 327250 }, - {"S24", 335250 }, - {"S25", 343250 }, - {"S26", 351250 }, - {"S27", 359250 }, - {"S28", 367250 }, - {"S29", 375250 }, - {"S30", 383250 }, - {"S31", 391250 }, - {"S32", 399250 }, - {"S33", 407250 }, - {"S34", 415250 }, - {"S35", 423250 }, - {"S36", 431250 }, - {"S37", 439250 }, - {"S38", 447250 }, - {"S39", 455250 }, - {"S40", 463250 }, - {"21", 471250 }, - {"22", 479250 }, - {"23", 487250 }, - {"24", 495250 }, - {"25", 503250 }, - {"26", 511250 }, - {"27", 519250 }, - {"28", 527250 }, - {"29", 535250 }, - {"30", 543250 }, - {"31", 551250 }, - {"32", 559250 }, - {"33", 567250 }, - {"34", 575250 }, - {"35", 583250 }, - {"36", 591250 }, - {"37", 599250 }, - {"38", 607250 }, - {"39", 615250 }, - {"40", 623250 }, - {"41", 631250 }, - {"42", 639250 }, - {"43", 647250 }, - {"44", 655250 }, - {"45", 663250 }, - {"46", 671250 }, - {"47", 679250 }, - {"48", 687250 }, - {"49", 695250 }, - {"50", 703250 }, - {"51", 711250 }, - {"52", 719250 }, - {"53", 727250 }, - {"54", 735250 }, - {"55", 743250 }, - {"56", 751250 }, - {"57", 759250 }, - {"58", 767250 }, - {"59", 775250 }, - {"60", 783250 }, - {"61", 791250 }, - {"62", 799250 }, - {"63", 807250 }, - {"64", 815250 }, - {"65", 523250 }, - {"66", 831250 }, - {"67", 839250 }, - {"68", 847250 }, - {"69", 855250 }, -}; -/* --------------------------------------------------------------------- */ - -const struct CHANLISTS chanlists[] = { - { "us-bcast", ntsc_bcast, CHAN_COUNT(ntsc_bcast) }, - { "us-cable", ntsc_cable, CHAN_COUNT(ntsc_cable) }, - { "us-cable-hrc", ntsc_hrc, CHAN_COUNT(ntsc_hrc) }, - { "japan-bcast", ntsc_bcast_jp, CHAN_COUNT(ntsc_bcast_jp) }, - { "japan-cable", ntsc_cable_jp, CHAN_COUNT(ntsc_cable_jp) }, - { "europe-west", europe_west, CHAN_COUNT(europe_west) }, - { "europe-east", europe_east, CHAN_COUNT(europe_east) }, - { "italy", pal_italy, CHAN_COUNT(pal_italy) }, - { "newzealand", pal_newzealand, CHAN_COUNT(pal_newzealand) }, - { "australia", pal_australia, CHAN_COUNT(pal_australia) }, - { "ireland", pal_ireland, CHAN_COUNT(pal_ireland) }, - { "france", secam_france, CHAN_COUNT(secam_france) }, - { "china-bcast", pal_bcast_cn, CHAN_COUNT(pal_bcast_cn) }, - { "southafrica", pal_bcast_za, CHAN_COUNT(pal_bcast_za) }, - { "argentina", argentina, CHAN_COUNT(argentina) }, - { "russia", russia, CHAN_COUNT(russia) }, - { NULL, NULL, 0 } /* EOF */ -}; - -const int chancount = CHAN_COUNT(europe_west); diff --git a/stream/frequencies.h b/stream/frequencies.h deleted file mode 100644 index e215d023b5..0000000000 --- a/stream/frequencies.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Worldwide channel/frequency list - * - * Nathan Laredo (laredo@broked.net) - * - * Frequencies are given in kHz - * - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#ifndef MPLAYER_FREQUENCIES_H -#define MPLAYER_FREQUENCIES_H - -#define NTSC_AUDIO_CARRIER 4500 -#define PAL_AUDIO_CARRIER_I 6000 -#define PAL_AUDIO_CARRIER_BGHN 5500 -#define PAL_AUDIO_CARRIER_MN 4500 -#define PAL_AUDIO_CARRIER_D 6500 -#define SEACAM_AUDIO_DKK1L 6500 -#define SEACAM_AUDIO_BG 5500 -/* NICAM 728 32-kHz, 14-bit digital stereo audio is transmitted in 1ms frames - containing 8 bits frame sync, 5 bits control, 11 bits additional data, and - 704 bits audio data. The bit rate is reduced by transmitting only 10 bits - plus parity of each 14 bit sample, the largest sample in a frame determines - which 10 bits are transmitted. The parity bits for audio samples also - specify the scaling factor used for that channel during that frame. The - companeded audio data is interleaved to reduce the influence of dropouts - and the whole frame except for sync bits is scrambled for spectrum shaping. - Data is modulated using QPSK, at below following subcarrier freqs */ -#define NICAM728_PAL_BGH 5850 -#define NICAM728_PAL_I 6552 - -/* COMPREHENSIVE LIST OF FORMAT BY COUNTRY - (M) NTSC used in: - Antigua, Aruba, Bahamas, Barbados, Belize, Bermuda, Bolivia, Burma, - Canada, Chile, Colombia, Costa Rica, Cuba, Curacao, Dominican Republic, - Ecuador, El Salvador, Guam Guatemala, Honduras, Jamaica, Japan, - South Korea, Mexico, Montserrat, Myanmar, Nicaragua, Panama, Peru, - Philippines, Puerto Rico, St Christopher and Nevis, Samoa, Suriname, - Taiwan, Trinidad/Tobago, United States, Venezuela, Virgin Islands - (B) PAL used in: - Albania, Algeria, Australia, Austria, Bahrain, Bangladesh, Belgium, - Bosnia-Herzegovinia, Brunei Darussalam, Cambodia, Cameroon, Croatia, - Cyprus, Denmark, Egypt, Ethiopia, Equatorial Guinea, Finland, Germany, - Ghana, Gibraltar, Greenland, Iceland, India, Indonesia, Israel, Italy, - Jordan, Kenya, Kuwait, Liberia, Libya, Luxembourg, Malaysa, Maldives, - Malta, Nepal, Netherlands, New Zeland, Nigeria, Norway, Oman, Pakistan, - Papua New Guinea, Portugal, Qatar, Sao Tome and Principe, Saudi Arabia, - Seychelles, Sierra Leone, Singapore, Slovenia, Somali, Spain, - Sri Lanka, Sudan, Swaziland, Sweden, Switzeland, Syria, Thailand, - Tunisia, Turkey, Uganda, United Arab Emirates, Yemen - (N) PAL used in: (Combination N = 4.5MHz audio carrier, 3.58MHz burst) - Argentina (Combination N), Paraguay, Uruguay - (M) PAL (525/60, 3.57MHz burst) used in: - Brazil - (G) PAL used in: - Albania, Algeria, Austria, Bahrain, Bosnia/Herzegovinia, Cambodia, - Cameroon, Croatia, Cyprus, Denmark, Egypt, Ethiopia, Equatorial Guinea, - Finland, Germany, Gibraltar, Greenland, Iceland, Israel, Italy, Jordan, - Kenya, Kuwait, Liberia, Libya, Luxembourg, Malaysia, Monaco, - Mozambique, Netherlands, New Zealand, Norway, Oman, Pakistan, - Papa New Guinea, Portugal, Qatar, Romania, Sierra Leone, Singapore, - Slovenia, Somalia, Spain, Sri Lanka, Sudan, Swaziland, Sweeden, - Switzerland, Syria, Thailand, Tunisia, Turkey, United Arab Emirates, - Yemen, Zambia, Zimbabwe - (D) PAL used in: - China, North Korea, Romania, Czech Republic - (H) PAL used in: - Belgium - (I) PAL used in: - Angola, Botswana, Gambia, Guinea-Bissau, Hong Kong, Ireland, Lesotho, - Malawi, Nambia, Nigeria, South Africa, Tanzania, United Kingdom, - Zanzibar - (B) SECAM used in: - Djibouti, Greece, Iran, Iraq, Lebanon, Mali, Mauritania, Mauritus, - Morocco - (D) SECAM used in: - Afghanistan, Armenia, Azerbaijan, Belarus, Bulgaria, - Estonia, Georgia, Hungary, Zazakhstan, Lithuania, Mongolia, Moldova, - Russia, Slovak Republic, Ukraine, Vietnam - (G) SECAM used in: - Greecem Iran, Iraq, Mali, Mauritus, Morocco, Saudi Arabia - (K) SECAM used in: - Armenia, Azerbaijan, Bulgaria, Estonia, Georgia, - Hungary, Kazakhstan, Lithuania, Madagascar, Moldova, Poland, Russia, - Slovak Republic, Ukraine, Vietnam - (K1) SECAM used in: - Benin, Burkina Faso, Burundi, Chad, Cape Verde, Central African - Republic, Comoros, Congo, Gabon, Madagascar, Niger, Rwanda, Senegal, - Togo, Zaire - (L) SECAM used in: - France -*/ - -/* --------------------------------------------------------------------- */ - -struct CHANLIST { - char name[8]; - int freq; -}; - -struct CHANLISTS { - const char *name; - const struct CHANLIST *list; - int count; -}; - -#define CHAN_COUNT(x) (sizeof(x)/sizeof(struct CHANLIST)) - -/* --------------------------------------------------------------------- */ - -extern const struct CHANLISTS chanlists[]; -extern const int chancount; - -#include "config.h" -#if !HAVE_GPL -#error GPL only -#endif - -#endif /* MPLAYER_FREQUENCIES_H */ diff --git a/stream/rar.c b/stream/rar.c deleted file mode 100644 index 9a74097ce7..0000000000 --- a/stream/rar.c +++ /dev/null @@ -1,451 +0,0 @@ -/***************************************************************************** - * rar.c: uncompressed RAR parser - ***************************************************************************** - * Copyright (C) 2008-2010 Laurent Aimar - * $Id: f368245f4260f913f5c211e09b7dd511a96525e6 $ - * - * Author: Laurent Aimar - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. - *****************************************************************************/ - -/***************************************************************************** - * Preamble - *****************************************************************************/ - -#include -#include -#include - -#include - -#include "mpv_talloc.h" -#include "common/common.h" -#include "stream.h" -#include "rar.h" - -static const uint8_t rar_marker[] = { - 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 -}; -static const int rar_marker_size = sizeof(rar_marker); - -void RarFileDelete(rar_file_t *file) -{ - for (int i = 0; i < file->chunk_count; i++) { - free(file->chunk[i]->mrl); - free(file->chunk[i]); - } - talloc_free(file->chunk); - free(file->name); - free_stream(file->s); - free(file); -} - -typedef struct { - uint16_t crc; - uint8_t type; - uint16_t flags; - uint16_t size; - uint32_t add_size; -} rar_block_t; - -enum { - RAR_BLOCK_MARKER = 0x72, - RAR_BLOCK_ARCHIVE = 0x73, - RAR_BLOCK_FILE = 0x74, - RAR_BLOCK_SUBBLOCK = 0x7a, - RAR_BLOCK_END = 0x7b, -}; -enum { - RAR_BLOCK_END_HAS_NEXT = 0x0001, -}; -enum { - RAR_BLOCK_FILE_HAS_PREVIOUS = 0x0001, - RAR_BLOCK_FILE_HAS_NEXT = 0x0002, - RAR_BLOCK_FILE_HAS_HIGH = 0x0100, -}; - -static int PeekBlock(struct stream *s, rar_block_t *hdr) -{ - bstr data = stream_peek(s, 11); - const uint8_t *peek = (uint8_t *)data.start; - int peek_size = data.len; - - if (peek_size < 7) - return -1; - - hdr->crc = AV_RL16(&peek[0]); - hdr->type = peek[2]; - hdr->flags = AV_RL16(&peek[3]); - hdr->size = AV_RL16(&peek[5]); - hdr->add_size = 0; - if ((hdr->flags & 0x8000) || - hdr->type == RAR_BLOCK_FILE || - hdr->type == RAR_BLOCK_SUBBLOCK) { - if (peek_size < 11) - return -1; - hdr->add_size = AV_RL32(&peek[7]); - } - - if (hdr->size < 7) - return -1; - return 0; -} -static int SkipBlock(struct stream *s, const rar_block_t *hdr) -{ - uint64_t size = (uint64_t)hdr->size + hdr->add_size; - - while (size > 0) { - int skip = MPMIN(size, INT_MAX); - if (!stream_skip(s, skip)) - return -1; - - size -= skip; - } - return 0; -} - -static int IgnoreBlock(struct stream *s, int block) -{ - /* */ - rar_block_t bk; - if (PeekBlock(s, &bk) || bk.type != block) - return -1; - return SkipBlock(s, &bk); -} - -static int SkipEnd(struct stream *s, const rar_block_t *hdr) -{ - if (!(hdr->flags & RAR_BLOCK_END_HAS_NEXT)) - return -1; - - if (SkipBlock(s, hdr)) - return -1; - - /* Now, we need to look for a marker block, - * It seems that there is garbage at EOF */ - for (;;) { - bstr peek = stream_peek(s, rar_marker_size); - - if (peek.len < rar_marker_size) - return -1; - - if (!memcmp(peek.start, rar_marker, rar_marker_size)) - break; - - if (!stream_skip(s, 1)) - return -1; - } - - /* Skip marker and archive blocks */ - if (IgnoreBlock(s, RAR_BLOCK_MARKER)) - return -1; - if (IgnoreBlock(s, RAR_BLOCK_ARCHIVE)) - return -1; - - return 0; -} - -static int SkipFile(struct stream *s, int *count, rar_file_t ***file, - const rar_block_t *hdr, const char *volume_mrl) -{ - int min_size = 7+21; - if (hdr->flags & RAR_BLOCK_FILE_HAS_HIGH) - min_size += 8; - if (hdr->size < (unsigned)min_size) - return -1; - - bstr data = stream_peek(s, min_size); - if (data.len < min_size) - return -1; - const uint8_t *peek = (uint8_t *)data.start; - - /* */ - uint32_t file_size_low = AV_RL32(&peek[7+4]); - uint8_t method = peek[7+18]; - uint16_t name_size = AV_RL16(&peek[7+19]); - uint32_t file_size_high = 0; - if (hdr->flags & RAR_BLOCK_FILE_HAS_HIGH) - file_size_high = AV_RL32(&peek[7+29]); - const uint64_t file_size = ((uint64_t)file_size_high << 32) | file_size_low; - - char *name = calloc(1, name_size + 1); - if (!name) - return -1; - - const int name_offset = (hdr->flags & RAR_BLOCK_FILE_HAS_HIGH) ? (7+33) : (7+25); - if (name_offset + name_size <= hdr->size) { - const int max_size = name_offset + name_size; - bstr namedata = stream_peek(s, max_size); - if (namedata.len < max_size) { - free(name); - return -1; - } - memcpy(name, &namedata.start[name_offset], name_size); - } - - rar_file_t *current = NULL; - if (method != 0x30) { - MP_WARN(s, "Ignoring compressed file %s (method=0x%2.2x)\n", name, method); - goto exit; - } - - /* */ - if( *count > 0 ) - current = (*file)[*count - 1]; - - if (current && - (current->is_complete || - strcmp(current->name, name) || - (hdr->flags & RAR_BLOCK_FILE_HAS_PREVIOUS) == 0)) - current = NULL; - - if (!current) { - if (hdr->flags & RAR_BLOCK_FILE_HAS_PREVIOUS) - goto exit; - current = calloc(1, sizeof(*current)); - if (!current) - goto exit; - MP_TARRAY_APPEND(NULL, *file, *count, current); - - current->name = name; - current->size = file_size; - current->is_complete = false; - current->real_size = 0; - current->chunk_count = 0; - current->chunk = NULL; - - name = NULL; - } - - /* Append chunks */ - rar_file_chunk_t *chunk = malloc(sizeof(*chunk)); - if (chunk) { - chunk->mrl = strdup(volume_mrl); - chunk->offset = stream_tell(s) + hdr->size; - chunk->size = hdr->add_size; - chunk->cummulated_size = 0; - if (current->chunk_count > 0) { - rar_file_chunk_t *previous = current->chunk[current->chunk_count-1]; - - chunk->cummulated_size += previous->cummulated_size + - previous->size; - } - - MP_TARRAY_APPEND(NULL, current->chunk, current->chunk_count, chunk); - - current->real_size += hdr->add_size; - } - if ((hdr->flags & RAR_BLOCK_FILE_HAS_NEXT) == 0) - current->is_complete = true; - -exit: - /* */ - free(name); - - /* We stop on the first non empty file if we cannot seek */ - if (current) { - if (!s->seekable && current->size > 0) - return -1; - } - - if (SkipBlock(s, hdr)) - return -1; - return 0; -} - -int RarProbe(struct stream *s) -{ - bstr peek = stream_peek(s, rar_marker_size); - if (peek.len < rar_marker_size) - return -1; - if (memcmp(peek.start, rar_marker, rar_marker_size)) - return -1; - return 0; -} - -typedef struct { - const char *match; - const char *format; - int start; - int stop; -} rar_pattern_t; - -static const rar_pattern_t *FindVolumePattern(const char *location) -{ - static const rar_pattern_t patterns[] = { - { ".part1.rar", "%s.part%.1d.rar", 2, 9 }, - { ".part01.rar", "%s.part%.2d.rar", 2, 99, }, - { ".part001.rar", "%s.part%.3d.rar", 2, 999 }, - { ".rar", "%s.%c%.2d", 0, 999 }, - { NULL, NULL, 0, 0 }, - }; - - const size_t location_size = strlen(location); - for (int i = 0; patterns[i].match != NULL; i++) { - const size_t match_size = strlen(patterns[i].match); - - if (location_size < match_size) - continue; - if (!strcmp(&location[location_size - match_size], patterns[i].match)) - return &patterns[i]; - } - return NULL; -} - -int RarParse(struct stream *s, int *count, rar_file_t ***file) -{ - *count = 0; - *file = NULL; - - const rar_pattern_t *pattern = FindVolumePattern(s->url); - int volume_offset = 0; - - char *volume_mrl; - if (asprintf(&volume_mrl, "%s", s->url) < 0) - return -1; - - struct stream *vol = s; - for (;;) { - /* Skip marker & archive */ - if (IgnoreBlock(vol, RAR_BLOCK_MARKER) || - IgnoreBlock(vol, RAR_BLOCK_ARCHIVE)) { - if (vol != s) - free_stream(vol); - free(volume_mrl); - return -1; - } - - /* */ - int has_next = -1; - for (;;) { - rar_block_t bk; - int ret; - - if (PeekBlock(vol, &bk)) - break; - - switch(bk.type) { - case RAR_BLOCK_END: - ret = SkipEnd(vol, &bk); - has_next = ret && (bk.flags & RAR_BLOCK_END_HAS_NEXT); - break; - case RAR_BLOCK_FILE: - ret = SkipFile(vol, count, file, &bk, volume_mrl); - break; - default: - ret = SkipBlock(vol, &bk); - break; - } - if (ret) - break; - } - if (has_next < 0 && *count > 0 && !(*file)[*count -1]->is_complete) - has_next = 1; - if (vol != s) - free_stream(vol); - - if (!has_next || !pattern) - goto done; - - /* Open next volume */ - const int volume_index = pattern->start + volume_offset++; - if (volume_index > pattern->stop) - goto done; - - char *volume_base; - if (asprintf(&volume_base, "%.*s", - (int)(strlen(s->url) - strlen(pattern->match)), s->url) < 0) { - goto done; - } - - free(volume_mrl); - if (pattern->start) { - if (asprintf(&volume_mrl, pattern->format, volume_base, volume_index) < 0) - volume_mrl = NULL; - } else { - if (asprintf(&volume_mrl, pattern->format, volume_base, - 'r' + volume_index / 100, volume_index % 100) < 0) - volume_mrl = NULL; - } - free(volume_base); - - if (!volume_mrl) - goto done; - - vol = stream_create(volume_mrl, STREAM_READ, s->cancel, s->global); - - if (!vol) - goto done; - } - -done: - free(volume_mrl); - if (*count == 0) { - talloc_free(*file); - return -1; - } - return 0; -} - -int RarSeek(rar_file_t *file, uint64_t position) -{ - if (position > file->real_size) - position = file->real_size; - - /* Search the chunk */ - const rar_file_chunk_t *old_chunk = file->current_chunk; - for (int i = 0; i < file->chunk_count; i++) { - file->current_chunk = file->chunk[i]; - if (position < file->current_chunk->cummulated_size + file->current_chunk->size) - break; - } - file->i_pos = position; - - const uint64_t offset = file->current_chunk->offset + - (position - file->current_chunk->cummulated_size); - - if (strcmp(old_chunk->mrl, file->current_chunk->mrl)) { - if (file->s) - free_stream(file->s); - file->s = stream_create(file->current_chunk->mrl, STREAM_READ, - file->cancel, file->global); - } - return file->s ? stream_seek(file->s, offset) : 0; -} - -ssize_t RarRead(rar_file_t *file, void *data, size_t size) -{ - size_t total = 0; - while (total < size) { - const uint64_t chunk_end = file->current_chunk->cummulated_size + file->current_chunk->size; - int max = MPMIN(MPMIN((int64_t)(size - total), (int64_t)(chunk_end - file->i_pos)), INT_MAX); - if (max <= 0) - break; - - int r = stream_read(file->s, data, max); - if (r <= 0) - break; - - total += r; - data = (char *)data + r; - file->i_pos += r; - if (file->i_pos >= chunk_end && - RarSeek(file, file->i_pos)) - break; - } - return total; - -} diff --git a/stream/rar.h b/stream/rar.h deleted file mode 100644 index f7f80a8177..0000000000 --- a/stream/rar.h +++ /dev/null @@ -1,61 +0,0 @@ -/***************************************************************************** - * rar.h: uncompressed RAR parser - ***************************************************************************** - * Copyright (C) 2008-2010 Laurent Aimar - * $Id: 4dea45925c2d8f319d692475bc0307fdd9f6cfe7 $ - * - * Author: Laurent Aimar - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. - *****************************************************************************/ - -#ifndef MP_RAR_H -#define MP_RAR_H - -#include -#include - -typedef struct { - char *mrl; - uint64_t offset; - uint64_t size; - uint64_t cummulated_size; -} rar_file_chunk_t; - -typedef struct { - char *name; - uint64_t size; - bool is_complete; - - int chunk_count; - rar_file_chunk_t **chunk; - uint64_t real_size; /* Gathered size */ - - // When actually reading the data - struct mpv_global *global; - struct mp_cancel *cancel; - uint64_t i_pos; - stream_t *s; - rar_file_chunk_t *current_chunk; -} rar_file_t; - -int RarProbe(struct stream *); -void RarFileDelete(rar_file_t *); -int RarParse(struct stream *, int *, rar_file_t ***); - -int RarSeek(rar_file_t *file, uint64_t position); -ssize_t RarRead(rar_file_t *file, void *data, size_t size); - -#endif diff --git a/stream/stream.c b/stream/stream.c index 7d093e1913..2b586fcd8c 100644 --- a/stream/stream.c +++ b/stream/stream.c @@ -45,10 +45,6 @@ // Includes additional padding in case sizes get rounded up by sector size. #define TOTAL_BUFFER_SIZE (STREAM_MAX_BUFFER_SIZE + STREAM_MAX_SECTOR_SIZE) -extern const stream_info_t stream_info_cdda; -extern const stream_info_t stream_info_dvb; -extern const stream_info_t stream_info_tv; -extern const stream_info_t stream_info_smb; extern const stream_info_t stream_info_null; extern const stream_info_t stream_info_memory; extern const stream_info_t stream_info_mf; @@ -56,56 +52,21 @@ extern const stream_info_t stream_info_ffmpeg; extern const stream_info_t stream_info_ffmpeg_unsafe; extern const stream_info_t stream_info_avdevice; extern const stream_info_t stream_info_file; -extern const stream_info_t stream_info_ifo; -extern const stream_info_t stream_info_ifo_dvdnav; -extern const stream_info_t stream_info_dvd; -extern const stream_info_t stream_info_dvdnav; -extern const stream_info_t stream_info_bdmv_dir; -extern const stream_info_t stream_info_bluray; -extern const stream_info_t stream_info_bdnav; -extern const stream_info_t stream_info_rar; extern const stream_info_t stream_info_edl; extern const stream_info_t stream_info_libarchive; extern const stream_info_t stream_info_cb; static const stream_info_t *const stream_list[] = { -#if HAVE_CDDA - &stream_info_cdda, -#endif &stream_info_ffmpeg, &stream_info_ffmpeg_unsafe, &stream_info_avdevice, -#if HAVE_DVBIN - &stream_info_dvb, -#endif -#if HAVE_TV - &stream_info_tv, -#endif -#if HAVE_LIBSMBCLIENT - &stream_info_smb, -#endif -#if HAVE_DVDREAD || HAVE_DVDNAV - &stream_info_ifo, - &stream_info_dvd, -#endif -#if HAVE_DVDNAV - &stream_info_ifo_dvdnav, - &stream_info_dvdnav, -#endif -#if HAVE_LIBBLURAY - &stream_info_bdmv_dir, - &stream_info_bluray, - &stream_info_bdnav, -#endif #if HAVE_LIBARCHIVE &stream_info_libarchive, #endif - &stream_info_memory, &stream_info_null, &stream_info_mf, &stream_info_edl, - &stream_info_rar, &stream_info_file, &stream_info_cb, NULL diff --git a/stream/stream.h b/stream/stream.h index c91843de8a..8ffc05ddab 100644 --- a/stream/stream.h +++ b/stream/stream.h @@ -55,48 +55,13 @@ enum stream_ctrl { // stream_memory.c STREAM_CTRL_SET_CONTENTS, - // stream_rar.c + // stream_libarchive.c STREAM_CTRL_GET_BASE_FILENAME, // Certain network protocols STREAM_CTRL_AVSEEK, STREAM_CTRL_HAS_AVSEEK, STREAM_CTRL_GET_METADATA, - - // TV - STREAM_CTRL_TV_SET_SCAN, - STREAM_CTRL_SET_TV_FREQ, - STREAM_CTRL_GET_TV_FREQ, - STREAM_CTRL_SET_TV_COLORS, - STREAM_CTRL_GET_TV_COLORS, - STREAM_CTRL_TV_SET_NORM, - STREAM_CTRL_TV_STEP_NORM, - STREAM_CTRL_TV_SET_CHAN, - STREAM_CTRL_TV_GET_CHAN, - STREAM_CTRL_TV_STEP_CHAN, - STREAM_CTRL_TV_LAST_CHAN, - STREAM_CTRL_DVB_SET_CHANNEL, - STREAM_CTRL_DVB_SET_CHANNEL_NAME, - STREAM_CTRL_DVB_GET_CHANNEL_NAME, - STREAM_CTRL_DVB_STEP_CHANNEL, - - // Optical discs - STREAM_CTRL_GET_TIME_LENGTH, - STREAM_CTRL_GET_DVD_INFO, - STREAM_CTRL_GET_DISC_NAME, - STREAM_CTRL_GET_NUM_CHAPTERS, - STREAM_CTRL_GET_CURRENT_TIME, - STREAM_CTRL_GET_CHAPTER_TIME, - STREAM_CTRL_SEEK_TO_TIME, - STREAM_CTRL_GET_ASPECT_RATIO, - STREAM_CTRL_GET_NUM_ANGLES, - STREAM_CTRL_GET_ANGLE, - STREAM_CTRL_SET_ANGLE, - STREAM_CTRL_GET_NUM_TITLES, - STREAM_CTRL_GET_TITLE_LENGTH, // double* (in: title number, out: len) - STREAM_CTRL_GET_LANG, - STREAM_CTRL_GET_CURRENT_TITLE, - STREAM_CTRL_SET_CURRENT_TITLE, }; struct stream_lang_req { @@ -110,12 +75,6 @@ struct stream_dvd_info_req { int num_subs; }; -// for STREAM_CTRL_SET_TV_COLORS -#define TV_COLOR_BRIGHTNESS 1 -#define TV_COLOR_HUE 2 -#define TV_COLOR_SATURATION 3 -#define TV_COLOR_CONTRAST 4 - // for STREAM_CTRL_AVSEEK struct stream_avseek { int stream_index; diff --git a/stream/stream_bluray.c b/stream/stream_bluray.c deleted file mode 100644 index f26420b56d..0000000000 --- a/stream/stream_bluray.c +++ /dev/null @@ -1,612 +0,0 @@ -/* - * Copyright (C) 2010 Benjamin Zores - * - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * mpv 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with mpv. If not, see . - */ - -/* - * Blu-ray parser/reader using libbluray - * Use 'git clone git://git.videolan.org/libbluray' to get it. - * - * TODO: - * - Add descrambled keys database support (KEYDB.cfg) - * - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "mpv_talloc.h" -#include "common/common.h" -#include "common/msg.h" -#include "options/m_config.h" -#include "options/path.h" -#include "stream.h" -#include "osdep/timer.h" -#include "sub/osd.h" -#include "sub/img_convert.h" -#include "video/mp_image.h" - -#define BLURAY_SECTOR_SIZE 6144 - -#define BLURAY_DEFAULT_ANGLE 0 -#define BLURAY_DEFAULT_CHAPTER 0 -#define BLURAY_PLAYLIST_TITLE -3 -#define BLURAY_DEFAULT_TITLE -2 -#define BLURAY_MENU_TITLE -1 - -// 90khz ticks -#define BD_TIMEBASE (90000) -#define BD_TIME_TO_MP(x) ((x) / (double)(BD_TIMEBASE)) -#define BD_TIME_FROM_MP(x) ((uint64_t)(x * BD_TIMEBASE)) - -// copied from aacs.h in libaacs -#define AACS_ERROR_CORRUPTED_DISC -1 /* opening or reading of AACS files failed */ -#define AACS_ERROR_NO_CONFIG -2 /* missing config file */ -#define AACS_ERROR_NO_PK -3 /* no matching processing key */ -#define AACS_ERROR_NO_CERT -4 /* no valid certificate */ -#define AACS_ERROR_CERT_REVOKED -5 /* certificate has been revoked */ -#define AACS_ERROR_MMC_OPEN -6 /* MMC open failed (no MMC drive ?) */ -#define AACS_ERROR_MMC_FAILURE -7 /* MMC failed */ -#define AACS_ERROR_NO_DK -8 /* no matching device key */ - -struct bluray_priv_s { - BLURAY *bd; - BLURAY_TITLE_INFO *title_info; - int num_titles; - int current_angle; - int current_title; - int current_playlist; - - int cfg_title; - int cfg_playlist; - char *cfg_device; - - bool use_nav; -}; - -static void destruct(struct bluray_priv_s *priv) -{ - if (priv->title_info) - bd_free_title_info(priv->title_info); - bd_close(priv->bd); -} - -inline static int play_playlist(struct bluray_priv_s *priv, int playlist) -{ - return bd_select_playlist(priv->bd, playlist); -} - -inline static int play_title(struct bluray_priv_s *priv, int title) -{ - return bd_select_title(priv->bd, title); -} - -static void bluray_stream_close(stream_t *s) -{ - destruct(s->priv); -} - -static void handle_event(stream_t *s, const BD_EVENT *ev) -{ - struct bluray_priv_s *b = s->priv; - switch (ev->event) { - case BD_EVENT_MENU: - break; - case BD_EVENT_STILL: - break; - case BD_EVENT_STILL_TIME: - bd_read_skip_still(b->bd); - break; - case BD_EVENT_END_OF_TITLE: - break; - case BD_EVENT_PLAYLIST: - b->current_playlist = ev->param; - b->current_title = bd_get_current_title(b->bd); - if (b->title_info) - bd_free_title_info(b->title_info); - b->title_info = bd_get_playlist_info(b->bd, b->current_playlist, - b->current_angle); - break; - case BD_EVENT_TITLE: - if (ev->param == BLURAY_TITLE_FIRST_PLAY) { - b->current_title = bd_get_current_title(b->bd); - } else - b->current_title = ev->param; - if (b->title_info) { - bd_free_title_info(b->title_info); - b->title_info = NULL; - } - break; - case BD_EVENT_ANGLE: - b->current_angle = ev->param; - if (b->title_info) { - bd_free_title_info(b->title_info); - b->title_info = bd_get_playlist_info(b->bd, b->current_playlist, - b->current_angle); - } - break; - case BD_EVENT_POPUP: - break; -#if BLURAY_VERSION >= BLURAY_VERSION_CODE(0, 5, 0) - case BD_EVENT_DISCONTINUITY: - break; -#endif - default: - MP_TRACE(s, "Unhandled event: %d %d\n", ev->event, ev->param); - break; - } -} - -static int bluray_stream_fill_buffer(stream_t *s, char *buf, int len) -{ - struct bluray_priv_s *b = s->priv; - BD_EVENT event; - while (bd_get_event(b->bd, &event)) - handle_event(s, &event); - return bd_read(b->bd, buf, len); -} - -static int bluray_stream_control(stream_t *s, int cmd, void *arg) -{ - struct bluray_priv_s *b = s->priv; - - switch (cmd) { - case STREAM_CTRL_GET_NUM_CHAPTERS: { - const BLURAY_TITLE_INFO *ti = b->title_info; - if (!ti) - return STREAM_UNSUPPORTED; - *((unsigned int *) arg) = ti->chapter_count; - return STREAM_OK; - } - case STREAM_CTRL_GET_CHAPTER_TIME: { - const BLURAY_TITLE_INFO *ti = b->title_info; - if (!ti) - return STREAM_UNSUPPORTED; - int chapter = *(double *)arg; - double time = MP_NOPTS_VALUE; - if (chapter >= 0 || chapter < ti->chapter_count) - time = BD_TIME_TO_MP(ti->chapters[chapter].start); - if (time == MP_NOPTS_VALUE) - return STREAM_ERROR; - *(double *)arg = time; - return STREAM_OK; - } - case STREAM_CTRL_SET_CURRENT_TITLE: { - const uint32_t title = *((unsigned int*)arg); - if (title >= b->num_titles || !play_title(b, title)) - return STREAM_UNSUPPORTED; - b->current_title = title; - return STREAM_OK; - } - case STREAM_CTRL_GET_CURRENT_TITLE: { - *((unsigned int *) arg) = b->current_title; - return STREAM_OK; - } - case STREAM_CTRL_GET_NUM_TITLES: { - *((unsigned int *)arg) = b->num_titles; - return STREAM_OK; - } - case STREAM_CTRL_GET_TIME_LENGTH: { - const BLURAY_TITLE_INFO *ti = b->title_info; - if (!ti) - return STREAM_UNSUPPORTED; - *((double *) arg) = BD_TIME_TO_MP(ti->duration); - return STREAM_OK; - } - case STREAM_CTRL_GET_CURRENT_TIME: { - *((double *) arg) = BD_TIME_TO_MP(bd_tell_time(b->bd)); - return STREAM_OK; - } - case STREAM_CTRL_SEEK_TO_TIME: { - double pts = *((double *) arg); - bd_seek_time(b->bd, BD_TIME_FROM_MP(pts)); - stream_drop_buffers(s); - // API makes it hard to determine seeking success - return STREAM_OK; - } - case STREAM_CTRL_GET_NUM_ANGLES: { - const BLURAY_TITLE_INFO *ti = b->title_info; - if (!ti) - return STREAM_UNSUPPORTED; - *((int *) arg) = ti->angle_count; - return STREAM_OK; - } - case STREAM_CTRL_GET_ANGLE: { - *((int *) arg) = b->current_angle; - return STREAM_OK; - } - case STREAM_CTRL_SET_ANGLE: { - const BLURAY_TITLE_INFO *ti = b->title_info; - if (!ti) - return STREAM_UNSUPPORTED; - int angle = *((int *) arg); - if (angle < 0 || angle > ti->angle_count) - return STREAM_UNSUPPORTED; - b->current_angle = angle; - bd_seamless_angle_change(b->bd, angle); - return STREAM_OK; - } - case STREAM_CTRL_GET_LANG: { - const BLURAY_TITLE_INFO *ti = b->title_info; - if (ti && ti->clip_count) { - struct stream_lang_req *req = arg; - BLURAY_STREAM_INFO *si = NULL; - int count = 0; - switch (req->type) { - case STREAM_AUDIO: - count = ti->clips[0].audio_stream_count; - si = ti->clips[0].audio_streams; - break; - case STREAM_SUB: - count = ti->clips[0].pg_stream_count; - si = ti->clips[0].pg_streams; - break; - } - for (int n = 0; n < count; n++) { - BLURAY_STREAM_INFO *i = &si[n]; - if (i->pid == req->id) { - snprintf(req->name, sizeof(req->name), "%.4s", i->lang); - return STREAM_OK; - } - } - } - return STREAM_ERROR; - } - case STREAM_CTRL_GET_DISC_NAME: { - const struct meta_dl *meta = bd_get_meta(b->bd); - if (!meta || !meta->di_name || !meta->di_name[0]) - break; - *(char**)arg = talloc_strdup(NULL, meta->di_name); - return STREAM_OK; - } - case STREAM_CTRL_GET_SIZE: - *(int64_t *)arg = bd_get_title_size(b->bd); - return STREAM_OK; - default: - break; - } - - return STREAM_UNSUPPORTED; -} - -static const char *aacs_strerr(int err) -{ - switch (err) { - case AACS_ERROR_CORRUPTED_DISC: return "opening or reading of AACS files failed"; - case AACS_ERROR_NO_CONFIG: return "missing config file"; - case AACS_ERROR_NO_PK: return "no matching processing key"; - case AACS_ERROR_NO_CERT: return "no valid certificate"; - case AACS_ERROR_CERT_REVOKED: return "certificate has been revoked"; - case AACS_ERROR_MMC_OPEN: return "MMC open failed (maybe no MMC drive?)"; - case AACS_ERROR_MMC_FAILURE: return "MMC failed"; - case AACS_ERROR_NO_DK: return "no matching device key"; - default: return "unknown error"; - } -} - -static bool check_disc_info(stream_t *s) -{ - struct bluray_priv_s *b = s->priv; - const BLURAY_DISC_INFO *info = bd_get_disc_info(b->bd); - - // check Blu-ray - if (!info->bluray_detected) { - MP_ERR(s, "Given stream is not a Blu-ray.\n"); - return false; - } - - // check AACS - if (info->aacs_detected) { - if (!info->libaacs_detected) { - MP_ERR(s, "AACS encryption detected but cannot find libaacs.\n"); - return false; - } - if (!info->aacs_handled) { - MP_ERR(s, "AACS error: %s\n", aacs_strerr(info->aacs_error_code)); - return false; - } - } - - // check BD+ - if (info->bdplus_detected) { - if (!info->libbdplus_detected) { - MP_ERR(s, "BD+ encryption detected but cannot find libbdplus.\n"); - return false; - } - if (!info->bdplus_handled) { - MP_ERR(s, "Cannot decrypt BD+ encryption.\n"); - return false; - } - } - - return true; -} - -static void select_initial_title(stream_t *s, int title_guess) { - struct bluray_priv_s *b = s->priv; - - if (b->cfg_title == BLURAY_PLAYLIST_TITLE) { - if (!play_playlist(b, b->cfg_playlist)) - MP_WARN(s, "Couldn't start playlist '%05d'.\n", b->cfg_playlist); - b->current_title = bd_get_current_title(b->bd); - } else { - int title = -1; - if (b->cfg_title != BLURAY_DEFAULT_TITLE ) - title = b->cfg_title; - else - title = title_guess; - if (title < 0) - return; - - if (play_title(b, title)) - b->current_title = title; - else { - MP_WARN(s, "Couldn't start title '%d'.\n", title); - b->current_title = bd_get_current_title(b->bd); - } - } -} - -static int bluray_stream_open_internal(stream_t *s) -{ - struct bluray_priv_s *b = s->priv; - - char *device = NULL; - /* find the requested device */ - if (b->cfg_device && b->cfg_device[0]) { - device = b->cfg_device; - } else { - mp_read_option_raw(s->global, "bluray-device", &m_option_type_string, - &device); - } - - if (!device || !device[0]) { - MP_ERR(s, "No Blu-ray device/location was specified ...\n"); - return STREAM_UNSUPPORTED; - } - - if (!mp_msg_test(s->log, MSGL_DEBUG)) - bd_set_debug_mask(0); - - /* open device */ - BLURAY *bd = bd_open(device, NULL); - if (!bd) { - MP_ERR(s, "Couldn't open Blu-ray device: %s\n", device); - return STREAM_UNSUPPORTED; - } - b->bd = bd; - - if (!check_disc_info(s)) { - destruct(b); - return STREAM_UNSUPPORTED; - } - - int title_guess = BLURAY_DEFAULT_TITLE; - if (b->use_nav) { - MP_FATAL(s, "BluRay menu support has been removed.\n"); - return STREAM_ERROR; - } else { - /* check for available titles on disc */ - b->num_titles = bd_get_titles(bd, TITLES_RELEVANT, 0); - if (!b->num_titles) { - MP_ERR(s, "Can't find any Blu-ray-compatible title here.\n"); - destruct(b); - return STREAM_UNSUPPORTED; - } - - MP_INFO(s, "List of available titles:\n"); - - /* parse titles information */ - uint64_t max_duration = 0; - for (int i = 0; i < b->num_titles; i++) { - BLURAY_TITLE_INFO *ti = bd_get_title_info(bd, i, 0); - if (!ti) - continue; - - char *time = mp_format_time(ti->duration / 90000, false); - MP_INFO(s, "idx: %3d duration: %s (playlist: %05d.mpls)\n", - i, time, ti->playlist); - talloc_free(time); - - /* try to guess which title may contain the main movie */ - if (ti->duration > max_duration) { - max_duration = ti->duration; - title_guess = i; - } - - bd_free_title_info(ti); - } - } - - // these should be set before any callback - b->current_angle = -1; - b->current_title = -1; - - // initialize libbluray event queue - bd_get_event(bd, NULL); - - select_initial_title(s, title_guess); - - s->fill_buffer = bluray_stream_fill_buffer; - s->close = bluray_stream_close; - s->control = bluray_stream_control; - s->sector_size = BLURAY_SECTOR_SIZE; - s->priv = b; - s->demuxer = "+disc"; - - MP_VERBOSE(s, "Blu-ray successfully opened.\n"); - - return STREAM_OK; -} - -const stream_info_t stream_info_bdnav; - -static int bluray_stream_open(stream_t *s) -{ - struct bluray_priv_s *b = talloc_zero(s, struct bluray_priv_s); - s->priv = b; - - b->use_nav = s->info == &stream_info_bdnav; - - bstr title, bdevice, rest = { .len = 0 }; - bstr_split_tok(bstr0(s->path), "/", &title, &bdevice); - - b->cfg_title = BLURAY_DEFAULT_TITLE; - - if (bstr_equals0(title, "longest") || bstr_equals0(title, "first")) { - b->cfg_title = BLURAY_DEFAULT_TITLE; - } else if (bstr_equals0(title, "menu")) { - b->cfg_title = BLURAY_MENU_TITLE; - } else if (bstr_equals0(title, "mpls")) { - bstr_split_tok(bdevice, "/", &title, &bdevice); - long long pl = bstrtoll(title, &rest, 10); - if (rest.len) { - MP_ERR(s, "number expected: '%.*s'\n", BSTR_P(rest)); - return STREAM_ERROR; - } else if (pl < 0 || 99999 < pl) { - MP_ERR(s, "invalid playlist: '%.*s', must be in the range 0-99999\n", - BSTR_P(title)); - return STREAM_ERROR; - } - b->cfg_playlist = pl; - b->cfg_title = BLURAY_PLAYLIST_TITLE; - } else if (title.len) { - long long t = bstrtoll(title, &rest, 10); - if (rest.len) { - MP_ERR(s, "number expected: '%.*s'\n", BSTR_P(rest)); - return STREAM_ERROR; - } else if (t < 0 || 99999 < t) { - MP_ERR(s, "invalid title: '%.*s', must be in the range 0-99999\n", - BSTR_P(title)); - return STREAM_ERROR; - } - b->cfg_title = t; - } - - b->cfg_device = bstrto0(b, bdevice); - - return bluray_stream_open_internal(s); -} - -const stream_info_t stream_info_bluray = { - .name = "bd", - .open = bluray_stream_open, - .protocols = (const char*const[]){ "bd", "br", "bluray", NULL }, -}; - -const stream_info_t stream_info_bdnav = { - .name = "bdnav", - .open = bluray_stream_open, - .protocols = (const char*const[]){ "bdnav", "brnav", "bluraynav", NULL }, -}; - -static bool check_bdmv(const char *path) -{ - if (strcasecmp(mp_basename(path), "MovieObject.bdmv")) - return false; - - FILE *temp = fopen(path, "rb"); - if (!temp) - return false; - - char data[50] = {0}; - - fread(data, 50, 1, temp); - fclose(temp); - - bstr bdata = {data, 50}; - - return bstr_startswith0(bdata, "MOBJ0100") || // AVCHD - bstr_startswith0(bdata, "MOBJ0200") || // Blu-ray - bstr_startswith0(bdata, "MOBJ0300"); // UHD BD -} - -// Destructively remove the current trailing path component. -static void remove_prefix(char *path) -{ - size_t len = strlen(path); -#if HAVE_DOS_PATHS - const char *seps = "/\\"; -#else - const char *seps = "/"; -#endif - while (len > 0 && !strchr(seps, path[len - 1])) - len--; - while (len > 0 && strchr(seps, path[len - 1])) - len--; - path[len] = '\0'; -} - -static int bdmv_dir_stream_open(stream_t *stream) -{ - struct bluray_priv_s *priv = talloc_ptrtype(stream, priv); - stream->priv = priv; - *priv = (struct bluray_priv_s){ - .cfg_title = BLURAY_DEFAULT_TITLE, - }; - - if (!stream->access_references) - goto unsupported; - - char *path = mp_file_get_path(priv, bstr0(stream->url)); - if (!path) - goto unsupported; - - // We allow the path to point to a directory containing BDMV/, a - // directory containing MovieObject.bdmv, or that file itself. - if (!check_bdmv(path)) { - // On UNIX, just assume the filename has always this case. - char *npath = mp_path_join(priv, path, "MovieObject.bdmv"); - if (!check_bdmv(npath)) { - npath = mp_path_join(priv, path, "BDMV/MovieObject.bdmv"); - if (!check_bdmv(npath)) - goto unsupported; - } - path = npath; - } - - // Go up by 2 levels. - remove_prefix(path); - remove_prefix(path); - priv->cfg_device = path; - if (strlen(priv->cfg_device) <= 1) - goto unsupported; - - MP_INFO(stream, "BDMV detected. Redirecting to bluray://\n"); - return bluray_stream_open_internal(stream); - -unsupported: - talloc_free(priv); - stream->priv = NULL; - return STREAM_UNSUPPORTED; -} - -const stream_info_t stream_info_bdmv_dir = { - .name = "bdmv/bluray", - .open = bdmv_dir_stream_open, - .protocols = (const char*const[]){ "file", "", NULL }, -}; diff --git a/stream/stream_cdda.c b/stream/stream_cdda.c deleted file mode 100644 index 7fd461a361..0000000000 --- a/stream/stream_cdda.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Original author: Albeu - * - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include "config.h" - -#include - -#if CDIO_API_VERSION < 6 -#define OLD_API -#endif - -#ifdef OLD_API -#include -#include -#else -#include -#include -#endif - -#include -#include -#include - -#include "mpv_talloc.h" - -#include "stream.h" -#include "options/m_option.h" -#include "options/m_config.h" -#include "options/options.h" - -#include "common/msg.h" - -#include "config.h" -#if !HAVE_GPL -#error GPL only -#endif - -typedef struct cdda_params { - cdrom_drive_t *cd; - cdrom_paranoia_t *cdp; - int sector; - int start_sector; - int end_sector; - - // options - int speed; - int paranoia_mode; - int sector_size; - int search_overlap; - int toc_bias; - int toc_offset; - int skip; - char *device; - int span[2]; - int cdtext; -} cdda_priv; - -#define OPT_BASE_STRUCT struct cdda_params -const struct m_sub_options stream_cdda_conf = { - .opts = (const m_option_t[]) { - OPT_INTRANGE("speed", speed, 0, 1, 100), - OPT_INTRANGE("paranoia", paranoia_mode, 0, 0, 2), - OPT_INTRANGE("sector-size", sector_size, 0, 1, 100), - OPT_INTRANGE("overlap", search_overlap, 0, 0, 75), - OPT_INT("toc-bias", toc_bias, 0), - OPT_INT("toc-offset", toc_offset, 0), - OPT_FLAG("skip", skip, 0), - OPT_INTPAIR("span", span, 0), - OPT_FLAG("cdtext", cdtext, 0), - {0} - }, - .size = sizeof(struct cdda_params), - .defaults = &(const struct cdda_params){ - .search_overlap = -1, - .skip = 1, - }, -}; - -static const char *const cdtext_name[] = { -#ifdef OLD_API - [CDTEXT_ARRANGER] = "Arranger", - [CDTEXT_COMPOSER] = "Composer", - [CDTEXT_MESSAGE] = "Message", - [CDTEXT_ISRC] = "ISRC", - [CDTEXT_PERFORMER] = "Performer", - [CDTEXT_SONGWRITER] = "Songwriter", - [CDTEXT_TITLE] = "Title", - [CDTEXT_UPC_EAN] = "UPC_EAN", -#else - [CDTEXT_FIELD_ARRANGER] = "Arranger", - [CDTEXT_FIELD_COMPOSER] = "Composer", - [CDTEXT_FIELD_MESSAGE] = "Message", - [CDTEXT_FIELD_ISRC] = "ISRC", - [CDTEXT_FIELD_PERFORMER] = "Performer", - [CDTEXT_FIELD_SONGWRITER] = "Songwriter", - [CDTEXT_FIELD_TITLE] = "Title", - [CDTEXT_FIELD_UPC_EAN] = "UPC_EAN", -#endif -}; - -static void print_cdtext(stream_t *s, int track) -{ - cdda_priv* p = (cdda_priv*)s->priv; - if (!p->cdtext) - return; -#ifdef OLD_API - cdtext_t *text = cdio_get_cdtext(p->cd->p_cdio, track); -#else - cdtext_t *text = cdio_get_cdtext(p->cd->p_cdio); -#endif - int header = 0; - if (text) { - for (int i = 0; i < sizeof(cdtext_name) / sizeof(cdtext_name[0]); i++) { - const char *name = cdtext_name[i]; -#ifdef OLD_API - const char *value = cdtext_get_const(i, text); -#else - const char *value = cdtext_get_const(text, i, track); -#endif - if (name && value) { - if (!header) - MP_INFO(s, "CD-Text (%s):\n", track ? "track" : "CD"); - header = 1; - MP_INFO(s, " %s: '%s'\n", name, value); - } - } - } -} - -static void print_track_info(stream_t *s, int track) -{ - MP_INFO(s, "Switched to track %d\n", track); - print_cdtext(s, track); -} - -static void cdparanoia_callback(long int inpos, paranoia_cb_mode_t function) -{ -} - -static int fill_buffer(stream_t *s, char *buffer, int max_len) -{ - cdda_priv *p = (cdda_priv *)s->priv; - int16_t *buf; - int i; - - if (max_len < CDIO_CD_FRAMESIZE_RAW) - return -1; - - if ((p->sector < p->start_sector) || (p->sector > p->end_sector)) { - return 0; - } - - buf = paranoia_read(p->cdp, cdparanoia_callback); - if (!buf) - return 0; - - p->sector++; - memcpy(buffer, buf, CDIO_CD_FRAMESIZE_RAW); - - for (i = 0; i < p->cd->tracks; i++) { - if (p->cd->disc_toc[i].dwStartSector == p->sector - 1) { - print_track_info(s, i + 1); - break; - } - } - - return CDIO_CD_FRAMESIZE_RAW; -} - -static int seek(stream_t *s, int64_t newpos) -{ - cdda_priv *p = (cdda_priv *)s->priv; - int sec; - int current_track = 0, seeked_track = 0; - int seek_to_track = 0; - int i; - - newpos += p->start_sector * CDIO_CD_FRAMESIZE_RAW; - - sec = newpos / CDIO_CD_FRAMESIZE_RAW; - if (newpos < 0 || sec > p->end_sector) { - p->sector = p->end_sector + 1; - return 0; - } - - for (i = 0; i < p->cd->tracks; i++) { - if (p->sector >= p->cd->disc_toc[i].dwStartSector - && p->sector < p->cd->disc_toc[i + 1].dwStartSector) - current_track = i; - if (sec >= p->cd->disc_toc[i].dwStartSector - && sec < p->cd->disc_toc[i + 1].dwStartSector) - { - seeked_track = i; - seek_to_track = sec == p->cd->disc_toc[i].dwStartSector; - } - } - if (current_track != seeked_track && !seek_to_track) - print_track_info(s, seeked_track + 1); - - p->sector = sec; - - paranoia_seek(p->cdp, sec, SEEK_SET); - return 1; -} - -static void close_cdda(stream_t *s) -{ - cdda_priv *p = (cdda_priv *)s->priv; - paranoia_free(p->cdp); - cdda_close(p->cd); -} - -static int get_track_by_sector(cdda_priv *p, unsigned int sector) -{ - int i; - for (i = p->cd->tracks; i >= 0; --i) - if (p->cd->disc_toc[i].dwStartSector <= sector) - break; - return i; -} - -static int control(stream_t *stream, int cmd, void *arg) -{ - cdda_priv *p = stream->priv; - switch (cmd) { - case STREAM_CTRL_GET_NUM_CHAPTERS: - { - int start_track = get_track_by_sector(p, p->start_sector); - int end_track = get_track_by_sector(p, p->end_sector); - if (start_track == -1 || end_track == -1) - return STREAM_ERROR; - *(unsigned int *)arg = end_track + 1 - start_track; - return STREAM_OK; - } - case STREAM_CTRL_GET_CHAPTER_TIME: - { - int track = *(double *)arg; - int start_track = get_track_by_sector(p, p->start_sector); - int end_track = get_track_by_sector(p, p->end_sector); - track += start_track; - if (track > end_track) - return STREAM_ERROR; - int64_t sector = p->cd->disc_toc[track].dwStartSector; - int64_t pos = sector * CDIO_CD_FRAMESIZE_RAW; - // Assume standard audio CD: 44.1khz, 2 channels, s16 samples - *(double *)arg = pos / (44100.0 * 2 * 2); - return STREAM_OK; - } - case STREAM_CTRL_GET_SIZE: - *(int64_t *)arg = - (p->end_sector + 1 - p->start_sector) * CDIO_CD_FRAMESIZE_RAW; - return STREAM_OK; - } - return STREAM_UNSUPPORTED; -} - -static int open_cdda(stream_t *st) -{ - st->priv = mp_get_config_group(st, st->global, &stream_cdda_conf); - cdda_priv *priv = st->priv; - cdda_priv *p = priv; - int mode = p->paranoia_mode; - int offset = p->toc_offset; - cdrom_drive_t *cdd = NULL; - int last_track; - - char *global_device; - mp_read_option_raw(st->global, "cdrom-device", &m_option_type_string, - &global_device); - talloc_steal(st, global_device); - - if (st->path[0]) { - p->device = st->path; - } else if (global_device && global_device[0]) { - p->device = global_device; - } else { - p->device = DEFAULT_CDROM_DEVICE; - } - -#if defined(__NetBSD__) - cdd = cdda_identify_scsi(p->device, p->device, 0, NULL); -#else - cdd = cdda_identify(p->device, 0, NULL); -#endif - - if (!cdd) { - MP_ERR(st, "Can't open CDDA device.\n"); - return STREAM_ERROR; - } - - cdda_verbose_set(cdd, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT); - - if (p->sector_size) - cdd->nsectors = p->sector_size; - - if (cdda_open(cdd) != 0) { - MP_ERR(st, "Can't open disc.\n"); - cdda_close(cdd); - return STREAM_ERROR; - } - - priv->cd = cdd; - - if (p->toc_bias) - offset -= cdda_track_firstsector(cdd, 1); - - if (offset) { - for (int n = 0; n < cdd->tracks + 1; n++) - cdd->disc_toc[n].dwStartSector += offset; - } - - if (p->speed > 0) - cdda_speed_set(cdd, p->speed); - - last_track = cdda_tracks(cdd); - if (p->span[0] > last_track) - p->span[0] = last_track; - if (p->span[1] < p->span[0]) - p->span[1] = p->span[0]; - if (p->span[1] > last_track) - p->span[1] = last_track; - if (p->span[0]) - priv->start_sector = cdda_track_firstsector(cdd, p->span[0]); - else - priv->start_sector = cdda_disc_firstsector(cdd); - - if (p->span[1]) - priv->end_sector = cdda_track_lastsector(cdd, p->span[1]); - else - priv->end_sector = cdda_disc_lastsector(cdd); - - priv->cdp = paranoia_init(cdd); - if (priv->cdp == NULL) { - cdda_close(cdd); - free(priv); - return STREAM_ERROR; - } - - if (mode == 0) - mode = PARANOIA_MODE_DISABLE; - else if (mode == 1) - mode = PARANOIA_MODE_OVERLAP; - else - mode = PARANOIA_MODE_FULL; - - if (p->skip) - mode &= ~PARANOIA_MODE_NEVERSKIP; - else - mode |= PARANOIA_MODE_NEVERSKIP; - - if (p->search_overlap > 0) - mode |= PARANOIA_MODE_OVERLAP; - else if (p->search_overlap == 0) - mode &= ~PARANOIA_MODE_OVERLAP; - - paranoia_modeset(priv->cdp, mode); - - if (p->search_overlap > 0) - paranoia_overlapset(priv->cdp, p->search_overlap); - - paranoia_seek(priv->cdp, priv->start_sector, SEEK_SET); - priv->sector = priv->start_sector; - - st->priv = priv; - st->sector_size = CDIO_CD_FRAMESIZE_RAW; - - st->fill_buffer = fill_buffer; - st->seek = seek; - st->seekable = true; - st->control = control; - st->close = close_cdda; - - st->streaming = true; - - st->demuxer = "+disc"; - - print_cdtext(st, 0); - - return STREAM_OK; -} - -const stream_info_t stream_info_cdda = { - .name = "cdda", - .open = open_cdda, - .protocols = (const char*const[]){"cdda", NULL }, -}; diff --git a/stream/stream_dvb.c b/stream/stream_dvb.c deleted file mode 100644 index fa58f633ec..0000000000 --- a/stream/stream_dvb.c +++ /dev/null @@ -1,1281 +0,0 @@ -/* - - dvbstream - (C) Dave Chapman 2001, 2002. - (C) Rozhuk Ivan 2016 - 2017 - - Original authors: Nico, probably Arpi - - Some code based on dvbstream, 0.4.3-pre3 (CVS checkout), - http://sourceforge.net/projects/dvbtools/ - - Modified for use with MPlayer, for details see the changelog at - http://svn.mplayerhq.hu/mplayer/trunk/ - $Id$ - - Copyright notice: - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "osdep/io.h" -#include "misc/ctype.h" - -#include "stream.h" -#include "common/tags.h" -#include "options/m_config.h" -#include "options/m_option.h" -#include "options/options.h" -#include "options/path.h" - -#include "dvbin.h" -#include "dvb_tune.h" - -#if !HAVE_GPL -#error GPL only -#endif - -#define CHANNEL_LINE_LEN 256 -#define min(a, b) ((a) <= (b) ? (a) : (b)) - -#define OPT_BASE_STRUCT dvb_priv_t - -static dvb_state_t *global_dvb_state = NULL; -static pthread_mutex_t global_dvb_state_lock = PTHREAD_MUTEX_INITIALIZER; - -const struct m_sub_options stream_dvb_conf = { - .opts = (const m_option_t[]) { - OPT_STRING("prog", cfg_prog, 0), - OPT_INTRANGE("card", cfg_devno, 0, 1, 4), - OPT_INTRANGE("timeout", cfg_timeout, 0, 1, 30), - OPT_STRING("file", cfg_file, M_OPT_FILE), - OPT_FLAG("full-transponder", cfg_full_transponder, 0), - {0} - }, - .size = sizeof(dvb_priv_t), - .defaults = &(const dvb_priv_t){ - .cfg_prog = NULL, - .cfg_devno = 0, - .cfg_timeout = 30, - }, -}; - -void dvbin_close(stream_t *stream); - -static fe_modulation_t parse_vdr_modulation(const char** modstring) { - if (!strncmp(*modstring, "16", 2)) { - (*modstring)+=2; - return QAM_16; - } else if (!strncmp(*modstring, "32", 2)) { - (*modstring)+=2; - return QAM_32; - } else if (!strncmp(*modstring, "64", 2)) { - (*modstring)+=2; - return QAM_64; - } else if (!strncmp(*modstring, "128", 3)) { - (*modstring)+=3; - return QAM_128; - } else if (!strncmp(*modstring, "256", 3)) { - (*modstring)+=3; - return QAM_256; - } else if (!strncmp(*modstring, "998", 3)) { - (*modstring)+=3; - return QAM_AUTO; - } else if (!strncmp(*modstring, "2", 1)) { - (*modstring)++; - return QPSK; - } else if (!strncmp(*modstring, "5", 1)) { - (*modstring)++; - return PSK_8; - } else if (!strncmp(*modstring, "6", 1)) { - (*modstring)++; - return APSK_16; - } else if (!strncmp(*modstring, "7", 1)) { - (*modstring)++; - return APSK_32; - } else if (!strncmp(*modstring, "10", 2)) { - (*modstring)+=2; - return VSB_8; - } else if (!strncmp(*modstring, "11", 2)) { - (*modstring)+=2; - return VSB_16; - } else if (!strncmp(*modstring, "12", 2)) { - (*modstring)+=2; - return DQPSK; - } else { - return QAM_AUTO; - } -} - -static void parse_vdr_par_string(const char *vdr_par_str, dvb_channel_t *ptr) -{ - //FIXME: There is more information in this parameter string, especially related - // to non-DVB-S reception. - if (vdr_par_str[0]) { - const char *vdr_par = &vdr_par_str[0]; - while (vdr_par && *vdr_par) { - switch (mp_toupper(*vdr_par)) { - case 'H': - ptr->pol = 'H'; - vdr_par++; - break; - case 'V': - ptr->pol = 'V'; - vdr_par++; - break; - case 'S': - vdr_par++; - if (*vdr_par == '1') { - ptr->is_dvb_x2 = true; - } else { - ptr->is_dvb_x2 = false; - } - vdr_par++; - break; - case 'P': - vdr_par++; - char *endptr = NULL; - errno = 0; - int n = strtol(vdr_par, &endptr, 10); - if (!errno && endptr != vdr_par) { - ptr->stream_id = n; - vdr_par = endptr; - } - break; - case 'I': - vdr_par++; - if (*vdr_par == '1') { - ptr->inv = INVERSION_ON; - } else { - ptr->inv = INVERSION_OFF; - } - vdr_par++; - break; - case 'M': - vdr_par++; - ptr->mod = parse_vdr_modulation(&vdr_par); - break; - default: - vdr_par++; - } - } - } -} - -static char *dvb_strtok_r(char *s, const char *sep, char **p) -{ - if (!s && !(s = *p)) - return NULL; - - /* Skip leading separators. */ - s += strspn(s, sep); - - /* s points at first non-separator, or end of string. */ - if (!*s) - return *p = 0; - - /* Move *p to next separator. */ - *p = s + strcspn(s, sep); - if (**p) { - *(*p)++ = 0; - } else { - *p = 0; - } - return s; -} - -static bool parse_pid_string(struct mp_log *log, char *pid_string, - dvb_channel_t *ptr) -{ - if (pid_string[0]) { - int pcnt = 0; - /* These tokens also catch vdr-style PID lists. - * They can contain 123=deu@3,124=eng+jap@4;125 - * 3 and 4 are codes for codec type, =langLeft+langRight is allowed, - * and ; may separate a dolby channel. - * With the numChars-test and the full token-list, all is handled - * gracefully. - */ - const char *tokens = "+,;"; - char *pidPart; - char *savePtr = NULL; - pidPart = dvb_strtok_r(pid_string, tokens, &savePtr); - while (pidPart != NULL) { - if (ptr->pids_cnt >= DMX_FILTER_SIZE - 1) { - mp_verbose(log, "Maximum number of PIDs for one channel " - "reached, ignoring further ones!\n"); - return pcnt > 0; - } - int numChars = 0; - int pid = 0; - pcnt += sscanf(pidPart, "%d%n", &pid, &numChars); - if (numChars > 0) { - ptr->pids[ptr->pids_cnt] = pid; - ptr->pids_cnt++; - } - pidPart = dvb_strtok_r(NULL, tokens, &savePtr); - } - if (pcnt > 0) - return true; - } - return false; -} - -static dvb_channels_list_t *dvb_get_channels(struct mp_log *log, - dvb_channels_list_t *list_add, - int cfg_full_transponder, - char *filename, - unsigned int frontend, - int delsys, unsigned int delsys_mask) -{ - dvb_channels_list_t *list = list_add; - FILE *f; - char line[CHANNEL_LINE_LEN], *colon; - - if (!filename) - return NULL; - - int fields, cnt, k; - int has8192, has0; - dvb_channel_t *ptr, *tmp, chn; - char tmp_lcr[256], tmp_hier[256], inv[256], bw[256], cr[256], mod[256], - transm[256], gi[256], vpid_str[256], apid_str[256], tpid_str[256], - vdr_par_str[256], vdr_loc_str[256]; - const char *cbl_conf = - "%d:%255[^:]:%d:%255[^:]:%255[^:]:%255[^:]:%255[^:]\n"; - const char *sat_conf = "%d:%c:%d:%d:%255[^:]:%255[^:]\n"; - const char *ter_conf = - "%d:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]\n"; -#ifdef DVB_ATSC - const char *atsc_conf = "%d:%255[^:]:%255[^:]:%255[^:]\n"; -#endif - const char *vdr_conf = - "%d:%255[^:]:%255[^:]:%d:%255[^:]:%255[^:]:%255[^:]:%*255[^:]:%d:%*d:%*d:%*d\n%n"; - - mp_verbose(log, "CONFIG_READ FILE: %s, type: %s\n", - filename, get_dvb_delsys(delsys)); - if ((f = fopen(filename, "r")) == NULL) { - mp_fatal(log, "CAN'T READ CONFIG FILE %s\n", filename); - return NULL; - } - - if (list == NULL) { - list = malloc(sizeof(dvb_channels_list_t)); - if (list == NULL) { - fclose(f); - mp_verbose(log, "DVB_GET_CHANNELS: couldn't malloc enough memory\n"); - return NULL; - } - memset(list, 0x00, sizeof(dvb_channels_list_t)); - } - - ptr = &chn; - while (!feof(f)) { - if (fgets(line, CHANNEL_LINE_LEN, f) == NULL) - continue; - - if ((line[0] == '#') || (strlen(line) == 0)) - continue; - - memset(ptr, 0x00, sizeof(dvb_channel_t)); - vpid_str[0] = apid_str[0] = tpid_str[0] = 0; - vdr_loc_str[0] = vdr_par_str[0] = 0; - - colon = strchr(line, ':'); - if (colon) { - k = colon - line; - if (!k) - continue; - // In some modern VDR-style configs, channel name also has bouquet after ;. - // Parse that off, we ignore it. - char *bouquet_sep = strchr(line, ';'); - int channel_name_length = k; - if (bouquet_sep && bouquet_sep < colon) - channel_name_length = (bouquet_sep - line); - ptr->name = malloc((channel_name_length + 1)); - if (!ptr->name) - continue; - av_strlcpy(ptr->name, line, (channel_name_length + 1)); - } else { - continue; - } - k++; - ptr->pids_cnt = 0; - ptr->freq = 0; - ptr->service_id = -1; - ptr->is_dvb_x2 = false; - ptr->frontend = frontend; - ptr->delsys = delsys; - ptr->diseqc = 0; - ptr->stream_id = NO_STREAM_ID_FILTER; - ptr->inv = INVERSION_AUTO; - ptr->bw = BANDWIDTH_AUTO; - ptr->cr = FEC_AUTO; - ptr->cr_lp = FEC_AUTO; - ptr->mod = QAM_AUTO; - ptr->hier = HIERARCHY_AUTO; - ptr->gi = GUARD_INTERVAL_AUTO; - ptr->trans = TRANSMISSION_MODE_AUTO; - - // Check if VDR-type channels.conf-line - then full line is consumed by the scan. - int num_chars = 0; - fields = sscanf(&line[k], vdr_conf, - &ptr->freq, vdr_par_str, vdr_loc_str, &ptr->srate, - vpid_str, apid_str, tpid_str, &ptr->service_id, - &num_chars); - - if (num_chars == strlen(&line[k])) { - // Modulation parsed here, not via old xine-parsing path. - mod[0] = '\0'; - // It's a VDR-style config line. - parse_vdr_par_string(vdr_par_str, ptr); - // Units in VDR-style config files are divided by 1000. - ptr->freq *= 1000UL; - ptr->srate *= 1000UL; - switch (delsys) { - case SYS_DVBT: - case SYS_DVBT2: - /* Fix delsys value. */ - if (ptr->is_dvb_x2) { - ptr->delsys = delsys = SYS_DVBT2; - } else { - ptr->delsys = delsys = SYS_DVBT; - } - if (!DELSYS_IS_SET(delsys_mask, delsys)) - continue; /* Skip channel. */ - /* PASSTROUTH */ - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - case SYS_ATSC: - case SYS_DVBC_ANNEX_B: - mp_verbose(log, "VDR, %s, NUM: %d, NUM_FIELDS: %d, NAME: %s, " - "FREQ: %d, SRATE: %d", - get_dvb_delsys(delsys), - list->NUM_CHANNELS, fields, - ptr->name, ptr->freq, ptr->srate); - break; - case SYS_DVBS: - case SYS_DVBS2: - /* Fix delsys value. */ - if (ptr->is_dvb_x2) { - ptr->delsys = delsys = SYS_DVBS2; - } else { - ptr->delsys = delsys = SYS_DVBS; - } - if (!DELSYS_IS_SET(delsys_mask, delsys)) - continue; /* Skip channel. */ - - if (vdr_loc_str[0]) { - // In older vdr config format, this field contained the DISEQc information. - // If it is numeric, assume that's it. - int diseqc_info = 0; - int valid_digits = 0; - if (sscanf(vdr_loc_str, "%d%n", &diseqc_info, - &valid_digits) == 1) - { - if (valid_digits == strlen(vdr_loc_str)) { - ptr->diseqc = (unsigned int)diseqc_info; - if (ptr->diseqc > 4) - continue; - if (ptr->diseqc > 0) - ptr->diseqc--; - } - } - } - - mp_verbose(log, "%s NUM: %d, NUM_FIELDS: %d, NAME: %s, " - "FREQ: %d, SRATE: %d, POL: %c, DISEQC: %d, S2: %s, " - "StreamID: %d, SID: %d", - get_dvb_delsys(delsys), - list->NUM_CHANNELS, - fields, ptr->name, ptr->freq, ptr->srate, ptr->pol, - ptr->diseqc, (delsys == SYS_DVBS2) ? "yes" : "no", - ptr->stream_id, ptr->service_id); - break; - default: - break; - } - } else { - switch (delsys) { - case SYS_DVBT: - case SYS_DVBT2: - fields = sscanf(&line[k], ter_conf, - &ptr->freq, inv, bw, cr, tmp_lcr, mod, - transm, gi, tmp_hier, vpid_str, apid_str); - mp_verbose(log, "%s, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d", - get_dvb_delsys(delsys), list->NUM_CHANNELS, - fields, ptr->name, ptr->freq); - break; - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - fields = sscanf(&line[k], cbl_conf, - &ptr->freq, inv, &ptr->srate, - cr, mod, vpid_str, apid_str); - mp_verbose(log, "%s, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d, " - "SRATE: %d", - get_dvb_delsys(delsys), - list->NUM_CHANNELS, fields, ptr->name, - ptr->freq, ptr->srate); - break; -#ifdef DVB_ATSC - case SYS_ATSC: - case SYS_DVBC_ANNEX_B: - fields = sscanf(&line[k], atsc_conf, - &ptr->freq, mod, vpid_str, apid_str); - mp_verbose(log, "%s, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d\n", - get_dvb_delsys(delsys), list->NUM_CHANNELS, - fields, ptr->name, ptr->freq); - break; -#endif - case SYS_DVBS: - case SYS_DVBS2: - fields = sscanf(&line[k], sat_conf, - &ptr->freq, &ptr->pol, &ptr->diseqc, &ptr->srate, - vpid_str, - apid_str); - ptr->pol = mp_toupper(ptr->pol); - ptr->freq *= 1000UL; - ptr->srate *= 1000UL; - if (ptr->diseqc > 4) - continue; - if (ptr->diseqc > 0) - ptr->diseqc--; - mp_verbose(log, "%s, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d, " - "SRATE: %d, POL: %c, DISEQC: %d", - get_dvb_delsys(delsys), - list->NUM_CHANNELS, fields, ptr->name, ptr->freq, - ptr->srate, ptr->pol, ptr->diseqc); - break; - default: - break; - } - } - - if (parse_pid_string(log, vpid_str, ptr)) - fields++; - if (parse_pid_string(log, apid_str, ptr)) - fields++; - /* If we do not know the service_id, PMT can not be extracted. - Teletext decoding will fail without PMT. */ - if (ptr->service_id != -1) { - if (parse_pid_string(log, tpid_str, ptr)) - fields++; - } - - - if (fields < 2 || ptr->pids_cnt == 0 || ptr->freq == 0 || - strlen(ptr->name) == 0) - continue; - - /* Add some PIDs which are mandatory in DVB, - * and contain human-readable helpful data. */ - - /* This is the STD, the service description table. - * It contains service names and such, ffmpeg decodes it. */ - ptr->pids[ptr->pids_cnt] = 0x0011; - ptr->pids_cnt++; - - /* This is the EIT, which contains EPG data. - * ffmpeg can not decode it (yet), but e.g. VLC - * shows what was recorded. */ - ptr->pids[ptr->pids_cnt] = 0x0012; - ptr->pids_cnt++; - - if (ptr->service_id != -1) { - /* We have the PMT-PID in addition. - This will be found later, when we tune to the channel. - Push back here to create the additional demux. */ - ptr->pids[ptr->pids_cnt] = -1; // Placeholder. - ptr->pids_cnt++; - } - - has8192 = has0 = 0; - for (cnt = 0; cnt < ptr->pids_cnt; cnt++) { - if (ptr->pids[cnt] == 8192) - has8192 = 1; - if (ptr->pids[cnt] == 0) - has0 = 1; - } - - /* 8192 is the pseudo-PID for full TP dump, - enforce that if requested. */ - if (!has8192 && cfg_full_transponder) - has8192 = 1; - if (has8192) { - ptr->pids[0] = 8192; - ptr->pids_cnt = 1; - } else if (!has0) { - ptr->pids[ptr->pids_cnt] = 0; //PID 0 is the PAT - ptr->pids_cnt++; - } - - mp_verbose(log, " PIDS: "); - for (cnt = 0; cnt < ptr->pids_cnt; cnt++) - mp_verbose(log, " %d ", ptr->pids[cnt]); - mp_verbose(log, "\n"); - - switch (delsys) { - case SYS_DVBT: - case SYS_DVBT2: - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - if (!strcmp(inv, "INVERSION_ON")) { - ptr->inv = INVERSION_ON; - } else if (!strcmp(inv, "INVERSION_OFF")) { - ptr->inv = INVERSION_OFF; - } - - - if (!strcmp(cr, "FEC_1_2")) { - ptr->cr = FEC_1_2; - } else if (!strcmp(cr, "FEC_2_3")) { - ptr->cr = FEC_2_3; - } else if (!strcmp(cr, "FEC_3_4")) { - ptr->cr = FEC_3_4; - } else if (!strcmp(cr, "FEC_4_5")) { - ptr->cr = FEC_4_5; - } else if (!strcmp(cr, "FEC_6_7")) { - ptr->cr = FEC_6_7; - } else if (!strcmp(cr, "FEC_8_9")) { - ptr->cr = FEC_8_9; - } else if (!strcmp(cr, "FEC_5_6")) { - ptr->cr = FEC_5_6; - } else if (!strcmp(cr, "FEC_7_8")) { - ptr->cr = FEC_7_8; - } else if (!strcmp(cr, "FEC_NONE")) { - ptr->cr = FEC_NONE; - } - } - - switch (delsys) { - case SYS_DVBT: - case SYS_DVBT2: - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - case SYS_ATSC: - case SYS_DVBC_ANNEX_B: - if (!strcmp(mod, "QAM_128")) { - ptr->mod = QAM_128; - } else if (!strcmp(mod, "QAM_256")) { - ptr->mod = QAM_256; - } else if (!strcmp(mod, "QAM_64")) { - ptr->mod = QAM_64; - } else if (!strcmp(mod, "QAM_32")) { - ptr->mod = QAM_32; - } else if (!strcmp(mod, "QAM_16")) { - ptr->mod = QAM_16; -#ifdef DVB_ATSC - } else if (!strcmp(mod, "VSB_8") || !strcmp(mod, "8VSB")) { - ptr->mod = VSB_8; - } else if (!strcmp(mod, "VSB_16") || !strcmp(mod, "16VSB")) { - ptr->mod = VSB_16; -#endif - } - } -#ifdef DVB_ATSC - /* Modulation defines real delsys for ATSC: - Terrestrial (VSB) is SYS_ATSC, Cable (QAM) is SYS_DVBC_ANNEX_B. */ - if (delsys == SYS_ATSC || delsys == SYS_DVBC_ANNEX_B) { - if (ptr->mod == VSB_8 || ptr->mod == VSB_16) { - delsys = SYS_ATSC; - } else { - delsys = SYS_DVBC_ANNEX_B; - } - if (!DELSYS_IS_SET(delsys_mask, delsys)) - continue; /* Skip channel. */ - mp_verbose(log, "Switched to delivery system for ATSC: %s (guessed from modulation).\n", - get_dvb_delsys(delsys)); - } -#endif - - switch (delsys) { - case SYS_DVBT: - case SYS_DVBT2: - if (!strcmp(bw, "BANDWIDTH_5_MHZ")) { - ptr->bw = BANDWIDTH_5_MHZ; - } else if (!strcmp(bw, "BANDWIDTH_6_MHZ")) { - ptr->bw = BANDWIDTH_6_MHZ; - } else if (!strcmp(bw, "BANDWIDTH_7_MHZ")) { - ptr->bw = BANDWIDTH_7_MHZ; - } else if (!strcmp(bw, "BANDWIDTH_8_MHZ")) { - ptr->bw = BANDWIDTH_8_MHZ; - } else if (!strcmp(bw, "BANDWIDTH_10_MHZ")) { - ptr->bw = BANDWIDTH_10_MHZ; - } - - - if (!strcmp(transm, "TRANSMISSION_MODE_2K")) { - ptr->trans = TRANSMISSION_MODE_2K; - } else if (!strcmp(transm, "TRANSMISSION_MODE_8K")) { - ptr->trans = TRANSMISSION_MODE_8K; - } else if (!strcmp(transm, "TRANSMISSION_MODE_AUTO")) { - ptr->trans = TRANSMISSION_MODE_AUTO; - } - - if (!strcmp(gi, "GUARD_INTERVAL_1_32")) { - ptr->gi = GUARD_INTERVAL_1_32; - } else if (!strcmp(gi, "GUARD_INTERVAL_1_16")) { - ptr->gi = GUARD_INTERVAL_1_16; - } else if (!strcmp(gi, "GUARD_INTERVAL_1_8")) { - ptr->gi = GUARD_INTERVAL_1_8; - } else if (!strcmp(gi, "GUARD_INTERVAL_1_4")) { - ptr->gi = GUARD_INTERVAL_1_4; - } - - if (!strcmp(tmp_lcr, "FEC_1_2")) { - ptr->cr_lp = FEC_1_2; - } else if (!strcmp(tmp_lcr, "FEC_2_3")) { - ptr->cr_lp = FEC_2_3; - } else if (!strcmp(tmp_lcr, "FEC_3_4")) { - ptr->cr_lp = FEC_3_4; - } else if (!strcmp(tmp_lcr, "FEC_4_5")) { - ptr->cr_lp = FEC_4_5; - } else if (!strcmp(tmp_lcr, "FEC_6_7")) { - ptr->cr_lp = FEC_6_7; - } else if (!strcmp(tmp_lcr, "FEC_8_9")) { - ptr->cr_lp = FEC_8_9; - } else if (!strcmp(tmp_lcr, "FEC_5_6")) { - ptr->cr_lp = FEC_5_6; - } else if (!strcmp(tmp_lcr, "FEC_7_8")) { - ptr->cr_lp = FEC_7_8; - } else if (!strcmp(tmp_lcr, "FEC_NONE")) { - ptr->cr_lp = FEC_NONE; - } - - - if (!strcmp(tmp_hier, "HIERARCHY_1")) { - ptr->hier = HIERARCHY_1; - } else if (!strcmp(tmp_hier, "HIERARCHY_2")) { - ptr->hier = HIERARCHY_2; - } else if (!strcmp(tmp_hier, "HIERARCHY_4")) { - ptr->hier = HIERARCHY_4; - } else if (!strcmp(tmp_hier, "HIERARCHY_NONE")) { - ptr->hier = HIERARCHY_NONE; - } - } - - tmp = realloc(list->channels, sizeof(dvb_channel_t) * - (list->NUM_CHANNELS + 1)); - if (tmp == NULL) - break; - - list->channels = tmp; - memcpy(&(list->channels[list->NUM_CHANNELS]), ptr, sizeof(dvb_channel_t)); - list->NUM_CHANNELS++; - if (sizeof(dvb_channel_t) * list->NUM_CHANNELS >= 1024 * 1024) { - mp_verbose(log, "dvbin.c, > 1MB allocated for channels struct, " - "dropping the rest of the file\n"); - break; - } - } - - fclose(f); - if (list->NUM_CHANNELS == 0) { - free(list->channels); - free(list); - return NULL; - } - - return list; -} - -void dvb_free_state(dvb_state_t *state) -{ - int i, j; - - for (i = 0; i < state->adapters_count; i++) { - if (!state->adapters[i].list) - continue; - if (state->adapters[i].list->channels) { - for (j = 0; j < state->adapters[i].list->NUM_CHANNELS; j++) - free(state->adapters[i].list->channels[j].name); - free(state->adapters[i].list->channels); - } - free(state->adapters[i].list); - } - free(state); -} - -static int dvb_streaming_read(stream_t *stream, char *buffer, int size) -{ - struct pollfd pfds[1]; - int pos = 0, tries, rk, fd; - dvb_priv_t *priv = (dvb_priv_t *) stream->priv; - dvb_state_t *state = priv->state; - - MP_TRACE(stream, "dvb_streaming_read(%d)\n", size); - - tries = state->retry; - fd = state->dvr_fd; - while (pos < size) { - rk = read(fd, &buffer[pos], (size - pos)); - if (rk <= 0) { - if (pos || tries == 0) - break; - tries --; - pfds[0].fd = fd; - pfds[0].events = POLLIN | POLLPRI; - if (poll(pfds, 1, 500) <= 0) { - MP_ERR(stream, "dvb_streaming_read, failed with " - "errno %d when reading %d bytes\n", errno, size - pos); - errno = 0; - break; - } - continue; - } - pos += rk; - MP_TRACE(stream, "ret (%d) bytes\n", pos); - } - - if (!pos) - MP_ERR(stream, "dvb_streaming_read, return 0 bytes\n"); - - return pos; -} - -int dvb_set_channel(stream_t *stream, unsigned int adapter, unsigned int n) -{ - dvb_channels_list_t *new_list; - dvb_channel_t *channel; - dvb_priv_t *priv = stream->priv; - char buf[4096]; - dvb_state_t *state = (dvb_state_t *) priv->state; - int devno; - int i; - - if (adapter >= state->adapters_count) { - MP_ERR(stream, "dvb_set_channel: INVALID internal ADAPTER NUMBER: %d vs %d, abort\n", - adapter, state->adapters_count); - return 0; - } - - devno = state->adapters[adapter].devno; - new_list = state->adapters[adapter].list; - if (n > new_list->NUM_CHANNELS) { - MP_ERR(stream, "dvb_set_channel: INVALID CHANNEL NUMBER: %d, for " - "adapter %d, abort\n", n, devno); - return 0; - } - channel = &(new_list->channels[n]); - - if (state->is_on) { //the fds are already open and we have to stop the demuxers - /* Remove all demuxes. */ - dvb_fix_demuxes(priv, 0); - - state->retry = 0; - //empty both the stream's and driver's buffer - while (dvb_streaming_read(stream, buf, sizeof(buf)) > 0) {} - if (state->cur_adapter != adapter || - state->cur_frontend != channel->frontend) { - dvbin_close(stream); - if (!dvb_open_devices(priv, devno, channel->frontend, channel->pids_cnt)) { - MP_ERR(stream, "DVB_SET_CHANNEL, COULDN'T OPEN DEVICES OF " - "ADAPTER: %d, EXIT\n", devno); - return 0; - } - } else { - // close all demux_fds with pos > pids required for the new channel - // or open other demux_fds if we have too few - if (!dvb_fix_demuxes(priv, channel->pids_cnt)) - return 0; - } - } else { - if (!dvb_open_devices(priv, devno, channel->frontend, channel->pids_cnt)) { - MP_ERR(stream, "DVB_SET_CHANNEL2, COULDN'T OPEN DEVICES OF " - "ADAPTER: %d, EXIT\n", devno); - return 0; - } - } - - state->retry = 5; - new_list->current = n; - MP_VERBOSE(stream, "DVB_SET_CHANNEL: new channel name=%s, adapter: %d, " - "channel %d\n", channel->name, devno, n); - - stream_drop_buffers(stream); - - if (channel->freq != state->last_freq) { - if (!dvb_tune(priv, channel->delsys, channel->freq, - channel->pol, channel->srate, channel->diseqc, - channel->stream_id, channel->inv, - channel->mod, channel->gi, - channel->trans, channel->bw, channel->cr, channel->cr_lp, - channel->hier, priv->cfg_timeout)) - return 0; - } - - state->is_on = 1; - state->last_freq = channel->freq; - state->cur_adapter = adapter; - state->cur_frontend = channel->frontend; - - if (channel->service_id != -1) { - /* We need the PMT-PID in addition. - If it has not yet beem resolved, do it now. */ - for (i = 0; i < channel->pids_cnt; i++) { - if (channel->pids[i] == -1) { - MP_VERBOSE(stream, "DVB_SET_CHANNEL: PMT-PID for service %d " - "not resolved yet, parsing PAT...\n", - channel->service_id); - int pmt_pid = dvb_get_pmt_pid(priv, adapter, channel->service_id); - MP_VERBOSE(stream, "DVB_SET_CHANNEL: Found PMT-PID: %d\n", - pmt_pid); - channel->pids[i] = pmt_pid; - } - } - } - - // sets demux filters and restart the stream - for (i = 0; i < channel->pids_cnt; i++) { - if (channel->pids[i] == -1) { - // In case PMT was not resolved, skip it here. - MP_ERR(stream, "DVB_SET_CHANNEL: PMT-PID not found, " - "teletext-decoding may fail.\n"); - } else { - if (!dvb_set_ts_filt(priv, state->demux_fds[i], channel->pids[i], - DMX_PES_OTHER)) - return 0; - } - } - - return 1; -} - -int dvb_step_channel(stream_t *stream, int dir) -{ - unsigned int new_current; - dvb_priv_t *priv = stream->priv; - dvb_state_t *state = priv->state; - dvb_channels_list_t *list = state->adapters[state->cur_adapter].list; - - MP_VERBOSE(stream, "DVB_STEP_CHANNEL dir %d\n", dir); - - if (list == NULL) { - MP_ERR(stream, "dvb_step_channel: NULL list_ptr, quit\n"); - return 0; - } - - new_current = (list->NUM_CHANNELS + list->current + - (dir >= 0 ? 1 : -1)) % list->NUM_CHANNELS; - - return dvb_set_channel(stream, state->cur_adapter, new_current); -} - -static int dvbin_stream_control(struct stream *s, int cmd, void *arg) -{ - int r; - dvb_priv_t *priv = (dvb_priv_t *) s->priv; - dvb_state_t *state = priv->state; - dvb_channels_list_t *list = NULL; - - - switch (cmd) { - case STREAM_CTRL_DVB_SET_CHANNEL: { - unsigned int *iarg = arg; - MP_VERBOSE(s, "dvbin_stream_control: cmd STREAM_CTRL_DVB_SET_CHANNEL: %i, %i\n", iarg[1], iarg[0]); - r = dvb_set_channel(s, iarg[1], iarg[0]); - if (r) { - // Stream will be pulled down after channel switch, - // persist state. - state->switching_channel = true; - return STREAM_OK; - } - return STREAM_ERROR; - } - case STREAM_CTRL_DVB_STEP_CHANNEL: { - MP_VERBOSE(s, "dvbin_stream_control: cmd STREAM_CTRL_DVB_STEP_CHANNEL: %i\n", (*(int *)arg)); - r = dvb_step_channel(s, (*(int *)arg)); - if (r) { - // Stream will be pulled down after channel switch, - // persist state. - state->switching_channel = true; - return STREAM_OK; - } - return STREAM_ERROR; - } - } - - - if (state->cur_adapter >= state->adapters_count) - return STREAM_ERROR; - list = state->adapters[state->cur_adapter].list; - - switch (cmd) { - case STREAM_CTRL_GET_TV_FREQ: - (*(unsigned int*)arg) = list->channels[list->current].freq; - return STREAM_ERROR; - case STREAM_CTRL_DVB_SET_CHANNEL_NAME: { - char *progname = *((char**)arg); - unsigned int new_channel = (~(unsigned int)0); - MP_VERBOSE(s, "dvbin_stream_control: cmd STREAM_CTRL_DVB_SET_CHANNEL_NAME: %s\n", progname); - for (unsigned int i=0; i < list->NUM_CHANNELS; ++i) { - if (!strcmp(list->channels[i].name, progname)) { - new_channel = i; - break; - } - } - if (new_channel == -1) { - MP_ERR(s, "Program '%s' not found for adapter %d!\n", - progname, state->adapters[state->cur_adapter].devno); - return STREAM_ERROR; - } - r = dvb_set_channel(s, state->cur_adapter, new_channel); - if (r) { - // Stream will be pulled down after channel switch, - // persist state. - state->switching_channel = true; - return STREAM_OK; - } - return STREAM_ERROR; - } - case STREAM_CTRL_DVB_GET_CHANNEL_NAME: { - MP_VERBOSE(s, "dvbin_stream_control: cmd STREAM_CTRL_DVB_GET_CHANNEL_NAME\n"); - char *progname = list->channels[list->current].name; - *(char **)arg = talloc_strdup(NULL, progname); - return STREAM_OK; - } - case STREAM_CTRL_GET_METADATA: { - struct mp_tags *metadata = talloc_zero(NULL, struct mp_tags); - char *progname = list->channels[list->current].name; - mp_tags_set_str(metadata, "title", progname); - *(struct mp_tags **)arg = metadata; - return STREAM_OK; - } - } - return STREAM_UNSUPPORTED; -} - -void dvbin_close(stream_t *stream) -{ - dvb_priv_t *priv = (dvb_priv_t *) stream->priv; - dvb_state_t *state = priv->state; - - if (state->switching_channel && state->is_on) { - // Prevent state destruction, reset channel-switch. - state->switching_channel = false; - pthread_mutex_lock(&global_dvb_state_lock); - global_dvb_state->stream_used = false; - pthread_mutex_unlock(&global_dvb_state_lock); - return; - } - - for (int i = state->demux_fds_cnt - 1; i >= 0; i--) { - state->demux_fds_cnt--; - MP_VERBOSE(stream, "DVBIN_CLOSE, close(%d), fd=%d, COUNT=%d\n", i, - state->demux_fds[i], state->demux_fds_cnt); - close(state->demux_fds[i]); - } - close(state->dvr_fd); - close(state->fe_fd); - state->fe_fd = state->dvr_fd = -1; - - state->is_on = 0; - state->cur_adapter = -1; - state->cur_frontend = -1; - - pthread_mutex_lock(&global_dvb_state_lock); - dvb_free_state(state); - global_dvb_state = NULL; - pthread_mutex_unlock(&global_dvb_state_lock); -} - -static int dvb_streaming_start(stream_t *stream, char *progname) -{ - int i; - dvb_channel_t *channel = NULL; - dvb_priv_t *priv = stream->priv; - dvb_state_t *state = priv->state; - dvb_channels_list_t *list; - - if (progname == NULL) - return 0; - MP_VERBOSE(stream, "\r\ndvb_streaming_start(PROG: %s, ADAPTER: %d)\n", - progname, priv->cfg_devno); - - state->is_on = 0; - list = state->adapters[state->cur_adapter].list; - for (i = 0; i < list->NUM_CHANNELS; i ++) { - if (!strcmp(list->channels[i].name, progname)) { - channel = &(list->channels[i]); - break; - } - } - - if (channel == NULL) { - MP_ERR(stream, "\n\nDVBIN: no such channel \"%s\"\n\n", progname); - return 0; - } - - list->current = i; - MP_VERBOSE(stream, "PROGRAM NUMBER %d: name=%s, freq=%u\n", i, - channel->name, channel->freq); - - if (!dvb_set_channel(stream, state->cur_adapter, list->current)) { - MP_ERR(stream, "ERROR, COULDN'T SET CHANNEL %i: \"%s\"\n", list->current, progname); - dvbin_close(stream); - return 0; - } - - MP_VERBOSE(stream, "SUCCESSFUL EXIT from dvb_streaming_start\n"); - - return 1; -} - - -static int dvb_open(stream_t *stream) -{ - // I don't force the file format because, although it's almost always TS, - // there are some providers that stream an IP multicast with M$ Mpeg4 inside - dvb_priv_t *priv = NULL; - char *progname; - int i; - - pthread_mutex_lock(&global_dvb_state_lock); - if (global_dvb_state && global_dvb_state->stream_used) { - MP_ERR(stream, "DVB stream already in use, only one DVB stream can exist at a time!\n"); - pthread_mutex_unlock(&global_dvb_state_lock); - goto err_out; - } - - // Need to re-get config in any case, not part of global state. - stream->priv = mp_get_config_group(stream, stream->global, &stream_dvb_conf); - dvb_state_t *state = dvb_get_state(stream); - - priv = stream->priv; - priv->state = state; - priv->log = stream->log; - if (state == NULL) { - MP_ERR(stream, "DVB CONFIGURATION IS EMPTY, exit\n"); - pthread_mutex_unlock(&global_dvb_state_lock); - goto err_out; - } - state->stream_used = true; - pthread_mutex_unlock(&global_dvb_state_lock); - - if (state->is_on != 1) { - // State could be already initialized, for example, we just did a channel switch. - // The following setup only has to be done once. - - state->cur_adapter = -1; - state->cur_frontend = -1; - for (i = 0; i < state->adapters_count; i++) { - if (state->adapters[i].devno == priv->cfg_devno) { - state->cur_adapter = i; - break; - } - } - - if (state->cur_adapter == -1) { - MP_ERR(stream, "NO CONFIGURATION FOUND FOR ADAPTER N. %d, exit\n", - priv->cfg_devno); - goto err_out; - } - state->timeout = priv->cfg_timeout; - - MP_VERBOSE(stream, "OPEN_DVB: prog=%s, devno=%d\n", - priv->cfg_prog, state->adapters[state->cur_adapter].devno); - - if ((priv->cfg_prog == NULL || priv->cfg_prog[0] == 0) && - state->adapters[state->cur_adapter].list != NULL) { - progname = state->adapters[state->cur_adapter].list->channels[0].name; - } else { - progname = priv->cfg_prog; - } - - if (!dvb_streaming_start(stream, progname)) - goto err_out; - } - - stream->fill_buffer = dvb_streaming_read; - stream->close = dvbin_close; - stream->control = dvbin_stream_control; - stream->streaming = true; - stream->demuxer = "lavf"; - stream->lavf_type = "mpegts"; - stream->extended_ctrls = true; - - return STREAM_OK; - -err_out: - talloc_free(priv); - stream->priv = NULL; - return STREAM_ERROR; -} - -dvb_state_t *dvb_get_state(stream_t *stream) -{ - if (global_dvb_state != NULL) { - return global_dvb_state; - } - struct mp_log *log = stream->log; - struct mpv_global *global = stream->global; - dvb_priv_t *priv = stream->priv; - unsigned int delsys, delsys_mask[MAX_FRONTENDS], size; - char filename[PATH_MAX], *conf_file; - const char *conf_file_name; - void *talloc_ctx; - dvb_channels_list_t *list; - dvb_adapter_config_t *adapters = NULL, *tmp; - dvb_state_t *state = NULL; - bstr prog, devno; - - if (!bstr_split_tok(bstr0(stream->path), "@", &devno, &prog)) { - prog = devno; - devno.len = 0; - } - if (prog.len) { - talloc_free(priv->cfg_prog); - priv->cfg_prog = bstrto0(NULL, prog); - } - if (devno.len) { - bstr r; - priv->cfg_devno = bstrtoll(devno, &r, 0); - if (r.len || priv->cfg_devno < 0 || priv->cfg_devno > MAX_ADAPTERS) { - MP_ERR(stream, "invalid devno: '%.*s'\n", BSTR_P(devno)); - return NULL; - } - } - - MP_VERBOSE(stream, "DVB_CONFIG: prog=%s, devno=%d\n", - priv->cfg_prog, priv->cfg_devno); - - state = malloc(sizeof(dvb_state_t)); - if (state == NULL) - return NULL; - memset(state, 0x00, sizeof(dvb_state_t)); - state->switching_channel = false; - state->stream_used = true; - state->fe_fd = state->dvr_fd = -1; - for (unsigned int i = 0; i < MAX_ADAPTERS; i++) { - list = NULL; - for (unsigned int f = 0; f < MAX_FRONTENDS; f++) { - snprintf(filename, sizeof(filename), "/dev/dvb/adapter%u/frontend%u", i, f); - int fd = open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC); - if (fd < 0) - continue; - - mp_verbose(log, "Opened device %s, FD: %d\n", filename, fd); - delsys_mask[f] = dvb_get_tuner_delsys_mask(fd, log); - delsys_mask[f] &= DELSYS_SUPP_MASK; /* Filter unsupported delivery systems. */ - close(fd); - if (delsys_mask[f] == 0) { - mp_verbose(log, "Frontend device %s has no supported delivery systems.\n", - filename); - continue; /* Skip tuner. */ - } - mp_verbose(log, "Frontend device %s offers some supported delivery systems.\n", - filename); - /* Create channel list for adapter. */ - for (delsys = 0; delsys < SYS_DVB__COUNT__; delsys++) { - if (!DELSYS_IS_SET(delsys_mask[f], delsys)) - continue; /* Skip unsupported. */ - - switch (delsys) { - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - conf_file_name = "channels.conf.cbl"; - break; - case SYS_ATSC: - conf_file_name = "channels.conf.atsc"; - break; - case SYS_DVBT: - if (DELSYS_IS_SET(delsys_mask[f], SYS_DVBT2)) - continue; /* Add all channels later with T2. */ - /* PASSTOUTH */ - case SYS_DVBT2: - conf_file_name = "channels.conf.ter"; - break; - case SYS_DVBS: - if (DELSYS_IS_SET(delsys_mask[f], SYS_DVBS2)) - continue; /* Add all channels later with S2. */ - /* PASSTOUTH */ - case SYS_DVBS2: - conf_file_name = "channels.conf.sat"; - break; - default: - continue; - } - - if (priv->cfg_file && priv->cfg_file[0]) { - talloc_ctx = NULL; - conf_file = priv->cfg_file; - } else { - talloc_ctx = talloc_new(NULL); - conf_file = mp_find_config_file(talloc_ctx, global, conf_file_name); - if (conf_file) { - mp_verbose(log, "Ignoring other channels.conf files.\n"); - } else { - conf_file = mp_find_config_file(talloc_ctx, global, - "channels.conf"); - } - } - - list = dvb_get_channels(log, list, priv->cfg_full_transponder, - conf_file, f, delsys, delsys_mask[f]); - talloc_free(talloc_ctx); - } - } - /* Add adapter with non zero channel list. */ - if (list == NULL) - continue; - - size = sizeof(dvb_adapter_config_t) * (state->adapters_count + 1); - tmp = realloc(state->adapters, size); - - if (tmp == NULL) { - mp_err(log, "DVB_CONFIG, can't realloc %d bytes, skipping\n", - size); - free(list); - continue; - } - adapters = tmp; - - state->adapters = adapters; - state->adapters[state->adapters_count].devno = i; - memcpy(&state->adapters[state->adapters_count].delsys_mask, - &delsys_mask, (sizeof(unsigned int) * MAX_FRONTENDS)); - state->adapters[state->adapters_count].list = list; - state->adapters_count++; - } - - if (state->adapters_count == 0) { - free(state); - state = NULL; - } - - global_dvb_state = state; - return state; -} - -const stream_info_t stream_info_dvb = { - .name = "dvbin", - .open = dvb_open, - .protocols = (const char *const[]){ "dvb", NULL }, -}; diff --git a/stream/stream_dvd.c b/stream/stream_dvd.c deleted file mode 100644 index 4fe3e3e7a3..0000000000 --- a/stream/stream_dvd.c +++ /dev/null @@ -1,993 +0,0 @@ -/* - * Original author: Benjamin Zores - * - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "osdep/io.h" - -#include "config.h" -#include "mpv_talloc.h" -#include "common/common.h" -#include "common/msg.h" - -#define FIRST_AC3_AID 128 -#define FIRST_DTS_AID 136 -#define FIRST_MPG_AID 0 -#define FIRST_PCM_AID 160 - -#include "stream.h" -#include "options/m_config.h" -#include "options/options.h" -#include "options/path.h" - -#include "stream_dvd_common.h" - -#define LIBDVDREAD_VERSION(maj,min,micro) ((maj)*10000 + (min)*100 + (micro)) -/* - * Try to autodetect the libdvd-0.9.0 library - * (0.9.0 removed the header, and moved the two defines - * DVD_VIDEO_LB_LEN and MAX_UDF_FILE_NAME_LEN from it to - * ) - */ -#ifndef DVDREAD_VERSION -#if defined(DVD_VIDEO_LB_LEN) && defined(MAX_UDF_FILE_NAME_LEN) -#define DVDREAD_VERSION LIBDVDREAD_VERSION(0,9,0) -#else -#define DVDREAD_VERSION LIBDVDREAD_VERSION(0,8,0) -#endif -#endif - -typedef struct { - int id; // 0 - 31 mpeg; 128 - 159 ac3; 160 - 191 pcm - int language; - int type; - int channels; -} stream_language_t; - -typedef struct { - dvd_reader_t *dvd; - dvd_file_t *title; - ifo_handle_t *vmg_file; - tt_srpt_t *tt_srpt; - ifo_handle_t *vts_file; - vts_ptt_srpt_t *vts_ptt_srpt; - pgc_t *cur_pgc; -// - int cur_title; - int cur_cell; - int last_cell; - int cur_pack; - int cell_last_pack; - int cur_pgc_idx; -// Navi: - int packs_left; - dsi_t dsi_pack; - int angle_seek; - unsigned int *cell_times_table; -// audio datas - int nr_of_channels; - stream_language_t audio_streams[32]; -// subtitles - int nr_of_subtitles; - stream_language_t subtitles[32]; - - int dvd_angle; - char *dvd_device_current; - int dvd_speed; - int dvd_title; - - int cfg_title; - char *cfg_device; -} dvd_priv_t; - -static int dvd_lang_from_aid(stream_t *stream, int id) { - dvd_priv_t *d; - int i; - if (!stream) return 0; - d = stream->priv; - if (!d) return 0; - for(i=0;inr_of_channels;i++) { - if(d->audio_streams[i].id==id) - return d->audio_streams[i].language; - } - return 0; -} - -static int dvd_number_of_subs(stream_t *stream) { - int i; - int maxid = -1; - dvd_priv_t *d; - if (!stream) return -1; - d = stream->priv; - if (!d) return -1; - for (i = 0; i < d->nr_of_subtitles; i++) - if (d->subtitles[i].id > maxid) maxid = d->subtitles[i].id; - return maxid + 1; -} - -static int dvd_lang_from_sid(stream_t *stream, int id) { - int i; - dvd_priv_t *d; - if (!stream) return 0; - d = stream->priv; - if (!d) return 0; - for (i = 0; i < d->nr_of_subtitles; i++) - if (d->subtitles[i].id == id && d->subtitles[i].language) return d->subtitles[i].language; - return 0; -} - -static int dvd_next_cell(stream_t *stream, dvd_priv_t *d) { - int next_cell=d->cur_cell; - - MP_DBG(stream, "dvd_next_cell: next1=0x%X \n",next_cell); - if( d->cur_pgc->cell_playback[ next_cell ].block_type == BLOCK_TYPE_ANGLE_BLOCK ) { - while(next_celllast_cell) { - if( d->cur_pgc->cell_playback[next_cell].block_mode == BLOCK_MODE_LAST_CELL ) - break; - ++next_cell; - } - } - MP_DBG(stream, "dvd_next_cell: next2=0x%X \n",next_cell); - - ++next_cell; - if(next_cell>=d->last_cell) - return -1; // EOF - if(d->cur_pgc->cell_playback[next_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK ) { - next_cell+=d->dvd_angle-1; - if(next_cell>=d->last_cell) - return -1; // EOF - } - MP_DBG(stream, "dvd_next_cell: next3=0x%X \n",next_cell); - return next_cell; -} - -static int dvd_read_sector(stream_t *stream, dvd_priv_t *d, unsigned char *data) -{ - int len; - - if(d->packs_left==0) { - /** - * If we're not at the end of this cell, we can determine the next - * VOBU to display using the VOBU_SRI information section of the - * DSI. Using this value correctly follows the current angle, - * avoiding the doubled scenes in The Matrix, and makes our life - * really happy. - * - * Otherwise, we set our next address past the end of this cell to - * force the code above to go to the next cell in the program. - */ - if(d->dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL) { - d->cur_pack= d->dsi_pack.dsi_gi.nv_pck_lbn + ( d->dsi_pack.vobu_sri.next_vobu & 0x7fffffff ); - MP_DBG(stream, "Navi new pos=0x%X \n",d->cur_pack); - } else { - // end of cell! find next cell! - MP_VERBOSE(stream, "--- END OF CELL !!! ---\n"); - d->cur_pack=d->cell_last_pack+1; - } - } - -read_next: - if(d->cur_pack>d->cell_last_pack) { - // end of cell! - int next=dvd_next_cell(stream, d); - if(next>=0) { - d->cur_cell=next; - // if( d->cur_pgc->cell_playback[d->cur_cell].block_type - // == BLOCK_TYPE_ANGLE_BLOCK ) d->cur_cell+=dvd_angle-1; - d->cur_pack = d->cur_pgc->cell_playback[ d->cur_cell ].first_sector; - d->cell_last_pack=d->cur_pgc->cell_playback[ d->cur_cell ].last_sector; - MP_VERBOSE(stream, "DVD next cell: %d pack: 0x%X-0x%X \n",d->cur_cell,d->cur_pack,d->cell_last_pack); - } else - return -1; // EOF - } - - len = DVDReadBlocks(d->title, d->cur_pack, 1, data); - // only == 0 should indicate an error, but some dvdread version are buggy when used with dvdcss - if(len <= 0) return -1; //error - - if(data[38]==0 && data[39]==0 && data[40]==1 && data[41]==0xBF && - data[1024]==0 && data[1025]==0 && data[1026]==1 && data[1027]==0xBF) { - // found a Navi packet!!! -#if DVDREAD_VERSION >= LIBDVDREAD_VERSION(0,9,0) - navRead_DSI(&d->dsi_pack, &(data[ DSI_START_BYTE ])); -#else - navRead_DSI(&d->dsi_pack, &(data[ DSI_START_BYTE ]), sizeof(dsi_t)); -#endif - if(d->cur_pack != d->dsi_pack.dsi_gi.nv_pck_lbn ) { - MP_VERBOSE(stream, "Invalid NAVI packet! lba=0x%X navi=0x%X \n", - d->cur_pack,d->dsi_pack.dsi_gi.nv_pck_lbn); - } else { - // process! - d->packs_left = d->dsi_pack.dsi_gi.vobu_ea; - MP_DBG(stream, "Found NAVI packet! lba=0x%X len=%d \n",d->cur_pack,d->packs_left); - //navPrint_DSI(&d->dsi_pack); - MP_TRACE(stream, "\r### CELL %d: Navi: %d/%d IFO: %d/%d \n",d->cur_cell, - d->dsi_pack.dsi_gi.vobu_c_idn,d->dsi_pack.dsi_gi.vobu_vob_idn, - d->cur_pgc->cell_position[d->cur_cell].cell_nr, - d->cur_pgc->cell_position[d->cur_cell].vob_id_nr); - - if(d->angle_seek) { - int i,skip=0; - for(i=0;i<9;i++) // check if all values zero: - if((skip=d->dsi_pack.sml_agli.data[i].address)!=0) break; - if(skip && skip!=0x7fffffff) { - // sml_agli table has valid data (at least one non-zero): - d->cur_pack=d->dsi_pack.dsi_gi.nv_pck_lbn+ - d->dsi_pack.sml_agli.data[d->dvd_angle-1].address; - d->angle_seek=0; - d->cur_pack--; - MP_VERBOSE(stream, "Angle-seek synced using sml_agli map! new_lba=0x%X \n",d->cur_pack); - } else { - // check if we're in the right cell, jump otherwise: - if( (d->dsi_pack.dsi_gi.vobu_c_idn==d->cur_pgc->cell_position[d->cur_cell].cell_nr) && - (d->dsi_pack.dsi_gi.vobu_vob_idn==d->cur_pgc->cell_position[d->cur_cell].vob_id_nr) ){ - d->angle_seek=0; - MP_VERBOSE(stream, "Angle-seek synced by cell/vob IDN search! \n"); - } else { - // wrong angle, skip this vobu: - d->cur_pack=d->dsi_pack.dsi_gi.nv_pck_lbn+ - d->dsi_pack.dsi_gi.vobu_ea; - d->angle_seek=2; // DEBUG - } - } - } - } - ++d->cur_pack; - goto read_next; - } - - ++d->cur_pack; - if(d->packs_left>=0) --d->packs_left; - - if(d->angle_seek) { - if(d->angle_seek==2) MP_VERBOSE(stream, "!!! warning! reading packet while angle_seek !!!\n"); - goto read_next; // searching for Navi packet - } - - return d->cur_pack-1; -} - -static int fill_buffer(stream_t *s, char *buf, int len) -{ - int64_t pos; - if (len < 2048) - return -1; - pos = dvd_read_sector(s, s->priv, buf); - if (pos < 0) - return -1; - return 2048; // full sector -} - -static void stream_dvd_close(stream_t *s) { - dvd_priv_t *d = s->priv; - ifoClose(d->vts_file); - ifoClose(d->vmg_file); - DVDCloseFile(d->title); - DVDClose(d->dvd); - if (d->dvd_speed) - dvd_set_speed(s,d->dvd_device_current, -1); /* -1 => restore default */ -} - -static int mp_get_titleset_length(ifo_handle_t *vts_file, tt_srpt_t *tt_srpt, int title_no) -{ - int vts_ttn; ///< title number within video title set - int pgc_no; ///< program chain number - int msec; ///< time length in milliseconds - - msec=0; - if(!vts_file || !tt_srpt) - return 0; - - if(vts_file->vtsi_mat && vts_file->vts_pgcit) - { - vts_ttn = tt_srpt->title[title_no].vts_ttn - 1; - pgc_no = vts_file->vts_ptt_srpt->title[vts_ttn].ptt[0].pgcn - 1; - msec = mp_dvdtimetomsec(&vts_file->vts_pgcit->pgci_srp[pgc_no].pgc->playback_time); - } - return msec; -} - - -static int get_num_chapter(ifo_handle_t *vts_file, tt_srpt_t *tt_srpt, int title_no) -{ - if(!vts_file || !tt_srpt) - return 0; - - if(title_no < 0 || title_no >= tt_srpt->nr_of_srpts) - return 0; - - // map global title to vts title - title_no = tt_srpt->title[title_no].vts_ttn - 1; - - if(title_no < 0 || title_no >= vts_file->vts_ptt_srpt->nr_of_srpts) - return 0; - - return vts_file->vts_ptt_srpt->title[title_no].nr_of_ptts; -} - -// p: in=chapter number, out=PTS -static int get_chapter_time(ifo_handle_t *vts_file, tt_srpt_t *tt_srpt, int title_no, double *p) -{ - unsigned int i, cell, last_cell; - unsigned int t=0; - ptt_info_t *ptt; - pgc_t *pgc; - - title_no = tt_srpt->title[title_no].vts_ttn - 1; - if(vts_file->vts_ptt_srpt->title[title_no].nr_of_ptts < 2) - return 0; - ptt = vts_file->vts_ptt_srpt->title[title_no].ptt; - - int cur = 0; - for(i=0; ivts_ptt_srpt->title[title_no].nr_of_ptts; i++) - { - pgc = vts_file->vts_pgcit->pgci_srp[ptt[i].pgcn-1].pgc; - cell = pgc->program_map[ptt[i].pgn-1]; //here the cell is 1-based - if(ptt[i].pgnnr_of_programs) - last_cell = pgc->program_map[ptt[i].pgn]; - else - last_cell = 0; - while (cell < last_cell) { - if(!(pgc->cell_playback[cell-1].block_type == BLOCK_TYPE_ANGLE_BLOCK && - pgc->cell_playback[cell-1].block_mode != BLOCK_MODE_FIRST_CELL) - ) { - if (cur == *p) { - *p = t / 1000.0; - return 1; - } - t += mp_dvdtimetomsec(&pgc->cell_playback[cell-1].playback_time); - cur++; - } - cell++; - } - } - return 0; -} - -static void list_chapters(stream_t *stream, ifo_handle_t *vts_file, tt_srpt_t *tt_srpt, int title_no) -{ - MP_INFO(stream, "CHAPTERS: "); - for (int n = 0; ; n++) { - double p = n; - int r; - r = get_chapter_time(vts_file, tt_srpt, title_no, &p); - if (!r) - break; - int t = p * 1000; - MP_INFO(stream, "%02d:%02d:%02d.%03d,", t/3600000, (t/60000)%60, (t/1000)%60, t%1000); - } - MP_INFO(stream, "\n"); -} - -static double dvd_get_current_time(stream_t *stream, int cell) -{ - int i, tm; - dvd_priv_t *d = stream->priv; - - tm=0; - if(cell < 0) cell=d->cur_cell; - for(i=0; icur_pgc->cell_playback[i].block_type == BLOCK_TYPE_ANGLE_BLOCK && - d->cur_pgc->cell_playback[i].block_mode != BLOCK_MODE_FIRST_CELL - ) - continue; - tm += d->cell_times_table[i]; - } - tm += mp_dvdtimetomsec(&d->dsi_pack.dsi_gi.c_eltm); - - return (double)tm/1000.0; -} - -static void dvd_seek(stream_t *stream, dvd_priv_t *d, int pos) -{ - d->packs_left=-1; - d->cur_pack=pos; - - // check if we stay in current cell (speedup things, and avoid angle skip) - if(d->cur_pack>d->cell_last_pack || - d->cur_packcur_pgc->cell_playback[ d->cur_cell ].first_sector) { - - // ok, cell change, find the right cell! - cell_playback_t *cell; - for(d->cur_cell=0; d->cur_cell < d->cur_pgc->nr_of_cells; d->cur_cell++) { - cell = &(d->cur_pgc->cell_playback[d->cur_cell]); - if(cell->block_type == BLOCK_TYPE_ANGLE_BLOCK && cell->block_mode != BLOCK_MODE_FIRST_CELL) - continue; - d->cell_last_pack=cell->last_sector; - if(d->cur_packfirst_sector) { - d->cur_pack=cell->first_sector; - break; - } - if(d->cur_pack<=d->cell_last_pack) break; // ok, we find it! :) - } - } - - MP_VERBOSE(stream, "DVD Seek! lba=0x%X cell=%d packs: 0x%X-0x%X \n", - d->cur_pack,d->cur_cell,d->cur_pgc->cell_playback[ d->cur_cell ].first_sector,d->cell_last_pack); - - // if we're in interleaved multi-angle cell, find the right angle chain! - // (read Navi block, and use the seamless angle jump table) - d->angle_seek=1; -} - -static int do_seek(stream_t *s, int64_t newpos) { - stream_drop_buffers(s); - dvd_seek(s, s->priv,newpos/2048); - return 1; -} - -static int dvd_seek_to_time(stream_t *stream, ifo_handle_t *vts_file, double sec) -{ - unsigned int i, j, k, timeunit, ac_time, tmap_sector=0, cell_sector=0, vobu_sector=0; - int t=0; - double tm, duration; - int64_t pos = -1; - dvd_priv_t *d = stream->priv; - vts_tmapt_t *vts_tmapt = vts_file->vts_tmapt; - - if(!vts_file->vts_tmapt || sec < 0) - return 0; - - duration = (double) mp_get_titleset_length(d->vts_file, d->tt_srpt, d->cur_title) / 1000.0f; - if(sec > duration) - return 0; - - i=d->cur_pgc_idx; - timeunit = vts_tmapt->tmap[i].tmu; - for(j = 0; j < vts_tmapt->tmap[i].nr_of_entries; j++) { - ac_time = timeunit * (j + 1); - if(ac_time >= sec) - break; - tmap_sector = vts_tmapt->tmap[i].map_ent[j] & 0x7fffffff; - } - //search enclosing cell - for(i=0; icur_pgc->nr_of_cells; i++) { - if(tmap_sector >= d->cur_pgc->cell_playback[i].first_sector && tmap_sector <= d->cur_pgc->cell_playback[i].last_sector) { - cell_sector = d->cur_pgc->cell_playback[i].first_sector; - break; - } - } - - pos = ((int64_t)cell_sector)<<11; - do_seek(stream, pos); - do { - char buf[2048]; - if (dvd_read_sector(stream, stream->priv, buf) < 0) // skip - break; - t = mp_dvdtimetomsec(&d->dsi_pack.dsi_gi.c_eltm); - } while(!t); - tm = dvd_get_current_time(stream, -1); - - pos = ((int64_t)tmap_sector)<<11; - do_seek(stream, pos); - //now get current time in terms of the cell+cell time offset - memset(&d->dsi_pack.dsi_gi.c_eltm, 0, sizeof(dvd_time_t)); - while(tm <= sec) { - char buf[2048]; - if (dvd_read_sector(stream, stream->priv, buf) < 0) // skip - break; - pos += 2048; - tm = dvd_get_current_time(stream, -1); - }; - tmap_sector = pos >> 11; - - //search closest VOBU sector - k=(vts_file->vts_vobu_admap->last_byte + 1 - VOBU_ADMAP_SIZE)/4; //entries in the vobu admap - for(i=1; ivts_vobu_admap->vobu_start_sectors[i] > tmap_sector) - break; - } - vobu_sector = vts_file->vts_vobu_admap->vobu_start_sectors[i-1]; - pos = ((int64_t)vobu_sector) << 11; - do_seek(stream, pos); - - return 1; -} - -static int control(stream_t *stream,int cmd,void* arg) -{ - dvd_priv_t *d = stream->priv; - switch(cmd) - { - case STREAM_CTRL_GET_TIME_LENGTH: - { - *((double *)arg) = (double) mp_get_titleset_length(d->vts_file, d->tt_srpt, d->cur_title)/1000.0; - return 1; - } - case STREAM_CTRL_GET_NUM_TITLES: - { - *((unsigned int *)arg) = d->vmg_file->tt_srpt->nr_of_srpts; - return 1; - } - case STREAM_CTRL_GET_TITLE_LENGTH: - { - int t = *(double *)arg; - if (t < 0 || t >= d->vmg_file->tt_srpt->nr_of_srpts) - break; - if (d->tt_srpt->title[t].title_set_nr != - d->tt_srpt->title[d->dvd_title].title_set_nr) - break; - *(double *)arg = - mp_get_titleset_length(d->vts_file, d->tt_srpt, t) / 1000.0; - return 1; - } - case STREAM_CTRL_GET_NUM_CHAPTERS: - { - int r; - r = get_num_chapter(d->vts_file, d->tt_srpt, d->cur_title); - if(! r) return STREAM_UNSUPPORTED; - *((unsigned int *)arg) = r; - return 1; - } - case STREAM_CTRL_GET_CHAPTER_TIME: - { - int r; - r = get_chapter_time(d->vts_file, d->tt_srpt, d->cur_title, (double *)arg); - if(! r) return STREAM_UNSUPPORTED; - return 1; - } - case STREAM_CTRL_GET_CURRENT_TITLE: - { - *((unsigned int *)arg) = d->cur_title; - return 1; - } - case STREAM_CTRL_GET_CURRENT_TIME: - { - double tm; - tm = dvd_get_current_time(stream, -1); - if(tm != -1) { - *((double *)arg) = tm; - return 1; - } - break; - } - case STREAM_CTRL_SEEK_TO_TIME: - { - if(dvd_seek_to_time(stream, d->vts_file, *((double*)arg))) - return 1; - break; - } - case STREAM_CTRL_GET_ASPECT_RATIO: - { - *((double *)arg) = !d->vts_file->vtsi_mat->vts_video_attr.display_aspect_ratio ? 4.0/3.0 : 16.0/9.0; - return 1; - } - case STREAM_CTRL_GET_NUM_ANGLES: - { - *((int *)arg) = d->vmg_file->tt_srpt->title[d->dvd_title].nr_of_angles; - return 1; - } - case STREAM_CTRL_GET_ANGLE: - { - *((int *)arg) = d->dvd_angle; - return 1; - } - case STREAM_CTRL_SET_ANGLE: - { - int ang = *((int *)arg); - if(ang>d->vmg_file->tt_srpt->title[d->dvd_title].nr_of_angles || ang<=0) - break; - d->dvd_angle = ang; - d->angle_seek = 1; - return 1; - } - case STREAM_CTRL_GET_LANG: - { - struct stream_lang_req *req = arg; - int lang = 0; - switch(req->type) { - case STREAM_AUDIO: - lang = dvd_lang_from_aid(stream, req->id); - break; - case STREAM_SUB: - lang = dvd_lang_from_sid(stream, req->id); - break; - } - if (!lang) - break; - snprintf(req->name, sizeof(req->name), "%c%c", lang >> 8, lang); - return STREAM_OK; - } - case STREAM_CTRL_GET_DVD_INFO: - { - struct stream_dvd_info_req *req = arg; - memset(req, 0, sizeof(*req)); - req->num_subs = dvd_number_of_subs(stream); - memcpy(req->palette, d->cur_pgc->palette, sizeof(req->palette)); - return STREAM_OK; - } - case STREAM_CTRL_GET_DISC_NAME: - { - char buffer[128]; - if (DVDUDFVolumeInfo(d->dvd, buffer, sizeof(buffer), NULL, 0) < 0 && - DVDISOVolumeInfo(d->dvd, buffer, sizeof(buffer), NULL, 0) < 0) - break; - if (!buffer[0]) - break; - *(char**)arg = talloc_strdup(NULL, buffer); - return STREAM_OK; - } - case STREAM_CTRL_GET_SIZE: - *(int64_t *)arg = - (d->cur_pgc->cell_playback[d->last_cell-1].last_sector)*2048LL; - return STREAM_OK; - } - return STREAM_UNSUPPORTED; -} - - -static int open_s_internal(stream_t *stream) -{ - int k; - dvd_priv_t *d = stream->priv; - - struct dvd_opts *opts = - mp_get_config_group(stream, stream->global, &dvd_conf); - - d->dvd_angle = opts->angle; - - MP_VERBOSE(stream, "URL: %s\n", stream->url); - d->dvd_title = d->cfg_title + 1; - if(1){ - //int ret,ret2; - int ttn,pgc_id,pgn; - dvd_reader_t *dvd; - dvd_file_t *title; - ifo_handle_t *vmg_file; - tt_srpt_t *tt_srpt; - ifo_handle_t *vts_file; - pgc_t *pgc; - /** - * Open the disc. - */ - if(d->cfg_device && d->cfg_device[0]) - d->dvd_device_current = d->cfg_device; - else if(opts->device && opts->device[0]) - d->dvd_device_current = talloc_strdup(stream, opts->device); - else - d->dvd_device_current = DEFAULT_DVD_DEVICE; - d->dvd_speed = opts->speed; - dvd_set_speed(stream,d->dvd_device_current, d->dvd_speed); -#if defined(__APPLE__) || defined(__DARWIN__) - /* Dynamic DVD drive selection on Darwin */ - if(!strcmp(d->dvd_device_current, "/dev/rdiskN")) { - int i; - size_t len = strlen(d->dvd_device_current)+1; - char *temp_device = malloc(len); - - for (i = 1; i < 10; i++) { - snprintf(temp_device, len, "/dev/rdisk%d", i); - dvd = DVDOpen(temp_device); - if(!dvd) { - MP_ERR(stream, "Couldn't open DVD device: %s (%s)\n",temp_device, - mp_strerror(errno)); - } else { -#if DVDREAD_VERSION <= LIBDVDREAD_VERSION(0,9,4) - dvd_file_t *dvdfile = DVDOpenFile(dvd,d->dvd_title,DVD_READ_INFO_FILE); - if(!dvdfile) { - MP_ERR(stream, "Couldn't open DVD device: %s (%s)\n",temp_device, - mp_strerror(errno)); - DVDClose(dvd); - continue; - } - DVDCloseFile(dvdfile); -#endif - break; - } - } - free(temp_device); - - if(!dvd) { - return STREAM_UNSUPPORTED; - } - } else -#endif /* defined(__APPLE__) || defined(__DARWIN__) */ - { - dvd = DVDOpen(d->dvd_device_current); - if(!dvd) { - MP_ERR(stream, "Couldn't open DVD device: %s (%s)\n", - d->dvd_device_current, mp_strerror(errno)); - return STREAM_UNSUPPORTED; - } - } - - MP_VERBOSE(stream, "Reading disc structure, please wait...\n"); - - /** - * Load the video manager to find out the information about the titles on - * this disc. - */ - vmg_file = ifoOpen(dvd, 0); - if(!vmg_file) { - MP_ERR(stream, "Can't open VMG info!\n"); - DVDClose( dvd ); - return STREAM_UNSUPPORTED; - } - tt_srpt = vmg_file->tt_srpt; - /** - * Make sure our title number is valid. - */ - MP_INFO(stream, "There are %d titles on this DVD.\n", tt_srpt->nr_of_srpts ); - if(d->dvd_title < 1 || d->dvd_title > tt_srpt->nr_of_srpts) { - MP_ERR(stream, "Invalid DVD title number: %d\n", d->dvd_title); - ifoClose( vmg_file ); - DVDClose( dvd ); - return STREAM_UNSUPPORTED; - } - --(d->dvd_title); // remap 1.. -> 0.. - /** - * Make sure the angle number is valid for this title. - */ - MP_INFO(stream, "There are %d angles in this DVD title.\n", tt_srpt->title[d->dvd_title].nr_of_angles); - if(d->dvd_angle<1 || d->dvd_angle>tt_srpt->title[d->dvd_title].nr_of_angles) { - MP_ERR(stream, "Invalid DVD angle number: %d\n", d->dvd_angle); - goto fail; - } - - ttn = tt_srpt->title[d->dvd_title].vts_ttn - 1; - /** - * Load the VTS information for the title set our title is in. - */ - vts_file = ifoOpen( dvd, tt_srpt->title[d->dvd_title].title_set_nr ); - if(!vts_file) { - MP_ERR(stream, "Cannot open the IFO file for DVD title %d.\n", tt_srpt->title[d->dvd_title].title_set_nr ); - goto fail; - } - /** - * We've got enough info, time to open the title set data. - */ - title = DVDOpenFile(dvd, tt_srpt->title[d->dvd_title].title_set_nr, DVD_READ_TITLE_VOBS); - if(!title) { - MP_ERR(stream, "Cannot open title VOBS (VTS_%02d_1.VOB).\n", tt_srpt->title[d->dvd_title].title_set_nr); - ifoClose( vts_file ); - goto fail; - } - - MP_VERBOSE(stream, "DVD successfully opened.\n"); - // store data - d->dvd=dvd; - d->title=title; - d->vmg_file=vmg_file; - d->tt_srpt=tt_srpt; - d->vts_file=vts_file; - d->cur_title = d->dvd_title; - - pgc_id = vts_file->vts_ptt_srpt->title[ttn].ptt[0].pgcn; // local - pgn = vts_file->vts_ptt_srpt->title[ttn].ptt[0].pgn; // local - pgc = vts_file->vts_pgcit ? vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc : NULL; - /** - * Check number of audio channels and types - */ - { - d->nr_of_channels=0; - if(vts_file->vts_pgcit) { - int i; - for(i=0;i<8;i++) - if(pgc->audio_control[i] & 0x8000) { - audio_attr_t * audio = &vts_file->vtsi_mat->vts_audio_attr[i]; - int language = 0; - char tmp[] = "unknown"; - stream_language_t *audio_stream = &d->audio_streams[d->nr_of_channels]; - - if(audio->lang_type == 1) { - language=audio->lang_code; - tmp[0]=language>>8; - tmp[1]=language&0xff; - tmp[2]=0; - } - - audio_stream->language=language; - audio_stream->id=pgc->audio_control[i] >> 8 & 7; - switch(audio->audio_format) { - case 0: // ac3 - audio_stream->id+=FIRST_AC3_AID; - break; - case 6: // dts - audio_stream->id+=FIRST_DTS_AID; - break; - case 2: // mpeg layer 1/2/3 - case 3: // mpeg2 ext - audio_stream->id+=FIRST_MPG_AID; - break; - case 4: // lpcm - audio_stream->id+=FIRST_PCM_AID; - break; - } - - audio_stream->type=audio->audio_format; - // Pontscho: to my mind, tha channels: - // 1 - stereo - // 5 - 5.1 - audio_stream->channels=audio->channels; - MP_INFO(stream, "audio stream: %d format: %s (%s) language: %s aid: %d.\n", - d->nr_of_channels, - dvd_audio_stream_types[ audio->audio_format ], - dvd_audio_stream_channels[ audio->channels ], - tmp, - audio_stream->id - ); - - d->nr_of_channels++; - } - } - MP_INFO(stream, "number of audio channels on disk: %d.\n",d->nr_of_channels ); - } - - /** - * Check number of subtitles and language - */ - { - int i; - - d->nr_of_subtitles=0; - for(i=0;i<32;i++) - if(pgc->subp_control[i] & 0x80000000) { - subp_attr_t * subtitle = &vts_file->vtsi_mat->vts_subp_attr[i]; - video_attr_t *video = &vts_file->vtsi_mat->vts_video_attr; - int language = 0; - char tmp[] = "unknown"; - stream_language_t *sub_stream = &d->subtitles[d->nr_of_subtitles]; - - if(subtitle->type == 1) { - language=subtitle->lang_code; - tmp[0]=language>>8; - tmp[1]=language&0xff; - tmp[2]=0; - } - - sub_stream->language=language; - sub_stream->id=d->nr_of_subtitles; - if(video->display_aspect_ratio == 0) /* 4:3 */ - sub_stream->id = pgc->subp_control[i] >> 24 & 31; - else if(video->display_aspect_ratio == 3) /* 16:9 */ - sub_stream->id = pgc->subp_control[i] >> 8 & 31; - - MP_INFO(stream, "subtitle ( sid ): %d language: %s\n", sub_stream->id, tmp); - d->nr_of_subtitles++; - } - MP_INFO(stream, "number of subtitles on disk: %d\n",d->nr_of_subtitles); - } - - /** - * Determine which program chain we want to watch. This is based on the - * chapter number. - */ - d->cur_pgc_idx = pgc_id-1; - d->cur_pgc = vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc; - d->cur_cell = d->cur_pgc->program_map[pgn-1] - 1; // start playback here - d->packs_left=-1; // for Navi stuff - d->angle_seek=0; - d->last_cell=d->cur_pgc->nr_of_cells; - - if(d->cur_pgc->cell_playback[d->cur_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK ) - d->cur_cell+=d->dvd_angle-1; - d->cur_pack = d->cur_pgc->cell_playback[ d->cur_cell ].first_sector; - d->cell_last_pack=d->cur_pgc->cell_playback[ d->cur_cell ].last_sector; - MP_VERBOSE(stream, "DVD start cell: %d pack: 0x%X-0x%X \n",d->cur_cell,d->cur_pack,d->cell_last_pack); - - //assign cell_times_table - d->cell_times_table = malloc(sizeof(unsigned int) * d->cur_pgc->nr_of_cells); - if(d->cell_times_table == NULL) - return STREAM_UNSUPPORTED; - for(k=0; kcur_pgc->nr_of_cells; k++) - d->cell_times_table[k] = mp_dvdtimetomsec(&d->cur_pgc->cell_playback[k].playback_time); - list_chapters(stream, vts_file,tt_srpt,d->dvd_title); - - // ... (unimplemented) - // return NULL; - stream->demuxer = "+disc"; - stream->lavf_type = "mpeg"; - stream->sector_size = 2048; - stream->fill_buffer = fill_buffer; - stream->control = control; - stream->close = stream_dvd_close; - MP_VERBOSE(stream, "DVD start=%d end=%d \n",d->cur_pack,d->cur_pgc->cell_playback[d->last_cell-1].last_sector); - stream->priv = (void*)d; - return STREAM_OK; - -fail: - ifoClose(vmg_file); - DVDClose(dvd); - return STREAM_UNSUPPORTED; - } - MP_ERR(stream, "mpv was compiled without DVD support, exiting.\n"); - return STREAM_UNSUPPORTED; -} - -static int open_s(stream_t *stream) -{ - dvd_priv_t *d = talloc_zero(stream, dvd_priv_t); - stream->priv = d; - - bstr title, bdevice; - bstr_split_tok(bstr0(stream->path), "/", &title, &bdevice); - - if (title.len) { - bstr rest; - d->cfg_title = bstrtoll(title, &rest, 10); - if (rest.len) { - MP_ERR(stream, "number expected: '%.*s'\n", BSTR_P(rest)); - return STREAM_ERROR; - } - } - - d->cfg_device = bstrto0(d, bdevice); - - return open_s_internal(stream); -} - -static int ifo_stream_open(stream_t *stream) -{ - dvd_priv_t *priv = talloc_zero(stream, dvd_priv_t); - stream->priv = priv; - - if (!stream->access_references) - goto unsupported; - - char *path = mp_file_get_path(priv, bstr0(stream->url)); - if (!path) - goto unsupported; - - if (!dvd_probe(path, ".ifo", "DVDVIDEO-VTS")) - goto unsupported; - - char *base = mp_basename(path); - - // Only accept individual titles - use dvdnav for video_ts.ifo - if (strncasecmp(base, "vts_", 4)) - goto unsupported; - - if (sscanf(base + 3, "_%02d_", &priv->cfg_title) != 1) - goto unsupported; - - priv->cfg_device = bstrto0(priv, mp_dirname(path)); - - MP_INFO(stream, ".IFO detected. Redirecting to dvdread://\n"); - return open_s_internal(stream); - -unsupported: - talloc_free(priv); - stream->priv = NULL; - return STREAM_UNSUPPORTED; -} - -const stream_info_t stream_info_dvd = { - .name = "dvd", - .open = open_s, - .protocols = (const char*const[]){ "dvdread", NULL }, -}; - -const stream_info_t stream_info_ifo = { - .name = "ifo", - .open = ifo_stream_open, - .protocols = (const char*const[]){ "file", "", NULL }, -}; diff --git a/stream/stream_dvd_common.c b/stream/stream_dvd_common.c deleted file mode 100644 index 82da42e85c..0000000000 --- a/stream/stream_dvd_common.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "config.h" - -#include - -#ifdef __FreeBSD__ -#include -#endif - -#ifdef __linux__ -#include -#include -#include -#include -#include -#endif - -#include "osdep/io.h" - -#include "common/msg.h" -#include "misc/bstr.h" -#include "stream_dvd_common.h" - -const char * const dvd_audio_stream_types[8] = { "ac3","unknown","mpeg1","mpeg2ext","lpcm","unknown","dts" }; -const char * const dvd_audio_stream_channels[6] = { "mono", "stereo", "unknown", "unknown", "5.1/6.1", "5.1" }; - -void dvd_set_speed(stream_t *stream, char *device, unsigned speed) -{ -#if defined(__linux__) && defined(SG_IO) && defined(GPCMD_SET_STREAMING) - int fd; - unsigned char buffer[28]; - unsigned char cmd[12]; - struct sg_io_hdr sghdr; - struct stat st; - - memset(&st, 0, sizeof(st)); - - if (stat(device, &st) == -1) return; - - if (!S_ISBLK(st.st_mode)) return; /* not a block device */ - - switch (speed) { - case 0: /* don't touch speed setting */ - return; - case -1: /* restore default value */ - MP_INFO(stream, "Restoring DVD speed... "); - break; - default: /* limit to KB/s */ - // speed < 100 is multiple of DVD single speed (1350KB/s) - if (speed < 100) - speed *= 1350; - MP_INFO(stream, "Limiting DVD speed to %dKB/s... ", speed); - break; - } - - memset(&sghdr, 0, sizeof(sghdr)); - sghdr.interface_id = 'S'; - sghdr.timeout = 5000; - sghdr.dxfer_direction = SG_DXFER_TO_DEV; - sghdr.dxfer_len = sizeof(buffer); - sghdr.dxferp = buffer; - sghdr.cmd_len = sizeof(cmd); - sghdr.cmdp = cmd; - - memset(cmd, 0, sizeof(cmd)); - cmd[0] = GPCMD_SET_STREAMING; - cmd[10] = sizeof(buffer); - - memset(buffer, 0, sizeof(buffer)); - /* first sector 0, last sector 0xffffffff */ - AV_WB32(buffer + 8, 0xffffffff); - if (speed == -1) - buffer[0] = 4; /* restore default */ - else { - /* kilobyte */ - AV_WB32(buffer + 12, speed); - AV_WB32(buffer + 20, speed); - } - /* 1 second */ - AV_WB16(buffer + 18, 1000); - AV_WB16(buffer + 26, 1000); - - fd = open(device, O_RDWR | O_NONBLOCK | O_CLOEXEC); - if (fd == -1) { - MP_INFO(stream, "Couldn't open DVD device for writing, changing DVD speed needs write access.\n"); - return; - } - - if (ioctl(fd, SG_IO, &sghdr) < 0) - MP_INFO(stream, "failed\n"); - else - MP_INFO(stream, "successful\n"); - - close(fd); -#endif -} - -/** -\brief Converts DVD time structure to milliseconds. -\param *dev the DVD time structure to convert -\return returns the time in milliseconds -*/ -int mp_dvdtimetomsec(dvd_time_t *dt) -{ - int framerates[4] = {0, 2500, 0, 2997}; - int framerate = framerates[(dt->frame_u & 0xc0) >> 6]; - int msec = (((dt->hour & 0xf0) >> 3) * 5 + (dt->hour & 0x0f)) * 3600000; - msec += (((dt->minute & 0xf0) >> 3) * 5 + (dt->minute & 0x0f)) * 60000; - msec += (((dt->second & 0xf0) >> 3) * 5 + (dt->second & 0x0f)) * 1000; - if(framerate > 0) - msec += (((dt->frame_u & 0x30) >> 3) * 5 + (dt->frame_u & 0x0f)) * 100000 / framerate; - return msec; -} - -// Check if this is likely to be an .ifo or similar file. -int dvd_probe(const char *path, const char *ext, const char *sig) -{ - if (!bstr_case_endswith(bstr0(path), bstr0(ext))) - return false; - - FILE *temp = fopen(path, "rb"); - if (!temp) - return false; - - bool r = false; - - char data[50]; - - assert(strlen(sig) <= sizeof(data)); - - if (fread(data, 50, 1, temp) == 1) { - if (memcmp(data, sig, strlen(sig)) == 0) - r = true; - } - - fclose(temp); - return r; -} diff --git a/stream/stream_dvd_common.h b/stream/stream_dvd_common.h deleted file mode 100644 index dccf49246c..0000000000 --- a/stream/stream_dvd_common.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#ifndef MPLAYER_STREAM_DVD_COMMON_H -#define MPLAYER_STREAM_DVD_COMMON_H - -#include -#include -#include "stream.h" - -#include "config.h" -#if !HAVE_GPL -#error GPL only -#endif - -extern const char * const dvd_audio_stream_channels[6]; -extern const char * const dvd_audio_stream_types[8]; - -void dvd_set_speed(stream_t *stream, char *device, unsigned speed); -int mp_dvdtimetomsec(dvd_time_t *dt); - -int dvd_probe(const char *path, const char *ext, const char *sig); - -#endif /* MPLAYER_STREAM_DVD_COMMON_H */ diff --git a/stream/stream_dvdnav.c b/stream/stream_dvdnav.c deleted file mode 100644 index 55ce771896..0000000000 --- a/stream/stream_dvdnav.c +++ /dev/null @@ -1,611 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include - -#include "config.h" - -#if !HAVE_GPL -#error GPL only -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "osdep/io.h" - -#include "options/options.h" -#include "common/msg.h" -#include "input/input.h" -#include "options/m_config.h" -#include "options/path.h" -#include "osdep/timer.h" -#include "stream.h" -#include "demux/demux.h" -#include "video/out/vo.h" -#include "stream_dvd_common.h" - -#define TITLE_MENU -1 -#define TITLE_LONGEST -2 - -struct priv { - dvdnav_t *dvdnav; // handle to libdvdnav stuff - char *filename; // path - unsigned int duration; // in milliseconds - int mousex, mousey; - int title; - uint32_t spu_clut[16]; - bool spu_clut_valid; - bool had_initial_vts; - - int dvd_speed; - - int track; - char *device; - - struct dvd_opts *opts; -}; - -#define DNE(e) [e] = # e -static const char *const mp_dvdnav_events[] = { - DNE(DVDNAV_BLOCK_OK), - DNE(DVDNAV_NOP), - DNE(DVDNAV_STILL_FRAME), - DNE(DVDNAV_SPU_STREAM_CHANGE), - DNE(DVDNAV_AUDIO_STREAM_CHANGE), - DNE(DVDNAV_VTS_CHANGE), - DNE(DVDNAV_CELL_CHANGE), - DNE(DVDNAV_NAV_PACKET), - DNE(DVDNAV_STOP), - DNE(DVDNAV_HIGHLIGHT), - DNE(DVDNAV_SPU_CLUT_CHANGE), - DNE(DVDNAV_HOP_CHANNEL), - DNE(DVDNAV_WAIT), -}; - -#define LOOKUP_NAME(array, i) \ - (((i) >= 0 && (i) < MP_ARRAY_SIZE(array)) ? array[(i)] : "?") - -/** - * \brief mp_dvdnav_lang_from_aid() returns the language corresponding to audio id 'aid' - * \param stream: - stream pointer - * \param sid: physical subtitle id - * \return 0 on error, otherwise language id - */ -static int mp_dvdnav_lang_from_aid(stream_t *stream, int aid) -{ - uint8_t lg; - uint16_t lang; - struct priv *priv = stream->priv; - - if (aid < 0) - return 0; - lg = dvdnav_get_audio_logical_stream(priv->dvdnav, aid & 0x7); - if (lg == 0xff) - return 0; - lang = dvdnav_audio_stream_to_lang(priv->dvdnav, lg); - if (lang == 0xffff) - return 0; - return lang; -} - -/** - * \brief mp_dvdnav_lang_from_sid() returns the language corresponding to subtitle id 'sid' - * \param stream: - stream pointer - * \param sid: physical subtitle id - * \return 0 on error, otherwise language id - */ -static int mp_dvdnav_lang_from_sid(stream_t *stream, int sid) -{ - uint8_t k; - uint16_t lang; - struct priv *priv = stream->priv; - if (sid < 0) - return 0; - for (k = 0; k < 32; k++) - if (dvdnav_get_spu_logical_stream(priv->dvdnav, k) == sid) - break; - if (k == 32) - return 0; - lang = dvdnav_spu_stream_to_lang(priv->dvdnav, k); - if (lang == 0xffff) - return 0; - return lang; -} - -/** - * \brief mp_dvdnav_number_of_subs() returns the count of available subtitles - * \param stream: - stream pointer - * \return 0 on error, something meaningful otherwise - */ -static int mp_dvdnav_number_of_subs(stream_t *stream) -{ - struct priv *priv = stream->priv; - uint8_t lg, k, n = 0; - - for (k = 0; k < 32; k++) { - lg = dvdnav_get_spu_logical_stream(priv->dvdnav, k); - if (lg == 0xff) - continue; - if (lg >= n) - n = lg + 1; - } - return n; -} - -static int fill_buffer(stream_t *s, char *buf, int max_len) -{ - struct priv *priv = s->priv; - dvdnav_t *dvdnav = priv->dvdnav; - - if (max_len < 2048) - return -1; - - while (1) { - int len = -1; - int event = DVDNAV_NOP; - if (dvdnav_get_next_block(dvdnav, buf, &event, &len) != DVDNAV_STATUS_OK) - { - MP_ERR(s, "Error getting next block from DVD %d (%s)\n", - event, dvdnav_err_to_string(dvdnav)); - return 0; - } - if (event != DVDNAV_BLOCK_OK) { - const char *name = LOOKUP_NAME(mp_dvdnav_events, event); - MP_VERBOSE(s, "DVDNAV: event %s (%d).\n", name, event); - } - switch (event) { - case DVDNAV_BLOCK_OK: - return len; - case DVDNAV_STOP: - return 0; - case DVDNAV_NAV_PACKET: { - pci_t *pnavpci = dvdnav_get_current_nav_pci(dvdnav); - uint32_t start_pts = pnavpci->pci_gi.vobu_s_ptm; - MP_TRACE(s, "start pts = %"PRIu32"\n", start_pts); - break; - } - case DVDNAV_STILL_FRAME: - dvdnav_still_skip(dvdnav); - return 0; - case DVDNAV_WAIT: - dvdnav_wait_skip(dvdnav); - return 0; - case DVDNAV_HIGHLIGHT: - break; - case DVDNAV_VTS_CHANGE: { - int tit = 0, part = 0; - dvdnav_vts_change_event_t *vts_event = - (dvdnav_vts_change_event_t *)s->buffer; - MP_INFO(s, "DVDNAV, switched to title: %d\n", - vts_event->new_vtsN); - if (!priv->had_initial_vts) { - // dvdnav sends an initial VTS change before any data; don't - // cause a blocking wait for the player, because the player in - // turn can't initialize the demuxer without data. - priv->had_initial_vts = true; - break; - } - if (dvdnav_current_title_info(dvdnav, &tit, &part) == DVDNAV_STATUS_OK) - { - MP_VERBOSE(s, "DVDNAV, NEW TITLE %d\n", tit); - if (priv->title > 0 && tit != priv->title) - MP_WARN(s, "Requested title not found\n"); - } - break; - } - case DVDNAV_CELL_CHANGE: { - dvdnav_cell_change_event_t *ev = (dvdnav_cell_change_event_t *)buf; - - if (ev->pgc_length) - priv->duration = ev->pgc_length / 90; - - break; - } - case DVDNAV_SPU_CLUT_CHANGE: { - memcpy(priv->spu_clut, buf, 16 * sizeof(uint32_t)); - priv->spu_clut_valid = true; - break; - } - } - } - return 0; -} - -static int control(stream_t *stream, int cmd, void *arg) -{ - struct priv *priv = stream->priv; - dvdnav_t *dvdnav = priv->dvdnav; - int tit, part; - - switch (cmd) { - case STREAM_CTRL_GET_NUM_CHAPTERS: { - if (dvdnav_current_title_info(dvdnav, &tit, &part) != DVDNAV_STATUS_OK) - break; - if (dvdnav_get_number_of_parts(dvdnav, tit, &part) != DVDNAV_STATUS_OK) - break; - if (!part) - break; - *(unsigned int *)arg = part; - return 1; - } - case STREAM_CTRL_GET_CHAPTER_TIME: { - double *ch = arg; - int chapter = *ch; - if (dvdnav_current_title_info(dvdnav, &tit, &part) != DVDNAV_STATUS_OK) - break; - uint64_t *parts = NULL, duration = 0; - int n = dvdnav_describe_title_chapters(dvdnav, tit, &parts, &duration); - if (!parts) - break; - if (chapter < 0 || chapter + 1 > n) - break; - *ch = chapter > 0 ? parts[chapter - 1] / 90000.0 : 0; - free(parts); - return 1; - } - case STREAM_CTRL_GET_TIME_LENGTH: { - if (priv->duration) { - *(double *)arg = (double)priv->duration / 1000.0; - return 1; - } - break; - } - case STREAM_CTRL_GET_ASPECT_RATIO: { - uint8_t ar = dvdnav_get_video_aspect(dvdnav); - *(double *)arg = !ar ? 4.0 / 3.0 : 16.0 / 9.0; - return 1; - } - case STREAM_CTRL_GET_CURRENT_TIME: { - double tm; - tm = dvdnav_get_current_time(dvdnav) / 90000.0f; - if (tm != -1) { - *(double *)arg = tm; - return 1; - } - break; - } - case STREAM_CTRL_GET_NUM_TITLES: { - int32_t num_titles = 0; - if (dvdnav_get_number_of_titles(dvdnav, &num_titles) != DVDNAV_STATUS_OK) - break; - *((unsigned int*)arg)= num_titles; - return STREAM_OK; - } - case STREAM_CTRL_GET_TITLE_LENGTH: { - int t = *(double *)arg; - int32_t num_titles = 0; - if (dvdnav_get_number_of_titles(dvdnav, &num_titles) != DVDNAV_STATUS_OK) - break; - if (t < 0 || t >= num_titles) - break; - uint64_t duration = 0; - uint64_t *parts = NULL; - dvdnav_describe_title_chapters(dvdnav, t + 1, &parts, &duration); - if (!parts) - break; - free(parts); - *(double *)arg = duration / 90000.0; - return STREAM_OK; - } - case STREAM_CTRL_GET_CURRENT_TITLE: { - if (dvdnav_current_title_info(dvdnav, &tit, &part) != DVDNAV_STATUS_OK) - break; - *((unsigned int *) arg) = tit - 1; - return STREAM_OK; - } - case STREAM_CTRL_SET_CURRENT_TITLE: { - int title = *((unsigned int *) arg); - if (dvdnav_title_play(priv->dvdnav, title + 1) != DVDNAV_STATUS_OK) - break; - stream_drop_buffers(stream); - return STREAM_OK; - } - case STREAM_CTRL_SEEK_TO_TIME: { - double *args = arg; - double d = args[0]; // absolute target timestamp - int flags = args[1]; // from SEEK_* flags (demux.h) - if (flags & SEEK_HR) - d -= 10; // fudge offset; it's a hack, because fuck libdvd* - int64_t tm = (int64_t)(d * 90000); - if (tm < 0) - tm = 0; - if (priv->duration && tm >= (priv->duration * 90)) - tm = priv->duration * 90 - 1; - uint32_t pos, len; - if (dvdnav_get_position(dvdnav, &pos, &len) != DVDNAV_STATUS_OK) - break; - MP_VERBOSE(stream, "seek to PTS %f (%"PRId64")\n", d, tm); - if (dvdnav_time_search(dvdnav, tm) != DVDNAV_STATUS_OK) - break; - stream_drop_buffers(stream); - d = dvdnav_get_current_time(dvdnav) / 90000.0f; - MP_VERBOSE(stream, "landed at: %f\n", d); - if (dvdnav_get_position(dvdnav, &pos, &len) == DVDNAV_STATUS_OK) - MP_VERBOSE(stream, "block: %lu\n", (unsigned long)pos); - return STREAM_OK; - } - case STREAM_CTRL_GET_NUM_ANGLES: { - uint32_t curr, angles; - if (dvdnav_get_angle_info(dvdnav, &curr, &angles) != DVDNAV_STATUS_OK) - break; - *(int *)arg = angles; - return 1; - } - case STREAM_CTRL_GET_ANGLE: { - uint32_t curr, angles; - if (dvdnav_get_angle_info(dvdnav, &curr, &angles) != DVDNAV_STATUS_OK) - break; - *(int *)arg = curr; - return 1; - } - case STREAM_CTRL_SET_ANGLE: { - uint32_t curr, angles; - int new_angle = *(int *)arg; - if (dvdnav_get_angle_info(dvdnav, &curr, &angles) != DVDNAV_STATUS_OK) - break; - if (new_angle > angles || new_angle < 1) - break; - if (dvdnav_angle_change(dvdnav, new_angle) != DVDNAV_STATUS_OK) - return 1; - } - case STREAM_CTRL_GET_LANG: { - struct stream_lang_req *req = arg; - int lang = 0; - switch (req->type) { - case STREAM_AUDIO: - lang = mp_dvdnav_lang_from_aid(stream, req->id); - break; - case STREAM_SUB: - lang = mp_dvdnav_lang_from_sid(stream, req->id); - break; - } - if (!lang) - break; - snprintf(req->name, sizeof(req->name), "%c%c", lang >> 8, lang); - return STREAM_OK; - } - case STREAM_CTRL_GET_DVD_INFO: { - struct stream_dvd_info_req *req = arg; - memset(req, 0, sizeof(*req)); - req->num_subs = mp_dvdnav_number_of_subs(stream); - assert(sizeof(uint32_t) == sizeof(unsigned int)); - memcpy(req->palette, priv->spu_clut, sizeof(req->palette)); - return STREAM_OK; - } - case STREAM_CTRL_GET_DISC_NAME: { - const char *volume = NULL; - if (dvdnav_get_title_string(dvdnav, &volume) != DVDNAV_STATUS_OK) - break; - if (!volume || !volume[0]) - break; - *(char**)arg = talloc_strdup(NULL, volume); - return STREAM_OK; - } - } - - return STREAM_UNSUPPORTED; -} - -static void stream_dvdnav_close(stream_t *s) -{ - struct priv *priv = s->priv; - dvdnav_close(priv->dvdnav); - priv->dvdnav = NULL; - if (priv->dvd_speed) - dvd_set_speed(s, priv->filename, -1); - if (priv->filename) - free(priv->filename); -} - -static struct priv *new_dvdnav_stream(stream_t *stream, char *filename) -{ - struct priv *priv = stream->priv; - const char *title_str; - - if (!filename) - return NULL; - - if (!(priv->filename = strdup(filename))) - return NULL; - - priv->dvd_speed = priv->opts->speed; - dvd_set_speed(stream, priv->filename, priv->dvd_speed); - - if (dvdnav_open(&(priv->dvdnav), priv->filename) != DVDNAV_STATUS_OK) { - free(priv->filename); - priv->filename = NULL; - return NULL; - } - - if (!priv->dvdnav) - return NULL; - - dvdnav_set_readahead_flag(priv->dvdnav, 1); - if (dvdnav_set_PGC_positioning_flag(priv->dvdnav, 1) != DVDNAV_STATUS_OK) - MP_ERR(stream, "stream_dvdnav, failed to set PGC positioning\n"); - /* report the title?! */ - dvdnav_get_title_string(priv->dvdnav, &title_str); - - return priv; -} - -static int open_s_internal(stream_t *stream) -{ - struct priv *priv, *p; - priv = p = stream->priv; - char *filename; - - p->opts = mp_get_config_group(stream, stream->global, &dvd_conf); - - if (p->device && p->device[0]) - filename = p->device; - else if (p->opts->device && p->opts->device[0]) - filename = p->opts->device; - else - filename = DEFAULT_DVD_DEVICE; - if (!new_dvdnav_stream(stream, filename)) { - MP_ERR(stream, "Couldn't open DVD device: %s\n", - filename); - return STREAM_UNSUPPORTED; - } - - if (p->track == TITLE_LONGEST) { // longest - dvdnav_t *dvdnav = priv->dvdnav; - uint64_t best_length = 0; - int best_title = -1; - int32_t num_titles; - if (dvdnav_get_number_of_titles(dvdnav, &num_titles) == DVDNAV_STATUS_OK) { - MP_VERBOSE(stream, "List of available titles:\n"); - for (int n = 1; n <= num_titles; n++) { - uint64_t *parts = NULL, duration = 0; - dvdnav_describe_title_chapters(dvdnav, n, &parts, &duration); - if (parts) { - if (duration > best_length) { - best_length = duration; - best_title = n; - } - if (duration > 90000) { // arbitrarily ignore <1s titles - char *time = mp_format_time(duration / 90000, false); - MP_VERBOSE(stream, "title: %3d duration: %s\n", - n - 1, time); - talloc_free(time); - } - free(parts); - } - } - } - p->track = best_title - 1; - MP_INFO(stream, "Selecting title %d.\n", p->track); - } - - if (p->track >= 0) { - priv->title = p->track; - if (dvdnav_title_play(priv->dvdnav, p->track + 1) != DVDNAV_STATUS_OK) { - MP_FATAL(stream, "dvdnav_stream, couldn't select title %d, error '%s'\n", - p->track, dvdnav_err_to_string(priv->dvdnav)); - return STREAM_UNSUPPORTED; - } - } else { - MP_FATAL(stream, "DVD menu support has been removed.\n"); - return STREAM_ERROR; - } - if (p->opts->angle > 1) - dvdnav_angle_change(priv->dvdnav, p->opts->angle); - - stream->sector_size = 2048; - stream->fill_buffer = fill_buffer; - stream->control = control; - stream->close = stream_dvdnav_close; - stream->demuxer = "+disc"; - stream->lavf_type = "mpeg"; - - return STREAM_OK; -} - -static int open_s(stream_t *stream) -{ - struct priv *priv = talloc_zero(stream, struct priv); - stream->priv = priv; - - bstr title, bdevice; - bstr_split_tok(bstr0(stream->path), "/", &title, &bdevice); - - priv->track = TITLE_LONGEST; - - if (bstr_equals0(title, "longest") || bstr_equals0(title, "first")) { - priv->track = TITLE_LONGEST; - } else if (bstr_equals0(title, "menu")) { - priv->track = TITLE_MENU; - } else if (title.len) { - bstr rest; - priv->track = bstrtoll(title, &rest, 10); - if (rest.len) { - MP_ERR(stream, "number expected: '%.*s'\n", BSTR_P(rest)); - return STREAM_ERROR; - } - } - - priv->device = bstrto0(priv, bdevice); - - return open_s_internal(stream); -} - -const stream_info_t stream_info_dvdnav = { - .name = "dvdnav", - .open = open_s, - .protocols = (const char*const[]){ "dvd", "dvdnav", NULL }, -}; - -static bool check_ifo(const char *path) -{ - if (strcasecmp(mp_basename(path), "video_ts.ifo")) - return false; - - return dvd_probe(path, ".ifo", "DVDVIDEO-VMG"); -} - -static int ifo_dvdnav_stream_open(stream_t *stream) -{ - struct priv *priv = talloc_zero(stream, struct priv); - stream->priv = priv; - - if (!stream->access_references) - goto unsupported; - - priv->track = TITLE_LONGEST; - - char *path = mp_file_get_path(priv, bstr0(stream->url)); - if (!path) - goto unsupported; - - // We allow the path to point to a directory containing VIDEO_TS/, a - // directory containing VIDEO_TS.IFO, or that file itself. - if (!check_ifo(path)) { - // On UNIX, just assume the filename is always uppercase. - char *npath = mp_path_join(priv, path, "VIDEO_TS.IFO"); - if (!check_ifo(npath)) { - npath = mp_path_join(priv, path, "VIDEO_TS/VIDEO_TS.IFO"); - if (!check_ifo(npath)) - goto unsupported; - } - path = npath; - } - - priv->device = bstrto0(priv, mp_dirname(path)); - - MP_INFO(stream, ".IFO detected. Redirecting to dvd://\n"); - return open_s_internal(stream); - -unsupported: - talloc_free(priv); - stream->priv = NULL; - return STREAM_UNSUPPORTED; -} - -const stream_info_t stream_info_ifo_dvdnav = { - .name = "ifo_dvdnav", - .open = ifo_dvdnav_stream_open, - .protocols = (const char*const[]){ "file", "", NULL }, -}; diff --git a/stream/stream_rar.c b/stream/stream_rar.c deleted file mode 100644 index 3ba689b539..0000000000 --- a/stream/stream_rar.c +++ /dev/null @@ -1,147 +0,0 @@ -// Major parts based on: -/***************************************************************************** - * access.c: uncompressed RAR access - ***************************************************************************** - * Copyright (C) 2008-2010 Laurent Aimar - * $Id: dcd973529e0029abe326d31f8d58cd13bbcc276c $ - * - * Author: Laurent Aimar - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. - *****************************************************************************/ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include "osdep/io.h" - -#include "common/msg.h" -#include "stream.h" -#include "options/m_option.h" -#include "rar.h" - -/* -This works as follows: - -- stream_open() with file01.rar - - is opened as normal file (stream_file.c or others) first - - demux_rar.c detects it - - if multi-part, opens file02.rar, file03.rar, etc. as actual streams - - it returns a playlist with entries like this to the player: - rar://bla01.rar|subfile.mkv - (one such entry for each file contained in the rar) -- stream_open() with the playlist entry, e.g. rar://bla01.rar|subfile.mkv - - leads to rar_entry_open() - - opens bla01.rar etc. again as actual streams - - read accesses go into subfile.mkv contained in the rar file(s) -*/ - -static int rar_entry_fill_buffer(stream_t *s, char *buffer, int max_len) -{ - rar_file_t *rar_file = s->priv; - return RarRead(rar_file, buffer, max_len); -} - -static int rar_entry_seek(stream_t *s, int64_t newpos) -{ - rar_file_t *rar_file = s->priv; - return RarSeek(rar_file, newpos); -} - -static void rar_entry_close(stream_t *s) -{ - rar_file_t *rar_file = s->priv; - RarFileDelete(rar_file); -} - -static int rar_entry_control(stream_t *s, int cmd, void *arg) -{ - rar_file_t *rar_file = s->priv; - switch (cmd) { - case STREAM_CTRL_GET_BASE_FILENAME: - *(char **)arg = talloc_strdup(NULL, rar_file->s->url); - return STREAM_OK; - case STREAM_CTRL_GET_SIZE: - *(int64_t *)arg = rar_file->size; - return STREAM_OK; - } - return STREAM_UNSUPPORTED; -} - -static int rar_entry_open(stream_t *stream) -{ - if (!strchr(stream->path, '|')) - return STREAM_ERROR; - - char *base = talloc_strdup(stream, stream->path); - char *name = strchr(base, '|'); - *name++ = '\0'; - mp_url_unescape_inplace(base); - - struct stream *rar = stream_create(base, STREAM_READ | STREAM_SAFE_ONLY, - stream->cancel, stream->global); - if (!rar) - return STREAM_ERROR; - - int count; - rar_file_t **files; - if (RarProbe(rar) || RarParse(rar, &count, &files)) { - free_stream(rar); - return STREAM_ERROR; - } - - rar_file_t *file = NULL; - for (int i = 0; i < count; i++) { - if (!file && strcmp(files[i]->name, name) == 0) - file = files[i]; - else - RarFileDelete(files[i]); - } - talloc_free(files); - if (!file) { - free_stream(rar); - return STREAM_ERROR; - } - - rar_file_chunk_t dummy = { - .mrl = base, - }; - file->current_chunk = &dummy; - file->s = rar; // transfer ownership - file->cancel = stream->cancel; - file->global = stream->global; - RarSeek(file, 0); - - stream->priv = file; - stream->fill_buffer = rar_entry_fill_buffer; - stream->seek = rar_entry_seek; - stream->seekable = true; - stream->close = rar_entry_close; - stream->control = rar_entry_control; - - return STREAM_OK; -} - -const stream_info_t stream_info_rar = { - .name = "rar", - .open = rar_entry_open, - .protocols = (const char*const[]){ "rar", NULL }, -}; diff --git a/stream/stream_smb.c b/stream/stream_smb.c deleted file mode 100644 index 4376f71ee6..0000000000 --- a/stream/stream_smb.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Original author: M. Tourne - * - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include "config.h" - -#include -#include - -#include "common/msg.h" -#include "stream.h" -#include "options/m_option.h" - -#include "config.h" -#if !HAVE_GPL -#error GPL only -#endif - -struct priv { - int fd; -}; - -static void smb_auth_fn(const char *server, const char *share, - char *workgroup, int wgmaxlen, char *username, int unmaxlen, - char *password, int pwmaxlen) -{ - strncpy(workgroup, "LAN", wgmaxlen - 1); -} - -static int control(stream_t *s, int cmd, void *arg) { - struct priv *p = s->priv; - switch(cmd) { - case STREAM_CTRL_GET_SIZE: { - off_t size = smbc_lseek(p->fd,0,SEEK_END); - smbc_lseek(p->fd,s->pos,SEEK_SET); - if(size != (off_t)-1) { - *(int64_t *)arg = size; - return 1; - } - } - break; - } - return STREAM_UNSUPPORTED; -} - -static int seek(stream_t *s,int64_t newpos) { - struct priv *p = s->priv; - if(smbc_lseek(p->fd,newpos,SEEK_SET)<0) { - return 0; - } - return 1; -} - -static int fill_buffer(stream_t *s, char* buffer, int max_len){ - struct priv *p = s->priv; - int r = smbc_read(p->fd,buffer,max_len); - return (r <= 0) ? -1 : r; -} - -static int write_buffer(stream_t *s, char* buffer, int len) { - struct priv *p = s->priv; - int r; - int wr = 0; - while (wr < len) { - r = smbc_write(p->fd,buffer,len); - if (r <= 0) - return -1; - wr += r; - buffer += r; - } - return len; -} - -static void close_f(stream_t *s){ - struct priv *p = s->priv; - smbc_close(p->fd); -} - -static int open_f (stream_t *stream) -{ - char *filename; - int64_t len; - int fd, err; - - struct priv *priv = talloc_zero(stream, struct priv); - stream->priv = priv; - - filename = stream->url; - - bool write = stream->mode == STREAM_WRITE; - mode_t m = write ? O_RDWR|O_CREAT|O_TRUNC : O_RDONLY; - - if(!filename) { - MP_ERR(stream, "[smb] Bad url\n"); - return STREAM_ERROR; - } - - err = smbc_init(smb_auth_fn, 1); - if (err < 0) { - MP_ERR(stream, "Cannot init the libsmbclient library: %d\n",err); - return STREAM_ERROR; - } - - fd = smbc_open(filename, m,0644); - if (fd < 0) { - MP_ERR(stream, "Could not open from LAN: '%s'\n", filename); - return STREAM_ERROR; - } - - len = 0; - if(!write) { - len = smbc_lseek(fd,0,SEEK_END); - smbc_lseek (fd, 0, SEEK_SET); - } - if(len > 0 || write) { - stream->seekable = true; - stream->seek = seek; - } - priv->fd = fd; - stream->fill_buffer = fill_buffer; - stream->write_buffer = write_buffer; - stream->close = close_f; - stream->control = control; - stream->read_chunk = 128 * 1024; - stream->streaming = true; - - return STREAM_OK; -} - -const stream_info_t stream_info_smb = { - .name = "smb", - .open = open_f, - .protocols = (const char*const[]){"smb", NULL}, - .can_write = true, //who's gonna do that? -}; diff --git a/stream/stream_tv.c b/stream/stream_tv.c deleted file mode 100644 index bb3c48f269..0000000000 --- a/stream/stream_tv.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * stream layer for TV Input, based on previous work from Albeu - * - * Copyright (C) 2006 Benjamin Zores - * Original author: Albeu - * - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include "config.h" - -#include -#include - -#include "stream.h" -#include "options/m_option.h" -#include "tv.h" - -#include - -static void -tv_stream_close (stream_t *stream) -{ -} -static int -tv_stream_open (stream_t *stream) -{ - - stream->close=tv_stream_close; - stream->demuxer = "tv"; - - return STREAM_OK; -} - -const stream_info_t stream_info_tv = { - .name = "tv", - .open = tv_stream_open, - .protocols = (const char*const[]){ "tv", NULL }, -}; diff --git a/stream/tv.c b/stream/tv.c deleted file mode 100644 index de97f8d13e..0000000000 --- a/stream/tv.c +++ /dev/null @@ -1,986 +0,0 @@ -/* - * TV Interface for MPlayer - * - * API idea based on libvo2 - * - * Copyright (C) 2001 Alex Beregszaszi - * - * Feb 19, 2002: Significant rewrites by Charles R. Henrich (henrich@msu.edu) - * to add support for audio, and bktr *BSD support. - * - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" - - -#include "common/msg.h" -#include "misc/ctype.h" - -#include "options/m_option.h" -#include "options/m_config.h" -#include "options/options.h" - -#include "stream.h" - -#include "audio/format.h" -#include "osdep/timer.h" - -#include "tv.h" - -#include "frequencies.h" - -/* enumerating drivers (like in stream.c) */ -extern const tvi_info_t tvi_info_dummy; -extern const tvi_info_t tvi_info_v4l2; - -/** List of drivers in autodetection order */ -static const tvi_info_t *const tvi_driver_list[]={ -#if HAVE_TV_V4L2 - &tvi_info_v4l2, -#endif - &tvi_info_dummy, - NULL -}; - -#define OPT_BASE_STRUCT tv_param_t -const struct m_sub_options tv_params_conf = { - .opts = (const m_option_t[]) { - OPT_FLAG("immediatemode", immediate, 0), - OPT_FLAG("audio", audio, 0), - OPT_INT("audiorate", audiorate, 0), - OPT_STRING("driver", driver, 0), - OPT_STRING("device", device, 0), - OPT_FLOAT("freq", freq, 0), - OPT_STRING("channel", channel, 0), - OPT_STRING("chanlist", chanlist, 0), - OPT_STRING("norm", norm, 0), - OPT_INTRANGE("automute", automute, 0, 0, 255), -#if HAVE_TV_V4L2 - OPT_INT("normid", normid, 0), -#endif - OPT_INTRANGE("width", width, 0, 0, 4096), - OPT_INTRANGE("height", height, 0, 0, 4096), - OPT_INT("input", input, 0), - OPT_GENERAL(int, "outfmt", outfmt, 0, .type = &m_option_type_fourcc), - OPT_FLOAT("fps", fps, 0), - OPT_STRINGLIST("channels", channels, 0), - OPT_INTRANGE("brightness", brightness, 0, -100, 100), - OPT_INTRANGE("contrast", contrast, 0, -100, 100), - OPT_INTRANGE("hue", hue, 0, -100, 100), - OPT_INTRANGE("saturation", saturation, 0, -100, 100), - OPT_INTRANGE("gain", gain, 0, -1, 100), -#if HAVE_TV_V4L2 - OPT_INTRANGE("amode", amode, 0, 0, 3), - OPT_INTRANGE("volume", volume, 0, 0, 65535), - OPT_INTRANGE("bass", bass, 0, 0, 65535), - OPT_INTRANGE("treble", treble, 0, 0, 65535), - OPT_INTRANGE("balance", balance, 0, 0, 65535), - OPT_INTRANGE("forcechan", forcechan, 0, 1, 2), - OPT_FLAG("forceaudio", force_audio, 0), - OPT_INTRANGE("buffersize", buffer_size, 0, 16, 1024), - OPT_FLAG("mjpeg", mjpeg, 0), - OPT_INTRANGE("decimation", decimation, 0, 1, 4), - OPT_INTRANGE("quality", quality, 0, 0, 100), -#if HAVE_ALSA - OPT_FLAG("alsa", alsa, 0), -#endif /* HAVE_ALSA */ -#endif /* HAVE_TV_V4L2 */ - OPT_STRING("adevice", adevice, 0), - OPT_INTRANGE("audioid", audio_id, 0, 0, 9), - OPT_FLAG("scan-autostart", scan, 0), - OPT_INTRANGE("scan-threshold", scan_threshold, 0, 1, 100), - OPT_FLOATRANGE("scan-period", scan_period, 0, 0.1, 2.0), - {0} - }, - .size = sizeof(tv_param_t), - .defaults = &(const tv_param_t){ - .chanlist = "europe-east", - .norm = "pal", - .normid = -1, - .width = -1, - .height = -1, - .outfmt = -1, - .fps = -1.0, - .audio = 1, - .immediate = 1, - .audiorate = 44100, - .amode = -1, - .volume = -1, - .bass = -1, - .treble = -1, - .balance = -1, - .forcechan = -1, - .buffer_size = -1, - .decimation = 2, - .quality = 90, - .gain = -1, - .scan_threshold = 50, - .scan_period = 0.5, - }, -}; - -tvi_handle_t *tv_new_handle(int size, struct mp_log *log, const tvi_functions_t *functions) -{ - tvi_handle_t *h = calloc(1, sizeof(*h)); - - if (!h) - return NULL; - - h->priv = calloc(1, size); - - if (!h->priv) { - free(h); - return NULL; - } - - h->log = log; - h->functions = functions; - h->chanlist = -1; - h->norm = -1; - h->channel = -1; - - return h; -} - -void tv_free_handle(tvi_handle_t *h) -{ - if (!h) - return; - free(h->priv); - free(h->scan); - free(h); -} - -void tv_start_scan(tvi_handle_t *tvh, int start) -{ - MP_INFO(tvh, "start scan\n"); - tvh->tv_param->scan=start?1:0; -} - -static int tv_set_freq_float(tvi_handle_t *tvh, float freq) -{ - return tv_set_freq(tvh, freq/1000.0*16); -} - -void tv_scan(tvi_handle_t *tvh) -{ - unsigned int now; - struct CHANLIST cl; - tv_channels_t *tv_channel_tmp=NULL; - tv_channels_t *tv_channel_add=NULL; - tv_scan_t* scan; - int found=0, index=1; - - //Channel scanner without tuner is useless and causes crash due to uninitialized chanlist_s - if (tvh->functions->control(tvh->priv, TVI_CONTROL_IS_TUNER, 0) != TVI_CONTROL_TRUE) - { - MP_WARN(tvh, "Channel scanner is not available without tuner\n"); - tvh->tv_param->scan=0; - return; - } - - scan = tvh->scan; - now=(unsigned int)mp_time_us(); - if (!scan) { - scan=calloc(1,sizeof(tv_scan_t)); - tvh->scan=scan; - cl = tvh->chanlist_s[scan->channel_num]; - tv_set_freq_float(tvh, cl.freq); - scan->scan_timer=now+1e6*tvh->tv_param->scan_period; - } - if(scan->scan_timer>now) - return; - - if (tv_get_signal(tvh)>tvh->tv_param->scan_threshold) { - cl = tvh->chanlist_s[scan->channel_num]; - tv_channel_tmp=tvh->tv_channel_list; - while (tv_channel_tmp) { - index++; - if (cl.freq==tv_channel_tmp->freq){ - found=1; - break; - } - tv_channel_add=tv_channel_tmp; - tv_channel_tmp=tv_channel_tmp->next; - } - if (!found) { - MP_INFO(tvh, "Found new channel: %s (#%d). \n",cl.name,index); - scan->new_channels++; - tv_channel_tmp = malloc(sizeof(tv_channels_t)); - tv_channel_tmp->index=index; - tv_channel_tmp->next=NULL; - tv_channel_tmp->prev=tv_channel_add; - tv_channel_tmp->freq=cl.freq; - snprintf(tv_channel_tmp->name,sizeof(tv_channel_tmp->name),"ch%d",index); - strncpy(tv_channel_tmp->number, cl.name, 5); - tv_channel_tmp->number[4]='\0'; - if (!tvh->tv_channel_list) - tvh->tv_channel_list=tv_channel_tmp; - else { - tv_channel_add->next=tv_channel_tmp; - tvh->tv_channel_list->prev=tv_channel_tmp; - } - }else - MP_INFO(tvh, "Found existing channel: %s-%s.\n", - tv_channel_tmp->number,tv_channel_tmp->name); - } - scan->channel_num++; - scan->scan_timer=now+1e6*tvh->tv_param->scan_period; - if (scan->channel_num>=chanlists[tvh->chanlist].count) { - tvh->tv_param->scan=0; - MP_INFO(tvh, "TV scan end. Found %d new channels.\n", scan->new_channels); - tv_channel_tmp=tvh->tv_channel_list; - if(tv_channel_tmp){ - MP_INFO(tvh, "channels="); - while(tv_channel_tmp){ - MP_INFO(tvh, "%s-%s",tv_channel_tmp->number,tv_channel_tmp->name); - if(tv_channel_tmp->next) - MP_INFO(tvh, ","); - tv_channel_tmp=tv_channel_tmp->next; - } - MP_INFO(tvh, "\n"); - } - if (!tvh->tv_channel_current) tvh->tv_channel_current=tvh->tv_channel_list; - if (tvh->tv_channel_current) - tv_set_freq_float(tvh, tvh->tv_channel_current->freq); - free(tvh->scan); - tvh->scan=NULL; - }else{ - cl = tvh->chanlist_s[scan->channel_num]; - tv_set_freq_float(tvh, cl.freq); - MP_INFO(tvh, "Trying: %s (%.2f). \n",cl.name,1e-3*cl.freq); - } -} - -static int norm_from_string(tvi_handle_t *tvh, char* norm) -{ - const tvi_functions_t *funcs = tvh->functions; - char str[20]; - int ret; - - strncpy(str, norm, sizeof(str)-1); - str[sizeof(str)-1] = '\0'; - ret=funcs->control(tvh->priv, TVI_CONTROL_SPC_GET_NORMID, str); - - if (ret == TVI_CONTROL_TRUE) { - int *v = (int *)str; - return *v; - } - - if(ret!=TVI_CONTROL_UNKNOWN) - { - MP_WARN(tvh, "tv.c: norm_from_string(%s): Bogus norm parameter, setting %s.\n", norm,"default"); - return 0; - } - - if (!strcasecmp(norm, "pal")) - return TV_NORM_PAL; - else if (!strcasecmp(norm, "ntsc")) - return TV_NORM_NTSC; - else if (!strcasecmp(norm, "secam")) - return TV_NORM_SECAM; - else if (!strcasecmp(norm, "palnc")) - return TV_NORM_PALNC; - else if (!strcasecmp(norm, "palm")) - return TV_NORM_PALM; - else if (!strcasecmp(norm, "paln")) - return TV_NORM_PALN; - else if (!strcasecmp(norm, "ntscjp")) - return TV_NORM_NTSCJP; - else { - MP_WARN(tvh, "tv.c: norm_from_string(%s): Bogus norm parameter, setting %s.\n", norm, "PAL"); - return TV_NORM_PAL; - } -} - -static void parse_channels(tvi_handle_t *tvh) -{ - char** channels = tvh->tv_param->channels; - - MP_INFO(tvh, "TV channel names detected.\n"); - tvh->tv_channel_list = malloc(sizeof(tv_channels_t)); - tvh->tv_channel_list->index=1; - tvh->tv_channel_list->next=NULL; - tvh->tv_channel_list->prev=NULL; - tvh->tv_channel_current = tvh->tv_channel_list; - tvh->tv_channel_current->norm = tvh->norm; - - while (*channels) { - char* tmp = *(channels++); - char* sep = strchr(tmp,'-'); - int i; - struct CHANLIST cl; - - if (!sep) continue; // Wrong syntax, but mplayer should not crash - - av_strlcpy(tvh->tv_channel_current->name, sep + 1, - sizeof(tvh->tv_channel_current->name)); - sep[0] = '\0'; - strncpy(tvh->tv_channel_current->number, tmp, 5); - tvh->tv_channel_current->number[4]='\0'; - - while ((sep=strchr(tvh->tv_channel_current->name, '_'))) - sep[0] = ' '; - - // if channel number is a number and larger than 1000 threat it as frequency - // tmp still contain pointer to null-terminated string with channel number here - if (atoi(tmp)>1000){ - tvh->tv_channel_current->freq=atoi(tmp); - }else{ - tvh->tv_channel_current->freq = 0; - for (i = 0; i < chanlists[tvh->chanlist].count; i++) { - cl = tvh->chanlist_s[i]; - if (!strcasecmp(cl.name, tvh->tv_channel_current->number)) { - tvh->tv_channel_current->freq=cl.freq; - break; - } - } - } - if (tvh->tv_channel_current->freq == 0) - MP_ERR(tvh, "Couldn't find frequency for channel %s (%s)\n", - tvh->tv_channel_current->number, tvh->tv_channel_current->name); - else { - sep = strchr(tvh->tv_channel_current->name, '-'); - if ( !sep ) sep = strchr(tvh->tv_channel_current->name, '+'); - - if ( sep ) { - i = atoi (sep+1); - if ( sep[0] == '+' ) tvh->tv_channel_current->freq += i * 100; - if ( sep[0] == '-' ) tvh->tv_channel_current->freq -= i * 100; - sep[0] = '\0'; - } - - sep = strchr(tvh->tv_channel_current->name, '='); - if ( sep ) { - tvh->tv_channel_current->norm = norm_from_string(tvh, sep+1); - sep[0] = '\0'; - } - } - - /*MP_INFO(tvh, "-- Detected channel %s - %s (%5.3f)\n", - tvh->tv_channel_current->number, tvh->tv_channel_current->name, - (float)tvh->tv_channel_current->freq/1000);*/ - - tvh->tv_channel_current->next = malloc(sizeof(tv_channels_t)); - tvh->tv_channel_current->next->index = tvh->tv_channel_current->index + 1; - tvh->tv_channel_current->next->prev = tvh->tv_channel_current; - tvh->tv_channel_current->next->next = NULL; - tvh->tv_channel_current = tvh->tv_channel_current->next; - tvh->tv_channel_current->norm = tvh->norm; - } - if (tvh->tv_channel_current->prev) - tvh->tv_channel_current->prev->next = NULL; - free(tvh->tv_channel_current); -} - -int tv_set_norm(tvi_handle_t *tvh, char* norm) -{ - tvh->norm = norm_from_string(tvh, norm); - - MP_VERBOSE(tvh, "Selected norm : %s\n", norm); - if (tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, &tvh->norm) != TVI_CONTROL_TRUE) { - MP_ERR(tvh, "Error: Cannot set norm!\n"); - return 0; - } - return 1; -} - -static int tv_set_norm_i(tvi_handle_t *tvh, int norm) -{ - tvh->norm = norm; - - MP_VERBOSE(tvh, "Selected norm id: %d\n", norm); - if (tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, &tvh->norm) != TVI_CONTROL_TRUE) { - MP_ERR(tvh, "Error: Cannot set norm!\n"); - return 0; - } - - return 1; -} - -static void set_norm_and_freq(tvi_handle_t *tvh, tv_channels_t *chan) -{ - MP_INFO(tvh, "Selected channel: %s - %s (freq: %.3f)\n", - chan->number, chan->name, chan->freq/1000.0); - tv_set_norm_i(tvh, chan->norm); - tv_set_freq_float(tvh, chan->freq); -} - -int open_tv(tvi_handle_t *tvh) -{ - int i; - const tvi_functions_t *funcs = tvh->functions; - static const int tv_fmt_list[] = { - MP_FOURCC_YV12, - MP_FOURCC_I420, - MP_FOURCC_UYVY, - MP_FOURCC_YUY2, - MP_FOURCC_RGB32, - MP_FOURCC_RGB24, - MP_FOURCC_RGB16, - MP_FOURCC_RGB15 - }; - - if (funcs->control(tvh->priv, TVI_CONTROL_IS_VIDEO, 0) != TVI_CONTROL_TRUE) - { - MP_ERR(tvh, "Error: No video input present!\n"); - return 0; - } - - if (tvh->tv_param->outfmt == -1) - for (i = 0; i < sizeof (tv_fmt_list) / sizeof (*tv_fmt_list); i++) - { - tvh->tv_param->outfmt = tv_fmt_list[i]; - if (funcs->control (tvh->priv, TVI_CONTROL_VID_SET_FORMAT, - &tvh->tv_param->outfmt) == TVI_CONTROL_TRUE) - break; - } - else - { - switch(tvh->tv_param->outfmt) - { - case MP_FOURCC_YV12: - case MP_FOURCC_I420: - case MP_FOURCC_UYVY: - case MP_FOURCC_YUY2: - case MP_FOURCC_RGB32: - case MP_FOURCC_RGB24: - case MP_FOURCC_BGR32: - case MP_FOURCC_BGR24: - case MP_FOURCC_BGR16: - case MP_FOURCC_BGR15: - break; - default: - MP_ERR(tvh, "==================================================================\n"\ - " WARNING: UNTESTED OR UNKNOWN OUTPUT IMAGE FORMAT REQUESTED (0x%x)\n"\ - " This may cause buggy playback or program crash! Bug reports will\n"\ - " be ignored! You should try again with YV12 (which is the default\n"\ - " colorspace) and read the documentation!\n"\ - "==================================================================\n" - ,tvh->tv_param->outfmt); - } - funcs->control(tvh->priv, TVI_CONTROL_VID_SET_FORMAT, &tvh->tv_param->outfmt); - } - - /* set some params got from cmdline */ - funcs->control(tvh->priv, TVI_CONTROL_SPC_SET_INPUT, &tvh->tv_param->input); - - if ((!strcmp(tvh->tv_param->driver, "v4l2") && tvh->tv_param->normid >= 0)) - tv_set_norm_i(tvh, tvh->tv_param->normid); - else - tv_set_norm(tvh,tvh->tv_param->norm); - - /* limits on w&h are norm-dependent -- JM */ - if (tvh->tv_param->width != -1 && tvh->tv_param->height != -1) { - // first tell the driver both width and height, some drivers do not support setting them independently. - int dim[2]; - dim[0] = tvh->tv_param->width; dim[1] = tvh->tv_param->height; - funcs->control(tvh->priv, TVI_CONTROL_VID_SET_WIDTH_HEIGHT, dim); - } - /* set width */ - if (tvh->tv_param->width != -1) - { - if (funcs->control(tvh->priv, TVI_CONTROL_VID_CHK_WIDTH, &tvh->tv_param->width) == TVI_CONTROL_TRUE) - funcs->control(tvh->priv, TVI_CONTROL_VID_SET_WIDTH, &tvh->tv_param->width); - else - { - MP_ERR(tvh, "Unable to set requested width: %d\n", tvh->tv_param->width); - funcs->control(tvh->priv, TVI_CONTROL_VID_GET_WIDTH, &tvh->tv_param->width); - } - } - - /* set height */ - if (tvh->tv_param->height != -1) - { - if (funcs->control(tvh->priv, TVI_CONTROL_VID_CHK_HEIGHT, &tvh->tv_param->height) == TVI_CONTROL_TRUE) - funcs->control(tvh->priv, TVI_CONTROL_VID_SET_HEIGHT, &tvh->tv_param->height); - else - { - MP_ERR(tvh, "Unable to set requested height: %d\n", tvh->tv_param->height); - funcs->control(tvh->priv, TVI_CONTROL_VID_GET_HEIGHT, &tvh->tv_param->height); - } - } - - if (funcs->control(tvh->priv, TVI_CONTROL_IS_TUNER, 0) != TVI_CONTROL_TRUE) - { - MP_WARN(tvh, "Selected input hasn't got a tuner!\n"); - goto done; - } - - /* select channel list */ - for (i = 0; chanlists[i].name != NULL; i++) - { - if (!strcasecmp(chanlists[i].name, tvh->tv_param->chanlist)) - { - tvh->chanlist = i; - tvh->chanlist_s = chanlists[i].list; - break; - } - } - - if (tvh->chanlist == -1) { - MP_WARN(tvh, "Unable to find selected channel list! (%s)\n", - tvh->tv_param->chanlist); - return 0; - } else - MP_VERBOSE(tvh, "Selected channel list: %s (including %d channels)\n", - chanlists[tvh->chanlist].name, chanlists[tvh->chanlist].count); - - if (tvh->tv_param->freq && tvh->tv_param->channel) - { - MP_WARN(tvh, "You can't set frequency and channel simultaneously!\n"); - goto done; - } - - /* Handle channel names */ - if (tvh->tv_param->channels) { - parse_channels(tvh); - } else - tvh->tv_channel_last_real = malloc(5); - - if (tvh->tv_channel_list) { - int channel = 0; - if (tvh->tv_param->channel) - { - if (mp_isdigit(*tvh->tv_param->channel)) - /* if tvh->tv_param->channel begins with a digit interpret it as a number */ - channel = atoi(tvh->tv_param->channel); - else - { - /* if tvh->tv_param->channel does not begin with a digit - set the first channel that contains tvh->tv_param->channel in its name */ - - tvh->tv_channel_current = tvh->tv_channel_list; - while ( tvh->tv_channel_current ) { - if ( strstr(tvh->tv_channel_current->name, tvh->tv_param->channel) ) - break; - tvh->tv_channel_current = tvh->tv_channel_current->next; - } - if ( !tvh->tv_channel_current ) tvh->tv_channel_current = tvh->tv_channel_list; - } - } - else - channel = 1; - - if ( channel ) { - tvh->tv_channel_current = tvh->tv_channel_list; - for (int n = 1; n < channel; n++) - if (tvh->tv_channel_current->next) - tvh->tv_channel_current = tvh->tv_channel_current->next; - } - - set_norm_and_freq(tvh, tvh->tv_channel_current); - tvh->tv_channel_last = tvh->tv_channel_current; - } else { - /* we need to set frequency */ - if (tvh->tv_param->freq) - { - unsigned long freq = tvh->tv_param->freq * 16; - - /* set freq in MHz */ - funcs->control(tvh->priv, TVI_CONTROL_TUN_SET_FREQ, &freq); - - funcs->control(tvh->priv, TVI_CONTROL_TUN_GET_FREQ, &freq); - MP_VERBOSE(tvh, "Selected frequency: %lu (%.3f)\n", - freq, freq/16.0); - } - - if (tvh->tv_param->channel) { - struct CHANLIST cl; - - MP_VERBOSE(tvh, "Requested channel: %s\n", tvh->tv_param->channel); - for (i = 0; i < chanlists[tvh->chanlist].count; i++) - { - cl = tvh->chanlist_s[i]; - // printf("count%d: name: %s, freq: %d\n", - // i, cl.name, cl.freq); - if (!strcasecmp(cl.name, tvh->tv_param->channel)) - { - strcpy(tvh->tv_channel_last_real, cl.name); - tvh->channel = i; - MP_INFO(tvh, "Selected channel: %s (freq: %.3f)\n", - cl.name, cl.freq/1000.0); - tv_set_freq_float(tvh, cl.freq); - break; - } - } - } - } - - /* grep frequency in chanlist */ - { - unsigned long i2 = 0; - int freq; - - tv_get_freq(tvh, &i2); - - freq = (int) (((float)(i2/16))*1000)+250; - - for (i = 0; i < chanlists[tvh->chanlist].count; i++) - { - if (tvh->chanlist_s[i].freq == freq) - { - tvh->channel = i+1; - break; - } - } - } - -done: - /* also start device! */ - return 1; -} - -tvi_handle_t *tv_begin(tv_param_t* tv_param, struct mp_log *log) -{ - int i; - tvi_handle_t* h; - if(tv_param->driver && !strcmp(tv_param->driver,"help")){ - mp_info(log, "Available drivers:\n"); - for(i=0;tvi_driver_list[i];i++){ - mp_info(log, " %s\t%s\n",tvi_driver_list[i]->short_name,tvi_driver_list[i]->name); - } - return NULL; - } - - for(i=0;tvi_driver_list[i];i++){ - if (!tv_param->driver || !strcmp(tvi_driver_list[i]->short_name, tv_param->driver)){ - h=tvi_driver_list[i]->tvi_init(log, tv_param); - //Requested driver initialization failed - if (!h && tv_param->driver) - return NULL; - //Driver initialization failed during autodetection process. - if (!h) - continue; - - h->tv_param=tv_param; - MP_INFO(h, "Selected driver: %s\n name: %s\n", tvi_driver_list[i]->short_name, - tvi_driver_list[i]->name); - talloc_free(tv_param->driver); - tv_param->driver=talloc_strdup(NULL, tvi_driver_list[i]->short_name); - return h; - } - } - - if(tv_param->driver) - mp_err(log, "No such driver: %s\n", tv_param->driver); - else - mp_err(log, "TV driver autodetection failed.\n"); - return NULL; -} - -int tv_uninit(tvi_handle_t *tvh) -{ - int res; - if(!tvh) return 1; - if (!tvh->priv) return 1; - res=tvh->functions->uninit(tvh->priv); - if(res) { - free(tvh->priv); - tvh->priv=NULL; - } - return res; -} - -int tv_set_color_options(tvi_handle_t *tvh, int opt, int value) -{ - const tvi_functions_t *funcs = tvh->functions; - - switch(opt) - { - case TV_COLOR_BRIGHTNESS: - return funcs->control(tvh->priv, TVI_CONTROL_VID_SET_BRIGHTNESS, &value); - case TV_COLOR_HUE: - return funcs->control(tvh->priv, TVI_CONTROL_VID_SET_HUE, &value); - case TV_COLOR_SATURATION: - return funcs->control(tvh->priv, TVI_CONTROL_VID_SET_SATURATION, &value); - case TV_COLOR_CONTRAST: - return funcs->control(tvh->priv, TVI_CONTROL_VID_SET_CONTRAST, &value); - default: - MP_WARN(tvh, "Unknown color option (%d) specified!\n", opt); - } - - return TVI_CONTROL_UNKNOWN; -} - -int tv_get_color_options(tvi_handle_t *tvh, int opt, int* value) -{ - const tvi_functions_t *funcs = tvh->functions; - - switch(opt) - { - case TV_COLOR_BRIGHTNESS: - return funcs->control(tvh->priv, TVI_CONTROL_VID_GET_BRIGHTNESS, value); - case TV_COLOR_HUE: - return funcs->control(tvh->priv, TVI_CONTROL_VID_GET_HUE, value); - case TV_COLOR_SATURATION: - return funcs->control(tvh->priv, TVI_CONTROL_VID_GET_SATURATION, value); - case TV_COLOR_CONTRAST: - return funcs->control(tvh->priv, TVI_CONTROL_VID_GET_CONTRAST, value); - default: - MP_WARN(tvh, "Unknown color option (%d) specified!\n", opt); - } - - return TVI_CONTROL_UNKNOWN; -} - -int tv_get_freq(tvi_handle_t *tvh, unsigned long *freq) -{ - if (tvh->functions->control(tvh->priv, TVI_CONTROL_IS_TUNER, 0) == TVI_CONTROL_TRUE) - { - tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_GET_FREQ, freq); - MP_VERBOSE(tvh, "Current frequency: %lu (%.3f)\n", - *freq, *freq/16.0); - } - return 1; -} - -int tv_set_freq(tvi_handle_t *tvh, unsigned long freq) -{ - if (tvh->functions->control(tvh->priv, TVI_CONTROL_IS_TUNER, 0) == TVI_CONTROL_TRUE) - { -// unsigned long freq = atof(tvh->tv_param->freq)*16; - - /* set freq in MHz */ - tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_SET_FREQ, &freq); - - tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_GET_FREQ, &freq); - MP_VERBOSE(tvh, "Current frequency: %lu (%.3f)\n", - freq, freq/16.0); - } - return 1; -} - -int tv_get_signal(tvi_handle_t *tvh) -{ - int signal=0; - if (tvh->functions->control(tvh->priv, TVI_CONTROL_IS_TUNER, 0) != TVI_CONTROL_TRUE || - tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_GET_SIGNAL, &signal)!=TVI_CONTROL_TRUE) - return 0; - - return signal; -} - -/***************************************************************** - * \brief tune current frequency by step_interval value - * \parameter step_interval increment value in 1/16 MHz - * \note frequency is rounded to 1/16 MHz value - * \return 1 - * - */ -int tv_step_freq(tvi_handle_t* tvh, float step_interval){ - unsigned long frequency = 0; - - tvh->tv_param->scan=0; - tv_get_freq(tvh,&frequency); - frequency+=step_interval; - return tv_set_freq(tvh,frequency); -} - -int tv_step_channel_real(tvi_handle_t *tvh, int direction) -{ - struct CHANLIST cl; - - tvh->tv_param->scan=0; - if (direction == TV_CHANNEL_LOWER) - { - if (tvh->channel-1 >= 0) - { - strcpy(tvh->tv_channel_last_real, tvh->chanlist_s[tvh->channel].name); - cl = tvh->chanlist_s[--tvh->channel]; - MP_INFO(tvh, "Selected channel: %s (freq: %.3f)\n", - cl.name, cl.freq/1000.0); - tv_set_freq_float(tvh, cl.freq); - } - } - - if (direction == TV_CHANNEL_HIGHER) - { - if (tvh->channel+1 < chanlists[tvh->chanlist].count) - { - strcpy(tvh->tv_channel_last_real, tvh->chanlist_s[tvh->channel].name); - cl = tvh->chanlist_s[++tvh->channel]; - MP_INFO(tvh, "Selected channel: %s (freq: %.3f)\n", - cl.name, cl.freq/1000.0); - tv_set_freq_float(tvh, cl.freq); - } - } - return 1; -} - -int tv_step_channel(tvi_handle_t *tvh, int direction) { - tvh->tv_param->scan=0; - if (tvh->tv_channel_list) { - if (direction == TV_CHANNEL_HIGHER) { - tvh->tv_channel_last = tvh->tv_channel_current; - if (tvh->tv_channel_current->next) - tvh->tv_channel_current = tvh->tv_channel_current->next; - else - tvh->tv_channel_current = tvh->tv_channel_list; - set_norm_and_freq(tvh, tvh->tv_channel_current); - } - if (direction == TV_CHANNEL_LOWER) { - tvh->tv_channel_last = tvh->tv_channel_current; - if (tvh->tv_channel_current->prev) - tvh->tv_channel_current = tvh->tv_channel_current->prev; - else - while (tvh->tv_channel_current->next) - tvh->tv_channel_current = tvh->tv_channel_current->next; - set_norm_and_freq(tvh, tvh->tv_channel_current); - } - } else tv_step_channel_real(tvh, direction); - return 1; -} - -int tv_set_channel_real(tvi_handle_t *tvh, char *channel) { - int i; - struct CHANLIST cl; - - tvh->tv_param->scan=0; - strcpy(tvh->tv_channel_last_real, tvh->chanlist_s[tvh->channel].name); - for (i = 0; i < chanlists[tvh->chanlist].count; i++) - { - cl = tvh->chanlist_s[i]; -// printf("count%d: name: %s, freq: %d\n", -// i, cl.name, cl.freq); - if (!strcasecmp(cl.name, channel)) - { - tvh->channel = i; - MP_INFO(tvh, "Selected channel: %s (freq: %.3f)\n", - cl.name, cl.freq/1000.0); - tv_set_freq_float(tvh, cl.freq); - break; - } - } - return 1; -} - -int tv_set_channel(tvi_handle_t *tvh, char *channel) { - int i, channel_int; - - tvh->tv_param->scan=0; - if (tvh->tv_channel_list) { - tvh->tv_channel_last = tvh->tv_channel_current; - channel_int = atoi(channel); - tvh->tv_channel_current = tvh->tv_channel_list; - for (i = 1; i < channel_int; i++) - if (tvh->tv_channel_current->next) - tvh->tv_channel_current = tvh->tv_channel_current->next; - set_norm_and_freq(tvh, tvh->tv_channel_current); - } else tv_set_channel_real(tvh, channel); - return 1; -} - -int tv_last_channel(tvi_handle_t *tvh) { - - tvh->tv_param->scan=0; - if (tvh->tv_channel_list) { - tv_channels_t *tmp; - - tmp = tvh->tv_channel_last; - tvh->tv_channel_last = tvh->tv_channel_current; - tvh->tv_channel_current = tmp; - - set_norm_and_freq(tvh, tvh->tv_channel_current); - } else { - int i; - struct CHANLIST cl; - - for (i = 0; i < chanlists[tvh->chanlist].count; i++) - { - cl = tvh->chanlist_s[i]; - if (!strcasecmp(cl.name, tvh->tv_channel_last_real)) - { - strcpy(tvh->tv_channel_last_real, tvh->chanlist_s[tvh->channel].name); - tvh->channel = i; - MP_INFO(tvh, "Selected channel: %s (freq: %.3f)\n", - cl.name, cl.freq/1000.0); - tv_set_freq_float(tvh, cl.freq); - break; - } - } - } - return 1; -} - -int tv_step_norm(tvi_handle_t *tvh) -{ - tvh->norm++; - if (tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, - &tvh->norm) != TVI_CONTROL_TRUE) { - tvh->norm = 0; - if (tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, - &tvh->norm) != TVI_CONTROL_TRUE) { - MP_ERR(tvh, "Error: Cannot set norm!\n"); - return 0; - } - } - return 1; -} - -int tv_stream_control(tvi_handle_t *tvh, int cmd, void *arg) -{ - switch (cmd) { - case STREAM_CTRL_TV_SET_SCAN: - tv_start_scan(tvh, *(int *)arg); - return STREAM_OK; - case STREAM_CTRL_SET_TV_FREQ: - tv_set_freq(tvh, *(float *)arg * 16.0f); - return STREAM_OK; - case STREAM_CTRL_GET_TV_FREQ: { - unsigned long tmp = 0; - tv_get_freq(tvh, &tmp); - *(float *)arg = tmp / 16.0f; - return STREAM_OK; - } - case STREAM_CTRL_SET_TV_COLORS: - tv_set_color_options(tvh, ((int *)arg)[0], ((int *)arg)[1]); - return STREAM_OK; - case STREAM_CTRL_GET_TV_COLORS: - tv_get_color_options(tvh, ((int *)arg)[0], &((int *)arg)[1]); - return STREAM_OK; - case STREAM_CTRL_TV_SET_NORM: - tv_set_norm(tvh, (char *)arg); - return STREAM_OK; - case STREAM_CTRL_TV_STEP_NORM: - tv_step_norm(tvh); - return STREAM_OK; - case STREAM_CTRL_TV_SET_CHAN: - tv_set_channel(tvh, (char *)arg); - return STREAM_OK; - case STREAM_CTRL_TV_STEP_CHAN: - if (*(int *)arg >= 0) { - tv_step_channel(tvh, TV_CHANNEL_HIGHER); - } else { - tv_step_channel(tvh, TV_CHANNEL_LOWER); - } - return STREAM_OK; - case STREAM_CTRL_TV_LAST_CHAN: - tv_last_channel(tvh); - return STREAM_OK; - } - return STREAM_UNSUPPORTED; -} diff --git a/stream/tv.h b/stream/tv.h deleted file mode 100644 index 94b7f01887..0000000000 --- a/stream/tv.h +++ /dev/null @@ -1,285 +0,0 @@ -/* - * TV interface - * - * Copyright (C) 2001 Alex Beregszászi - * Copyright (C) 2007 Attila Ötvös - * Copyright (C) 2007 Vladimir Voroshilov - * - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#ifndef MPLAYER_TV_H -#define MPLAYER_TV_H - -#include "osdep/endian.h" - -#include "config.h" -#if !HAVE_GPL -#error GPL only -#endif - -struct mp_log; - -typedef struct tv_params { - float freq; - char *channel; - char *chanlist; - char *norm; - int automute; - int normid; - char *device; - char *driver; - int width; - int height; - int input; - int outfmt; - float fps; - char **channels; - int audio; - int immediate; - int audiorate; - int audio_id; - int amode; - int volume; - int bass; - int treble; - int balance; - int forcechan; - int force_audio; - int buffer_size; - int mjpeg; - int decimation; - int quality; - int alsa; - char* adevice; - int brightness; - int contrast; - int hue; - int saturation; - int gain; - - int scan; - int scan_threshold; - float scan_period; -} tv_param_t; - -struct tv_stream_params { - char *channel; - int input; -}; - -typedef struct tvi_info_s -{ - struct tvi_handle_s * (*tvi_init)(struct mp_log *log, tv_param_t* tv_param); - const char *name; - const char *short_name; -} tvi_info_t; - - -struct priv; - -typedef struct tvi_functions_s -{ - int (*init)(struct priv *priv); - int (*uninit)(struct priv *priv); - int (*control)(struct priv *priv, int cmd, void *arg); - int (*start)(struct priv *priv); - double (*grab_video_frame)(struct priv *priv, char *buffer, int len); - int (*get_video_framesize)(struct priv *priv); - double (*grab_audio_frame)(struct priv *priv, char *buffer, int len); - int (*get_audio_framesize)(struct priv *priv); -} tvi_functions_t; - -typedef struct tvi_handle_s { - struct mp_log *log; - const tvi_functions_t *functions; - void *priv; - int seq; - struct demuxer *demuxer; - - /* specific */ - int norm; - int chanlist; - const struct CHANLIST *chanlist_s; - int channel; - tv_param_t * tv_param; - void * scan; - - struct tv_channels_s *tv_channel_list; - struct tv_channels_s *tv_channel_current, *tv_channel_last; - char *tv_channel_last_real; -} tvi_handle_t; - -typedef struct tv_channels_s { - int index; - char number[5]; - char name[20]; - int norm; - int freq; - struct tv_channels_s *next; - struct tv_channels_s *prev; -} tv_channels_t; - -typedef struct { - unsigned int scan_timer; - int channel_num; - int new_channels; -} tv_scan_t; - -#define TVI_CONTROL_FALSE 0 -#define TVI_CONTROL_TRUE 1 -#define TVI_CONTROL_NA -1 -#define TVI_CONTROL_UNKNOWN -2 - -/* ======================== CONTROLS =========================== */ - -/* GENERIC controls */ -#define TVI_CONTROL_IS_AUDIO 0x1 -#define TVI_CONTROL_IS_VIDEO 0x2 -#define TVI_CONTROL_IS_TUNER 0x3 -#define TVI_CONTROL_IMMEDIATE 0x4 - -/* VIDEO controls */ -#define TVI_CONTROL_VID_GET_FPS 0x101 -#define TVI_CONTROL_VID_GET_PLANES 0x102 -#define TVI_CONTROL_VID_GET_BITS 0x103 -#define TVI_CONTROL_VID_CHK_BITS 0x104 -#define TVI_CONTROL_VID_SET_BITS 0x105 -#define TVI_CONTROL_VID_GET_FORMAT 0x106 -#define TVI_CONTROL_VID_CHK_FORMAT 0x107 -#define TVI_CONTROL_VID_SET_FORMAT 0x108 -#define TVI_CONTROL_VID_GET_WIDTH 0x109 -#define TVI_CONTROL_VID_CHK_WIDTH 0x110 -#define TVI_CONTROL_VID_SET_WIDTH 0x111 -#define TVI_CONTROL_VID_GET_HEIGHT 0x112 -#define TVI_CONTROL_VID_CHK_HEIGHT 0x113 -#define TVI_CONTROL_VID_SET_HEIGHT 0x114 -#define TVI_CONTROL_VID_GET_BRIGHTNESS 0x115 -#define TVI_CONTROL_VID_SET_BRIGHTNESS 0x116 -#define TVI_CONTROL_VID_GET_HUE 0x117 -#define TVI_CONTROL_VID_SET_HUE 0x118 -#define TVI_CONTROL_VID_GET_SATURATION 0x119 -#define TVI_CONTROL_VID_SET_SATURATION 0x11a -#define TVI_CONTROL_VID_GET_CONTRAST 0x11b -#define TVI_CONTROL_VID_SET_CONTRAST 0x11c -#define TVI_CONTROL_VID_GET_PICTURE 0x11d -#define TVI_CONTROL_VID_SET_PICTURE 0x11e -#define TVI_CONTROL_VID_SET_GAIN 0x11f -#define TVI_CONTROL_VID_GET_GAIN 0x120 -#define TVI_CONTROL_VID_SET_WIDTH_HEIGHT 0x121 - -/* TUNER controls */ -#define TVI_CONTROL_TUN_GET_FREQ 0x201 -#define TVI_CONTROL_TUN_SET_FREQ 0x202 -#define TVI_CONTROL_TUN_GET_TUNER 0x203 /* update priv->tuner struct for used input */ -#define TVI_CONTROL_TUN_SET_TUNER 0x204 /* update priv->tuner struct for used input */ -#define TVI_CONTROL_TUN_GET_NORM 0x205 -#define TVI_CONTROL_TUN_SET_NORM 0x206 -#define TVI_CONTROL_TUN_GET_SIGNAL 0x207 - -/* AUDIO controls */ -#define TVI_CONTROL_AUD_GET_FORMAT 0x301 -#define TVI_CONTROL_AUD_GET_SAMPLERATE 0x302 -#define TVI_CONTROL_AUD_GET_CHANNELS 0x304 -#define TVI_CONTROL_AUD_SET_SAMPLERATE 0x305 - -/* SPECIFIC controls */ -#define TVI_CONTROL_SPC_GET_INPUT 0x401 /* set input channel (tv,s-video,composite..) */ -#define TVI_CONTROL_SPC_SET_INPUT 0x402 /* set input channel (tv,s-video,composite..) */ -#define TVI_CONTROL_SPC_GET_NORMID 0x403 /* get normid from norm name */ - -int tv_set_color_options(tvi_handle_t *tvh, int opt, int val); -int tv_get_color_options(tvi_handle_t *tvh, int opt, int* val); - -int tv_step_channel_real(tvi_handle_t *tvh, int direction); -int tv_step_channel(tvi_handle_t *tvh, int direction); -#define TV_CHANNEL_LOWER 1 -#define TV_CHANNEL_HIGHER 2 - -int tv_last_channel(tvi_handle_t *tvh); - -int tv_set_channel_real(tvi_handle_t *tvh, char *channel); -int tv_set_channel(tvi_handle_t *tvh, char *channel); - -int tv_step_norm(tvi_handle_t *tvh); -int tv_step_chanlist(tvi_handle_t *tvh); - -int tv_set_freq(tvi_handle_t *tvh, unsigned long freq); -int tv_get_freq(tvi_handle_t *tvh, unsigned long *freq); -int tv_get_signal(tvi_handle_t *tvh); -int tv_step_freq(tvi_handle_t *tvh, float step_interval); - -int tv_set_norm(tvi_handle_t *tvh, char* norm); - -void tv_start_scan(tvi_handle_t *tvh, int start); - -tvi_handle_t *tv_new_handle(int size, struct mp_log *log, const tvi_functions_t *functions); -void tv_free_handle(tvi_handle_t *h); - -#define TV_NORM_PAL 1 -#define TV_NORM_NTSC 2 -#define TV_NORM_SECAM 3 -#define TV_NORM_PALNC 4 -#define TV_NORM_PALM 5 -#define TV_NORM_PALN 6 -#define TV_NORM_NTSCJP 7 - -int tv_uninit(tvi_handle_t *tvh); -void tv_scan(tvi_handle_t *tvh); -int open_tv(tvi_handle_t *tvh); -tvi_handle_t *tv_begin(tv_param_t* tv_param, struct mp_log *log); -int tv_stream_control(tvi_handle_t *tvh, int cmd, void *arg); - -extern const struct m_sub_options tv_params_conf; - -#define MP_FOURCC(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((unsigned)(d)<<24)) - -#if BYTE_ORDER == BIG_ENDIAN -#define MP_FOURCC_E(a,b,c,d) MP_FOURCC(a,b,c,d) -#else -#define MP_FOURCC_E(a,b,c,d) MP_FOURCC(d,c,b,a) -#endif - -#define MP_FOURCC_RGB8 MP_FOURCC_E(8, 'B', 'G', 'R') -#define MP_FOURCC_RGB12 MP_FOURCC_E(12, 'B', 'G', 'R') -#define MP_FOURCC_RGB15 MP_FOURCC_E(15, 'B', 'G', 'R') -#define MP_FOURCC_RGB16 MP_FOURCC_E(16, 'B', 'G', 'R') -#define MP_FOURCC_RGB24 MP_FOURCC_E(24, 'B', 'G', 'R') -#define MP_FOURCC_RGB32 MP_FOURCC_E('A', 'B', 'G', 'R') - -#define MP_FOURCC_BGR8 MP_FOURCC_E(8, 'R', 'G', 'B') -#define MP_FOURCC_BGR12 MP_FOURCC_E(12, 'R', 'G', 'B') -#define MP_FOURCC_BGR15 MP_FOURCC_E(15, 'R', 'G', 'B') -#define MP_FOURCC_BGR16 MP_FOURCC_E(16, 'R', 'G', 'B') -#define MP_FOURCC_BGR24 MP_FOURCC_E(24, 'R', 'G', 'B') -#define MP_FOURCC_BGR32 MP_FOURCC_E('A', 'R', 'G', 'B') - -#define MP_FOURCC_YVU9 MP_FOURCC('Y', 'U', 'V', '9') -#define MP_FOURCC_YUV9 MP_FOURCC('Y', 'V', 'U', '9') -#define MP_FOURCC_YV12 MP_FOURCC('Y', 'V', '1', '2') -#define MP_FOURCC_I420 MP_FOURCC('I', '4', '2', '0') -#define MP_FOURCC_IYUV MP_FOURCC('I', 'Y', 'U', 'V') -#define MP_FOURCC_Y800 MP_FOURCC('Y', '8', '0', '0') -#define MP_FOURCC_NV12 MP_FOURCC('N', 'V', '1', '2') -#define MP_FOURCC_NV21 MP_FOURCC('N', 'V', '2', '1') - -#define MP_FOURCC_UYVY MP_FOURCC('U', 'Y', 'V', 'Y') -#define MP_FOURCC_YUY2 MP_FOURCC('Y', 'U', 'Y', '2') - -#define MP_FOURCC_MJPEG MP_FOURCC('M', 'J', 'P', 'G') -#define MP_FOURCC_JPEG MP_FOURCC('J', 'P', 'E', 'G') - -#endif /* MPLAYER_TV_H */ diff --git a/stream/tvi_def.h b/stream/tvi_def.h deleted file mode 100644 index 0794b7eb91..0000000000 --- a/stream/tvi_def.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#ifndef MPLAYER_TVI_DEF_H -#define MPLAYER_TVI_DEF_H - -#include /* malloc */ -#include /* memset */ -#include "tv.h" - -static int init(priv_t *priv); -static int uninit(priv_t *priv); -static int do_control(priv_t *priv, int cmd, void *arg); -static int start(priv_t *priv); -static double grab_video_frame(priv_t *priv, char *buffer, int len); -static int get_video_framesize(priv_t *priv); -static double grab_audio_frame(priv_t *priv, char *buffer, int len); -static int get_audio_framesize(priv_t *priv); - -static const tvi_functions_t functions = -{ - init, - uninit, - do_control, - start, - grab_video_frame, - get_video_framesize, - grab_audio_frame, - get_audio_framesize -}; - -/** - Fills video frame in given buffer with blue color for yv12,i420,uyvy,yuy2. - Other formats will be filled with 0xC0 -*/ -static inline void fill_blank_frame(char* buffer,int len,int fmt){ - int i; - // RGB(0,0,255) <-> YVU(41,110,240) - - switch(fmt){ - case MP_FOURCC_YV12: - memset(buffer, 41,4*len/6); //Y - memset(buffer+4*len/6, 110,len/6);//V - memset(buffer+5*len/6, 240,len/6);//U - break; - case MP_FOURCC_I420: - memset(buffer, 41,4*len/6); //Y - memset(buffer+4*len/6, 240,len/6);//U - memset(buffer+5*len/6, 110,len/6);//V - break; - case MP_FOURCC_UYVY: - for(i=0;i. - */ - -#include "config.h" - -#include -#include "common/common.h" -#include "tv.h" - -static tvi_handle_t *tvi_init_dummy(struct mp_log *log, tv_param_t* tv_param); -/* information about this file */ -const tvi_info_t tvi_info_dummy = { - tvi_init_dummy, - "NULL-TV", - "dummy", -}; - -/* private data's */ -typedef struct priv { - int width; - int height; -} priv_t; - -#include "tvi_def.h" - -/* handler creator - entry point ! */ -static tvi_handle_t *tvi_init_dummy(struct mp_log *log, tv_param_t* tv_param) -{ - return tv_new_handle(sizeof(priv_t), log, &functions); -} - -/* initialisation */ -static int init(priv_t *priv) -{ - priv->width = 320; - priv->height = 200; - return 1; -} - -/* that's the real start, we'got the format parameters (checked with control) */ -static int start(priv_t *priv) -{ - return 1; -} - -static int uninit(priv_t *priv) -{ - return 1; -} - -static int do_control(priv_t *priv, int cmd, void *arg) -{ - switch(cmd) - { - case TVI_CONTROL_IS_VIDEO: - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_GET_FORMAT: - *(int *)arg = MP_FOURCC_YV12; - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_SET_FORMAT: - { -// int req_fmt = *(int *)arg; - int req_fmt = *(int *)arg; - if (req_fmt != MP_FOURCC_YV12) - return TVI_CONTROL_FALSE; - return TVI_CONTROL_TRUE; - } - case TVI_CONTROL_VID_SET_WIDTH: - priv->width = *(int *)arg; - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_GET_WIDTH: - *(int *)arg = priv->width; - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_SET_HEIGHT: - priv->height = *(int *)arg; - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_GET_HEIGHT: - *(int *)arg = priv->height; - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_CHK_WIDTH: - case TVI_CONTROL_VID_CHK_HEIGHT: - return TVI_CONTROL_TRUE; - case TVI_CONTROL_TUN_SET_NORM: - return TVI_CONTROL_TRUE; - } - return TVI_CONTROL_UNKNOWN; -} - -static double grab_video_frame(priv_t *priv, char *buffer, int len) -{ - memset(buffer, 0x42, len); - return MP_NOPTS_VALUE; -} - -static int get_video_framesize(priv_t *priv) -{ - /* YV12 */ - return priv->width * priv->height * 12 / 8; -} - -static double grab_audio_frame(priv_t *priv, char *buffer, int len) -{ - memset(buffer, 0x42, len); - return MP_NOPTS_VALUE; -} - -static int get_audio_framesize(priv_t *priv) -{ - return 1; -} diff --git a/stream/tvi_v4l2.c b/stream/tvi_v4l2.c deleted file mode 100644 index 70595c6034..0000000000 --- a/stream/tvi_v4l2.c +++ /dev/null @@ -1,1786 +0,0 @@ -/* - * Video 4 Linux 2 input - * - * copyright (c) 2003 Martin Olschewski - * copyright (c) 2003 Jindrich Makovicka - * - * Some ideas are based on works from - * Alex Beregszaszi - * Gerd Knorr - * - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -/* -known issues: -- norm setting isn't consistent with tvi_v4l -- the same for volume/bass/treble/balance -*/ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if HAVE_SYS_VIDEOIO_H -#include -#else -#include -#endif -#if HAVE_LIBV4L2 -#include -#endif -#include "common/msg.h" -#include "common/common.h" -#include "audio/format.h" -#include "tv.h" -#include "audio_in.h" - -#if !HAVE_LIBV4L2 -#define v4l2_open open -#define v4l2_close close -#define v4l2_ioctl ioctl -#define v4l2_mmap mmap -#define v4l2_munmap munmap -#endif - -// flag introduced in kernel 3.10 -#ifndef V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC -#define V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC 0x2000 -#endif - -#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 -#define HAVE_CLOCK_GETTIME 1 -#else -#define HAVE_CLOCK_GETTIME 0 -#endif - -#define info tvi_info_v4l2 -static tvi_handle_t *tvi_init_v4l2(struct mp_log *log, tv_param_t* tv_param); -/* information about this file */ -const tvi_info_t tvi_info_v4l2 = { - tvi_init_v4l2, - "Video 4 Linux 2 input", - "v4l2", -}; - -struct map { - struct v4l2_buffer buf; - void *addr; - size_t len; -}; - -#define BUFFER_COUNT 6 - -/** video ringbuffer entry */ -typedef struct { - unsigned char *data; ///< frame contents - long long timestamp; ///< frame timestamp - int framesize; ///< actual frame size -} video_buffer_entry; - -/* private data */ -typedef struct priv { - /* video */ - struct mp_log *log; - char *video_dev; - int video_fd; - int mp_format; - struct v4l2_capability capability; - struct v4l2_input input; - struct v4l2_format format; - struct v4l2_standard standard; - struct v4l2_tuner tuner; - struct map *map; - int mapcount; - int frames; - volatile long long first_frame; ///< number of useconds - long long curr_frame; ///< usec, using kernel timestamps - int clk_id; /**< clk_id from clock_gettime - used in frame timestamps */ - /* audio video interleaving ;-) */ - volatile int streamon; - pthread_t audio_grabber_thread; - pthread_mutex_t skew_mutex; - - /* 2nd level video buffers */ - int first; - int immediate_mode; - - int video_buffer_size_max; - volatile int video_buffer_size_current; - video_buffer_entry *video_ringbuffer; - volatile int video_head; - volatile int video_tail; - volatile int video_cnt; - pthread_t video_grabber_thread; - pthread_mutex_t video_buffer_mutex; - - /* audio */ - char *audio_dev; - audio_in_t audio_in; - - long long audio_start_time; - int audio_buffer_size; - int aud_skew_cnt; - unsigned char *audio_ringbuffer; - long long *audio_skew_buffer; - long long *audio_skew_delta_buffer; - volatile int audio_head; - volatile int audio_tail; - volatile int audio_cnt; - volatile long long audio_skew; - volatile double audio_skew_factor; - volatile long long audio_skew_measure_time; - volatile int audio_drop; - volatile int shutdown; - - int audio_initialized; - double audio_secs_per_block; - long long audio_usecs_per_block; - long long audio_skew_total; - long long audio_skew_delta_total; - long audio_recv_blocks_total; - long audio_sent_blocks_total; - pthread_mutex_t audio_mutex; - int audio_insert_null_samples; - volatile long audio_null_blocks_inserted; - volatile long long dropped_frames_timeshift; - long long dropped_frames_compensated; - - tv_param_t *tv_param; -} priv_t; - -typedef struct tt_stream_props_s{ - int sampling_rate; - int samples_per_line; - int offset; - int count[2]; ///< number of lines in first and second fields - int interlaced; ///< vbi data are interlaced - int bufsize; ///< required buffer size -} tt_stream_props; - -#include "tvi_def.h" - -static void *audio_grabber(void *data); -static void *video_grabber(void *data); - -/**********************************************************************\ - - Only few of the fourccs are the same in v4l2 and mplayer: - - MP_FOURCC_YVU9 == V4L2_PIX_FMT_YVU410 - MP_FOURCC_YV12 == V4L2_PIX_FMT_YVU420 - MP_FOURCC_NV12 == V4L2_PIX_FMT_NV12 - MP_FOURCC_422P == V4L2_PIX_FMT_YUV422P - MP_FOURCC_411P == V4L2_PIX_FMT_YUV411P - MP_FOURCC_UYVY == V4L2_PIX_FMT_UYVY - MP_FOURCC_Y41P == V4L2_PIX_FMT_Y41P - - This may be an useful translation table for some others: - - MP_FOURCC_RGB8 == V4L2_PIX_FMT_RGB332 - MP_FOURCC_BGR15 == V4L2_PIX_FMT_RGB555 - MP_FOURCC_BGR16 == V4L2_PIX_FMT_RGB565 - MP_FOURCC_RGB24 == V4L2_PIX_FMT_RGB24 - MP_FOURCC_RGB32 == V4L2_PIX_FMT_RGB32 - MP_FOURCC_BGR24 == V4L2_PIX_FMT_BGR24 - MP_FOURCC_BGR32 == V4L2_PIX_FMT_BGR32 - MP_FOURCC_Y800 == V4L2_PIX_FMT_GREY - MP_FOURCC_YUV9 == V4L2_PIX_FMT_YUV410 - MP_FOURCC_I420 == V4L2_PIX_FMT_YUV420 - MP_FOURCC_YUY2 == V4L2_PIX_FMT_YUYV - -\**********************************************************************/ - -/* -** Translate a mplayer fourcc to a video4linux2 pixel format. -*/ -static int fcc_mp2vl(int fcc) -{ - switch (fcc) { - case MP_FOURCC_RGB8: return V4L2_PIX_FMT_RGB332; - case MP_FOURCC_BGR15: return V4L2_PIX_FMT_RGB555; - case MP_FOURCC_BGR16: return V4L2_PIX_FMT_RGB565; - case MP_FOURCC_RGB24: return V4L2_PIX_FMT_RGB24; - case MP_FOURCC_RGB32: return V4L2_PIX_FMT_RGB32; - case MP_FOURCC_BGR24: return V4L2_PIX_FMT_BGR24; - case MP_FOURCC_BGR32: return V4L2_PIX_FMT_BGR32; - case MP_FOURCC_Y800: return V4L2_PIX_FMT_GREY; - case MP_FOURCC_YUV9: return V4L2_PIX_FMT_YUV410; - case MP_FOURCC_I420: return V4L2_PIX_FMT_YUV420; - case MP_FOURCC_YUY2: return V4L2_PIX_FMT_YUYV; - case MP_FOURCC_YV12: return V4L2_PIX_FMT_YVU420; - case MP_FOURCC_UYVY: return V4L2_PIX_FMT_UYVY; - case MP_FOURCC_MJPEG: return V4L2_PIX_FMT_MJPEG; - case MP_FOURCC_JPEG: return V4L2_PIX_FMT_JPEG; - } - return fcc; -} - -/* -** Translate a video4linux2 fourcc aka pixel format to mplayer. -*/ -static int fcc_vl2mp(int fcc) -{ - switch (fcc) { - case V4L2_PIX_FMT_RGB332: return MP_FOURCC_RGB8; - case V4L2_PIX_FMT_RGB555: return MP_FOURCC_BGR15; - case V4L2_PIX_FMT_RGB565: return MP_FOURCC_BGR16; - case V4L2_PIX_FMT_RGB24: return MP_FOURCC_RGB24; - case V4L2_PIX_FMT_RGB32: return MP_FOURCC_RGB32; - case V4L2_PIX_FMT_BGR24: return MP_FOURCC_BGR24; - case V4L2_PIX_FMT_BGR32: return MP_FOURCC_BGR32; - case V4L2_PIX_FMT_GREY: return MP_FOURCC_Y800; - case V4L2_PIX_FMT_YUV410: return MP_FOURCC_YUV9; - case V4L2_PIX_FMT_YUV420: return MP_FOURCC_I420; - case V4L2_PIX_FMT_YVU420: return MP_FOURCC_YV12; - case V4L2_PIX_FMT_YUYV: return MP_FOURCC_YUY2; - case V4L2_PIX_FMT_UYVY: return MP_FOURCC_UYVY; - case V4L2_PIX_FMT_MJPEG: return MP_FOURCC_MJPEG; - case V4L2_PIX_FMT_JPEG: return MP_FOURCC_JPEG; - } - return fcc; -} - -/* -** Translate a video4linux2 fourcc aka pixel format -** to a human readable string. -*/ -static const char *pixfmt2name(char *buf, int pixfmt) -{ - switch (pixfmt) { - case V4L2_PIX_FMT_RGB332: return "RGB332"; - case V4L2_PIX_FMT_RGB555: return "RGB555"; - case V4L2_PIX_FMT_RGB565: return "RGB565"; - case V4L2_PIX_FMT_RGB555X: return "RGB555X"; - case V4L2_PIX_FMT_RGB565X: return "RGB565X"; - case V4L2_PIX_FMT_BGR24: return "BGR24"; - case V4L2_PIX_FMT_RGB24: return "RGB24"; - case V4L2_PIX_FMT_BGR32: return "BGR32"; - case V4L2_PIX_FMT_RGB32: return "RGB32"; - case V4L2_PIX_FMT_GREY: return "GREY"; - case V4L2_PIX_FMT_YVU410: return "YVU410"; - case V4L2_PIX_FMT_YVU420: return "YVU420"; - case V4L2_PIX_FMT_YUYV: return "YUYV"; - case V4L2_PIX_FMT_UYVY: return "UYVY"; -/* case V4L2_PIX_FMT_YVU422P: return "YVU422P"; */ -/* case V4L2_PIX_FMT_YVU411P: return "YVU411P"; */ - case V4L2_PIX_FMT_YUV422P: return "YUV422P"; - case V4L2_PIX_FMT_YUV411P: return "YUV411P"; - case V4L2_PIX_FMT_Y41P: return "Y41P"; - case V4L2_PIX_FMT_NV12: return "NV12"; - case V4L2_PIX_FMT_NV21: return "NV21"; - case V4L2_PIX_FMT_YUV410: return "YUV410"; - case V4L2_PIX_FMT_YUV420: return "YUV420"; - case V4L2_PIX_FMT_YYUV: return "YYUV"; - case V4L2_PIX_FMT_HI240: return "HI240"; - case V4L2_PIX_FMT_WNVA: return "WNVA"; - case V4L2_PIX_FMT_MJPEG: return "MJPEG"; - case V4L2_PIX_FMT_JPEG: return "JPEG"; - } - sprintf(buf, "unknown (0x%x)", pixfmt); - return buf; -} - - -/* -** Gives the depth of a video4linux2 fourcc aka pixel format in bits. -*/ -static int pixfmt2depth(int pixfmt) -{ - switch (pixfmt) { - case V4L2_PIX_FMT_RGB332: - return 8; - case V4L2_PIX_FMT_RGB555: - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB555X: - case V4L2_PIX_FMT_RGB565X: - return 16; - case V4L2_PIX_FMT_BGR24: - case V4L2_PIX_FMT_RGB24: - return 24; - case V4L2_PIX_FMT_BGR32: - case V4L2_PIX_FMT_RGB32: - return 32; - case V4L2_PIX_FMT_GREY: - return 8; - case V4L2_PIX_FMT_YVU410: - return 9; - case V4L2_PIX_FMT_YVU420: - return 12; - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_YUV422P: - case V4L2_PIX_FMT_YUV411P: - return 16; - case V4L2_PIX_FMT_Y41P: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - return 12; - case V4L2_PIX_FMT_YUV410: - return 9; - case V4L2_PIX_FMT_YUV420: - return 12; - case V4L2_PIX_FMT_YYUV: - return 16; - case V4L2_PIX_FMT_HI240: - return 8; - - } - return 0; -} - -static int amode2v4l(int amode) -{ - switch (amode) { - case 0: - return V4L2_TUNER_MODE_MONO; - case 1: - return V4L2_TUNER_MODE_STEREO; - case 2: - return V4L2_TUNER_MODE_LANG1; - case 3: - return V4L2_TUNER_MODE_LANG2; - default: - return -1; - } -} - - -/* -** Get current FPS. -*/ -static double getfps(priv_t *priv) -{ - if (priv->tv_param->fps > 0) - return priv->tv_param->fps; - if (priv->standard.frameperiod.denominator && priv->standard.frameperiod.numerator) - return (double)priv->standard.frameperiod.denominator / priv->standard.frameperiod.numerator; - return 25.0; -} - -// sets and sanitizes audio buffer/block sizes -static void setup_audio_buffer_sizes(priv_t *priv) -{ - int bytes_per_sample = priv->audio_in.bytes_per_sample; - int seconds = priv->video_buffer_size_max/getfps(priv); - - if (seconds < 5) seconds = 5; - if (seconds > 500) seconds = 500; - - // make the audio buffer at least as the video buffer capacity (or 5 seconds) long - priv->audio_buffer_size = 1 + seconds*priv->audio_in.samplerate - *priv->audio_in.channels - *bytes_per_sample/priv->audio_in.blocksize; - if (priv->audio_buffer_size < 256) priv->audio_buffer_size = 256; - - // make the skew buffer at least 1 second long - priv->aud_skew_cnt = 1 + 1*priv->audio_in.samplerate - *priv->audio_in.channels - *bytes_per_sample/priv->audio_in.blocksize; - if (priv->aud_skew_cnt < 16) priv->aud_skew_cnt = 16; - - MP_VERBOSE(priv, "Audio capture - buffer %d blocks of %d bytes, skew average from %d meas.\n", - priv->audio_buffer_size, priv->audio_in.blocksize, priv->aud_skew_cnt); -} - -static void init_audio(priv_t *priv) -{ - if (priv->audio_initialized) return; - - if (priv->tv_param->audio) { -#if HAVE_ALSA - if (priv->tv_param->alsa) - audio_in_init(&priv->audio_in, priv->log, AUDIO_IN_ALSA); - else - audio_in_init(&priv->audio_in, priv->log, AUDIO_IN_OSS); -#else - audio_in_init(&priv->audio_in, priv->log, AUDIO_IN_OSS); -#endif - - if (priv->audio_dev) { - audio_in_set_device(&priv->audio_in, priv->audio_dev); - } - - audio_in_set_samplerate(&priv->audio_in, 44100); - if (priv->capability.capabilities & V4L2_CAP_TUNER) { - if (priv->tuner.audmode == V4L2_TUNER_MODE_STEREO) { - audio_in_set_channels(&priv->audio_in, 2); - } else { - audio_in_set_channels(&priv->audio_in, 1); - } - } else { - if (priv->tv_param->forcechan >= 0) { - audio_in_set_channels(&priv->audio_in, priv->tv_param->forcechan); - } else { - audio_in_set_channels(&priv->audio_in, 2); - } - } - - if (audio_in_setup(&priv->audio_in) < 0) return; - - priv->audio_initialized = 1; - } -} - -#if 0 -/* -** the number of milliseconds elapsed between time0 and time1 -*/ -static size_t difftv(struct timeval time1, struct timeval time0) -{ - return (time1.tv_sec - time0.tv_sec) * 1000 + - (time1.tv_usec - time0.tv_usec) / 1000; -} -#endif - -/* -** Get current video capture format. -*/ -static int getfmt(priv_t *priv) -{ - int i; - - priv->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if ((i = v4l2_ioctl(priv->video_fd, VIDIOC_G_FMT, &priv->format)) < 0) { - MP_ERR(priv, "ioctl get format failed: %s\n", - mp_strerror(errno)); - } - return i; -} - - -/* -** Get current video capture standard. -*/ -static int getstd(priv_t *priv) -{ - v4l2_std_id id; - int i=0; - - if (v4l2_ioctl(priv->video_fd, VIDIOC_G_STD, &id) < 0) { - struct v4l2_streamparm parm; - - parm.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; - if(v4l2_ioctl(priv->video_fd, VIDIOC_G_PARM, &parm) >= 0) { - MP_WARN(priv, "your device driver does not support VIDIOC_G_STD ioctl," - " VIDIOC_G_PARM was used instead.\n"); - priv->standard.index=0; - priv->standard.id=0; - priv->standard.frameperiod=parm.parm.capture.timeperframe; - return 0; - } - - MP_ERR(priv, "ioctl get standard failed: %s\n", mp_strerror(errno)); - return -1; - } - do { - priv->standard.index = i++; - if (v4l2_ioctl(priv->video_fd, VIDIOC_ENUMSTD, &priv->standard) < 0) { - return -1; - } - } while (priv->standard.id != id); - return 0; -} - -#if HAVE_CLOCK_GETTIME -/* -** Gets current timestamp, using specified clock id. -** @return number of microseconds. -*/ -static long long get_curr_timestamp(int clk_id) -{ - struct timespec ts; - clock_gettime(clk_id, &ts); - return (long long)ts.tv_sec * 1000000 + ts.tv_nsec / 1000; -} -#else -/* -** Gets current timestamp, using system time. -** @return number of microseconds. -*/ -static long long get_curr_timestamp(int clk_id) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return (long long)tv.tv_sec * 1000000 + tv.tv_usec; -} -#endif - -/***********************************************************************\ - * * - * * - * Interface to mplayer * - * * - * * -\***********************************************************************/ - -static int set_mute(priv_t *priv, int value) -{ - struct v4l2_control control; - control.id = V4L2_CID_AUDIO_MUTE; - control.value = value; - if (v4l2_ioctl(priv->video_fd, VIDIOC_S_CTRL, &control) < 0) { - MP_ERR(priv, "ioctl set mute failed: %s\n", mp_strerror(errno)); - return 0; - } - return 1; -} - -/* -** MPlayer uses values from -100 up to 100 for controls. -** Here they are scaled to what the tv card needs and applied. -*/ -static int set_control(priv_t *priv, struct v4l2_control *control, int val_signed) { - struct v4l2_queryctrl qctrl; - qctrl.id = control->id; - if (v4l2_ioctl(priv->video_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) { - MP_ERR(priv, "ioctl query control failed: %s\n", mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } - - if (val_signed) { - if (control->value < 0) { - control->value = qctrl.default_value + control->value * - (qctrl.default_value - qctrl.minimum) / 100; - } else { - control->value = qctrl.default_value + control->value * - (qctrl.maximum - qctrl.default_value) / 100; - } - } else { - if (control->value < 50) { - control->value = qctrl.default_value + (control->value-50) * - (qctrl.default_value - qctrl.minimum) / 50; - } else { - control->value = qctrl.default_value + (control->value-50) * - (qctrl.maximum - qctrl.default_value) / 50; - } - } - - - if (v4l2_ioctl(priv->video_fd, VIDIOC_S_CTRL, control) < 0) { - MP_ERR(priv, "ioctl set %s %d failed: %s\n", - qctrl.name, control->value, mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } - MP_VERBOSE(priv, "set %s: %d [%d, %d]\n", - qctrl.name, control->value, qctrl.minimum, qctrl.maximum); - - return TVI_CONTROL_TRUE; -} - - -/* -** Scale the control values back to what mplayer needs. -*/ -static int get_control(priv_t *priv, struct v4l2_control *control, int val_signed) { - struct v4l2_queryctrl qctrl; - - qctrl.id = control->id; - if (v4l2_ioctl(priv->video_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) { - MP_ERR(priv, "ioctl query control failed: %s\n", mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } - - if (v4l2_ioctl(priv->video_fd, VIDIOC_G_CTRL, control) < 0) { - MP_ERR(priv, "ioctl get %s failed: %s\n", qctrl.name, mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } - MP_VERBOSE(priv, "get %s: %d [%d, %d]\n", - qctrl.name, control->value, qctrl.minimum, qctrl.maximum); - - if (val_signed) { - if (control->value < qctrl.default_value) { - control->value = (control->value - qctrl.default_value) * 100 / - (qctrl.default_value - qctrl.minimum); - } else { - control->value = (control->value - qctrl.default_value) * 100 / - (qctrl.maximum - qctrl.default_value); - } - } else { - if (control->value < qctrl.default_value) { - control->value = (control->value - qctrl.default_value) * 50 / - (qctrl.default_value - qctrl.minimum) + 50; - } else { - control->value = (control->value - qctrl.default_value) * 50 / - (qctrl.maximum - qctrl.default_value) + 50; - } - } - - return TVI_CONTROL_TRUE; -} - -static int do_control(priv_t *priv, int cmd, void *arg) -{ - struct v4l2_control control; - struct v4l2_frequency frequency; - char buf[80]; - - switch(cmd) { - case TVI_CONTROL_IS_VIDEO: - return priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE? - TVI_CONTROL_TRUE: TVI_CONTROL_FALSE; - case TVI_CONTROL_IS_AUDIO: - if (priv->tv_param->force_audio) return TVI_CONTROL_TRUE; - case TVI_CONTROL_IS_TUNER: - return priv->capability.capabilities & V4L2_CAP_TUNER? - TVI_CONTROL_TRUE: TVI_CONTROL_FALSE; - case TVI_CONTROL_IMMEDIATE: - priv->immediate_mode = 1; - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_GET_FPS: - *(float *)arg = getfps(priv); - MP_VERBOSE(priv, "get fps: %f\n", *(float *)arg); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_GET_BITS: - if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; - *(int *)arg = pixfmt2depth(priv->format.fmt.pix.pixelformat); - MP_VERBOSE(priv, "get depth: %d\n", *(int *)arg); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_GET_FORMAT: - if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; - *(int *)arg = fcc_vl2mp(priv->format.fmt.pix.pixelformat); - MP_VERBOSE(priv, "get format: %s\n", - pixfmt2name(buf, priv->format.fmt.pix.pixelformat)); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_SET_FORMAT: - if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; - priv->format.fmt.pix.pixelformat = fcc_mp2vl(*(int *)arg); - priv->format.fmt.pix.field = V4L2_FIELD_ANY; - - priv->mp_format = *(int *)arg; - MP_VERBOSE(priv, "set format: %s\n", - pixfmt2name(buf, priv->format.fmt.pix.pixelformat)); - if (v4l2_ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { - MP_ERR(priv, "ioctl set format failed: %s\n", mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } - /* according to the v4l2 specs VIDIOC_S_FMT should not fail, inflexible drivers - might even always return the default parameters -> update the format here*/ - priv->mp_format = fcc_vl2mp(priv->format.fmt.pix.pixelformat); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_GET_WIDTH: - if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; - *(int *)arg = priv->format.fmt.pix.width; - MP_VERBOSE(priv, "get width: %d\n", *(int *)arg); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_CHK_WIDTH: - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_SET_WIDTH_HEIGHT: - if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; - priv->format.fmt.pix.width = ((int *)arg)[0]; - priv->format.fmt.pix.height = ((int *)arg)[1]; - priv->format.fmt.pix.field = V4L2_FIELD_ANY; - if (v4l2_ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) - return TVI_CONTROL_FALSE; - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_SET_WIDTH: - if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; - priv->format.fmt.pix.width = *(int *)arg; - MP_VERBOSE(priv, "set width: %d\n", *(int *)arg); - if (v4l2_ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { - MP_ERR(priv, "ioctl set width failed: %s\n", mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_GET_HEIGHT: - if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; - *(int *)arg = priv->format.fmt.pix.height; - MP_VERBOSE(priv, "get height: %d\n", *(int *)arg); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_CHK_HEIGHT: - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_SET_HEIGHT: - if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; - priv->format.fmt.pix.height = *(int *)arg; - priv->format.fmt.pix.field = V4L2_FIELD_ANY; - MP_VERBOSE(priv, "set height: %d\n", *(int *)arg); - if (v4l2_ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { - MP_ERR(priv, "ioctl set height failed: %s\n", mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_GET_BRIGHTNESS: - control.id = V4L2_CID_BRIGHTNESS; - if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { - *(int *)arg = control.value; - return TVI_CONTROL_TRUE; - } - return TVI_CONTROL_FALSE; - case TVI_CONTROL_VID_SET_BRIGHTNESS: - control.id = V4L2_CID_BRIGHTNESS; - control.value = *(int *)arg; - return set_control(priv, &control, 1); - case TVI_CONTROL_VID_GET_HUE: - control.id = V4L2_CID_HUE; - if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { - *(int *)arg = control.value; - return TVI_CONTROL_TRUE; - } - return TVI_CONTROL_FALSE; - case TVI_CONTROL_VID_SET_HUE: - control.id = V4L2_CID_HUE; - control.value = *(int *)arg; - return set_control(priv, &control, 1); - case TVI_CONTROL_VID_GET_SATURATION: - control.id = V4L2_CID_SATURATION; - if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { - *(int *)arg = control.value; - return TVI_CONTROL_TRUE; - } - return TVI_CONTROL_FALSE; - case TVI_CONTROL_VID_SET_SATURATION: - control.id = V4L2_CID_SATURATION; - control.value = *(int *)arg; - return set_control(priv, &control, 1); - case TVI_CONTROL_VID_GET_GAIN: - { - - control.id = V4L2_CID_AUTOGAIN; - if(get_control(priv,&control,0)!=TVI_CONTROL_TRUE) - return TVI_CONTROL_FALSE; - - if(control.value){ //Auto Gain control is enabled - *(int*)arg=0; - return TVI_CONTROL_TRUE; - } - - //Manual Gain control - control.id = V4L2_CID_GAIN; - if(get_control(priv,&control,0)!=TVI_CONTROL_TRUE) - return TVI_CONTROL_FALSE; - - *(int*)arg=control.value?control.value:1; - - return TVI_CONTROL_TRUE; - } - case TVI_CONTROL_VID_SET_GAIN: - { - //value==0 means automatic gain control - int value=*(int*)arg; - - if (value < 0 || value>100) - return TVI_CONTROL_FALSE; - - control.id=value?V4L2_CID_GAIN:V4L2_CID_AUTOGAIN; - control.value=value?value:1; - - return set_control(priv,&control,0); - } - case TVI_CONTROL_VID_GET_CONTRAST: - control.id = V4L2_CID_CONTRAST; - if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { - *(int *)arg = control.value; - return TVI_CONTROL_TRUE; - } - return TVI_CONTROL_FALSE; - case TVI_CONTROL_VID_SET_CONTRAST: - control.id = V4L2_CID_CONTRAST; - control.value = *(int *)arg; - return set_control(priv, &control, 1); - case TVI_CONTROL_TUN_GET_FREQ: - frequency.tuner = 0; - frequency.type = V4L2_TUNER_ANALOG_TV; - if (v4l2_ioctl(priv->video_fd, VIDIOC_G_FREQUENCY, &frequency) < 0) { - MP_ERR(priv, "ioctl get frequency failed: %s\n", mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } - *(int *)arg = frequency.frequency; - return TVI_CONTROL_TRUE; - case TVI_CONTROL_TUN_SET_FREQ: -#if 0 - set_mute(priv, 1); - usleep(100000); // wait to suppress noise during switching -#endif - frequency.tuner = 0; - frequency.type = V4L2_TUNER_ANALOG_TV; - frequency.frequency = *(int *)arg; - if (v4l2_ioctl(priv->video_fd, VIDIOC_S_FREQUENCY, &frequency) < 0) { - MP_ERR(priv, "ioctl set frequency failed: %s\n", mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } -#if 0 - usleep(100000); // wait to suppress noise during switching - set_mute(priv, 0); -#endif - return TVI_CONTROL_TRUE; - case TVI_CONTROL_TUN_GET_TUNER: - MP_VERBOSE(priv, "get tuner\n"); - if (v4l2_ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) < 0) { - MP_ERR(priv, "ioctl get tuner failed: %s\n", mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } - return TVI_CONTROL_TRUE; - case TVI_CONTROL_TUN_SET_TUNER: - MP_VERBOSE(priv, "set tuner\n"); - if (v4l2_ioctl(priv->video_fd, VIDIOC_S_TUNER, &priv->tuner) < 0) { - MP_ERR(priv, "ioctl set tuner failed: %s\n", mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } - return TVI_CONTROL_TRUE; - case TVI_CONTROL_TUN_GET_NORM: - *(int *)arg = priv->standard.index; - return TVI_CONTROL_TRUE; - case TVI_CONTROL_TUN_GET_SIGNAL: - if (v4l2_ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) < 0) { - MP_ERR(priv, "ioctl get tuner failed: %s\n", mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } - *(int*)arg=100*(priv->tuner.signal>>8)/255; - return TVI_CONTROL_TRUE; - case TVI_CONTROL_TUN_SET_NORM: - priv->standard.index = *(int *)arg; - if (v4l2_ioctl(priv->video_fd, VIDIOC_ENUMSTD, &priv->standard) < 0) { - MP_ERR(priv, "ioctl enum norm failed: %s\n", mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } - MP_VERBOSE(priv, "set norm: %s\n", priv->standard.name); - if (v4l2_ioctl(priv->video_fd, VIDIOC_S_STD, &priv->standard.id) < 0) { - MP_ERR(priv, "ioctl set norm failed: %s\n", mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } - return TVI_CONTROL_TRUE; - case TVI_CONTROL_SPC_GET_NORMID: - { - int i; - for (i = 0;; i++) { - struct v4l2_standard standard; - memset(&standard, 0, sizeof(standard)); - standard.index = i; - if (-1 == v4l2_ioctl(priv->video_fd, VIDIOC_ENUMSTD, &standard)) - return TVI_CONTROL_FALSE; - if (!strcasecmp(standard.name, (char *)arg)) { - *(int *)arg = i; - return TVI_CONTROL_TRUE; - } - } - return TVI_CONTROL_FALSE; - } - case TVI_CONTROL_SPC_GET_INPUT: - if (v4l2_ioctl(priv->video_fd, VIDIOC_G_INPUT, (int *)arg) < 0) { - MP_ERR(priv, "ioctl get input failed: %s\n", mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } - return TVI_CONTROL_TRUE; - case TVI_CONTROL_SPC_SET_INPUT: - MP_VERBOSE(priv, "set input: %d\n", *(int *)arg); - priv->input.index = *(int *)arg; - if (v4l2_ioctl(priv->video_fd, VIDIOC_ENUMINPUT, &priv->input) < 0) { - MP_ERR(priv, "ioctl enum input failed: %s\n", mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } - if (v4l2_ioctl(priv->video_fd, VIDIOC_S_INPUT, (int *)arg) < 0) { - MP_ERR(priv, "ioctl set input failed: %s\n", mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } - return TVI_CONTROL_TRUE; - case TVI_CONTROL_AUD_GET_FORMAT: - init_audio(priv); - if (!priv->audio_initialized) return TVI_CONTROL_FALSE; - *(int *)arg = AF_FORMAT_S16; - MP_VERBOSE(priv, "get audio format: %d\n", *(int *)arg); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_AUD_GET_SAMPLERATE: - init_audio(priv); - if (!priv->audio_initialized) return TVI_CONTROL_FALSE; - *(int *)arg = priv->audio_in.samplerate; - MP_VERBOSE(priv, "get audio samplerate: %d\n", *(int *)arg); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_AUD_GET_CHANNELS: - init_audio(priv); - if (!priv->audio_initialized) return TVI_CONTROL_FALSE; - *(int *)arg = priv->audio_in.channels; - MP_VERBOSE(priv, "get audio channels: %d\n", *(int *)arg); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_AUD_SET_SAMPLERATE: - init_audio(priv); - MP_VERBOSE(priv, "set audio samplerate: %d\n", *(int *)arg); - if (audio_in_set_samplerate(&priv->audio_in, *(int*)arg) < 0) return TVI_CONTROL_FALSE; -// setup_audio_buffer_sizes(priv); - return TVI_CONTROL_TRUE; - } - MP_VERBOSE(priv, "unknown control: %d\n", cmd); - return TVI_CONTROL_UNKNOWN; -} - - -#define PRIV ((priv_t *) (tvi_handle->priv)) - -/* handler creator - entry point ! */ -static tvi_handle_t *tvi_init_v4l2(struct mp_log *log, tv_param_t* tv_param) -{ - tvi_handle_t *tvi_handle; - - tvi_handle = tv_new_handle(sizeof(priv_t), log, &functions); - if (!tvi_handle) { - return NULL; - } - PRIV->log = log; - PRIV->video_fd = -1; - - PRIV->video_dev = strdup(tv_param->device? tv_param->device: "/dev/video0"); - if (!PRIV->video_dev) { - tv_free_handle(tvi_handle); - return NULL; - } - - if (tv_param->adevice) { - PRIV->audio_dev = strdup(tv_param->adevice); - if (!PRIV->audio_dev) { - free(PRIV->video_dev); - tv_free_handle(tvi_handle); - return NULL; - } - } - - PRIV->tv_param=tv_param; - return tvi_handle; -} - -#undef PRIV - - -static int uninit(priv_t *priv) -{ - int i, frames, dropped = 0; - - priv->shutdown = 1; - if(priv->video_grabber_thread) - pthread_join(priv->video_grabber_thread, NULL); - pthread_mutex_destroy(&priv->video_buffer_mutex); - - if (priv->streamon) { - /* get performance */ - frames = 1 + lrintf((double)(priv->curr_frame - priv->first_frame) / 1e6 * getfps(priv)); - dropped = frames - priv->frames; - - /* turn off streaming */ - if (v4l2_ioctl(priv->video_fd, VIDIOC_STREAMOFF, &(priv->map[0].buf.type)) < 0) { - MP_ERR(priv, "ioctl streamoff failed: %s\n", mp_strerror(errno)); - } - priv->streamon = 0; - - /* unqueue all remaining buffers (not sure if this code is correct) */ - for (i = 0; i < priv->mapcount; i++) { - if (v4l2_ioctl(priv->video_fd, VIDIOC_DQBUF, &priv->map[i].buf) < 0) { - MP_ERR(priv, "VIDIOC_DQBUF failed: %s\n", mp_strerror(errno)); - } - } - } - - /* unmap all buffers */ - for (i = 0; i < priv->mapcount; i++) { - if (v4l2_munmap(priv->map[i].addr, priv->map[i].len) < 0) { - MP_ERR(priv, "munmap capture buffer failed: %s\n", mp_strerror(errno)); - } - } - - /* stop audio thread */ - if (priv->tv_param->audio && priv->audio_grabber_thread) { - pthread_join(priv->audio_grabber_thread, NULL); - pthread_mutex_destroy(&priv->skew_mutex); - pthread_mutex_destroy(&priv->audio_mutex); - } - - set_mute(priv, 1); - - /* free memory and close device */ - free(priv->map); - priv->map = NULL; - priv->mapcount = 0; - if (priv->video_fd != -1) { - v4l2_close(priv->video_fd); - priv->video_fd = -1; - } - free(priv->video_dev); - priv->video_dev = NULL; - - if (priv->video_ringbuffer) { - for (int n = 0; n < priv->video_buffer_size_current; n++) { - free(priv->video_ringbuffer[n].data); - } - free(priv->video_ringbuffer); - } - if (priv->tv_param->audio) { - free(priv->audio_ringbuffer); - free(priv->audio_skew_buffer); - free(priv->audio_skew_delta_buffer); - - audio_in_uninit(&priv->audio_in); - } - - /* show some nice statistics ;-) */ - MP_INFO(priv, "%d frames successfully processed, %d frames dropped.\n", - priv->frames, dropped); - MP_VERBOSE(priv, "up to %u video frames buffered.\n", - priv->video_buffer_size_current); - return 1; -} - - -/* initialisation */ -static int init(priv_t *priv) -{ - int i; - - priv->audio_ringbuffer = NULL; - priv->audio_skew_buffer = NULL; - priv->audio_skew_delta_buffer = NULL; - - priv->audio_initialized = 0; - - /* Open the video device. */ - priv->video_fd = v4l2_open(priv->video_dev, O_RDWR); - if (priv->video_fd < 0) { - MP_ERR(priv, "unable to open '%s': %s\n", priv->video_dev, mp_strerror(errno)); - uninit(priv); - return 0; - } - MP_DBG(priv, "video fd: %s: %d\n", priv->video_dev, priv->video_fd); - - /* - ** Query the video capabilities and current settings - ** for further control calls. - */ - if (v4l2_ioctl(priv->video_fd, VIDIOC_QUERYCAP, &priv->capability) < 0) { - MP_ERR(priv, "ioctl query capabilities failed: %s\n", mp_strerror(errno)); - uninit(priv); - return 0; - } - - if (!(priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE)) - { - MP_ERR(priv, "Device %s is not a video capture device.\n", - priv->video_dev); - return 0; - } - - if (getfmt(priv) < 0) { - uninit(priv); - return 0; - } - getstd(priv); - /* - ** if this device has got a tuner query it's settings - ** otherwise set some nice defaults - */ - if (priv->capability.capabilities & V4L2_CAP_TUNER) { - if (v4l2_ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) < 0) { - MP_ERR(priv, "ioctl get tuner failed: %s\n", mp_strerror(errno)); - uninit(priv); - return 0; - } - } - MP_INFO(priv, "Selected device: %s\n", priv->capability.card); - if (priv->capability.capabilities & V4L2_CAP_TUNER) { - MP_INFO(priv, " Tuner cap:%s%s%s\n", - (priv->tuner.capability & V4L2_TUNER_CAP_STEREO) ? " STEREO" : "", - (priv->tuner.capability & V4L2_TUNER_CAP_LANG1) ? " LANG1" : "", - (priv->tuner.capability & V4L2_TUNER_CAP_LANG2) ? " LANG2" : ""); - MP_INFO(priv, " Tuner rxs:%s%s%s%s\n", - (priv->tuner.rxsubchans & V4L2_TUNER_SUB_MONO) ? " MONO" : "", - (priv->tuner.rxsubchans & V4L2_TUNER_SUB_STEREO) ? " STEREO" : "", - (priv->tuner.rxsubchans & V4L2_TUNER_SUB_LANG1) ? " LANG1" : "", - (priv->tuner.rxsubchans & V4L2_TUNER_SUB_LANG2) ? " LANG2" : ""); - } - MP_INFO(priv, " Capabilities:%s%s%s%s%s%s%s%s%s%s%s\n", - priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE? - " video capture": "", - priv->capability.capabilities & V4L2_CAP_VIDEO_OUTPUT? - " video output": "", - priv->capability.capabilities & V4L2_CAP_VIDEO_OVERLAY? - " video overlay": "", - priv->capability.capabilities & V4L2_CAP_VBI_CAPTURE? - " VBI capture device": "", - priv->capability.capabilities & V4L2_CAP_VBI_OUTPUT? - " VBI output": "", - priv->capability.capabilities & V4L2_CAP_RDS_CAPTURE? - " RDS data capture": "", - priv->capability.capabilities & V4L2_CAP_TUNER? - " tuner": "", - priv->capability.capabilities & V4L2_CAP_AUDIO? - " audio": "", - priv->capability.capabilities & V4L2_CAP_READWRITE? - " read/write": "", - priv->capability.capabilities & V4L2_CAP_ASYNCIO? - " async i/o": "", - priv->capability.capabilities & V4L2_CAP_STREAMING? - " streaming": ""); - MP_INFO(priv, " supported norms:"); - for (i = 0;; i++) { - struct v4l2_standard standard; - memset(&standard, 0, sizeof(standard)); - standard.index = i; - if (-1 == v4l2_ioctl(priv->video_fd, VIDIOC_ENUMSTD, &standard)) - break; - MP_INFO(priv, " %d = %s;", i, standard.name); - } - MP_INFO(priv, "\n inputs:"); - for (i = 0; 1; i++) { - struct v4l2_input input; - - input.index = i; - if (v4l2_ioctl(priv->video_fd, VIDIOC_ENUMINPUT, &input) < 0) { - break; - } - MP_INFO(priv, " %d = %s;", i, input.name); - } - i = -1; - if (v4l2_ioctl(priv->video_fd, VIDIOC_G_INPUT, &i) < 0) { - MP_ERR(priv, "ioctl get input failed: %s\n", mp_strerror(errno)); - } - char buf[80]; - MP_INFO(priv, "\n Current input: %d\n", i); - for (i = 0; ; i++) { - struct v4l2_fmtdesc fmtdesc; - - fmtdesc.index = i; - fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (v4l2_ioctl(priv->video_fd, VIDIOC_ENUM_FMT, &fmtdesc) < 0) { - break; - } - MP_VERBOSE(priv, " Format %-6s (%2d bits, %s)\n", - pixfmt2name(buf, fmtdesc.pixelformat), pixfmt2depth(fmtdesc.pixelformat), - fmtdesc.description); - } - MP_INFO(priv, " Current format: %s\n", - pixfmt2name(buf, priv->format.fmt.pix.pixelformat)); - - /* set some nice defaults */ - if (getfmt(priv) < 0) return 0; - priv->format.fmt.pix.width = 640; - priv->format.fmt.pix.height = 480; - if (v4l2_ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { - MP_ERR(priv, "ioctl set format failed: %s\n", mp_strerror(errno)); - uninit(priv); - return 0; - } - -// if (!(priv->capability.capabilities & V4L2_CAP_AUDIO) && !priv->tv_param->force_audio) priv->tv_param->noaudio = 1; - - if (priv->capability.capabilities & V4L2_CAP_TUNER) { - struct v4l2_control control; - if (priv->tv_param->amode >= 0) { - MP_VERBOSE(priv, "setting audio mode\n"); - priv->tuner.audmode = amode2v4l(priv->tv_param->amode); - if (v4l2_ioctl(priv->video_fd, VIDIOC_S_TUNER, &priv->tuner) < 0) { - MP_ERR(priv, "ioctl set tuner failed: %s\n", mp_strerror(errno)); - return TVI_CONTROL_FALSE; - } - } - MP_INFO(priv, "current audio mode is :%s%s%s%s\n", - (priv->tuner.audmode == V4L2_TUNER_MODE_MONO) ? " MONO" : "", - (priv->tuner.audmode == V4L2_TUNER_MODE_STEREO) ? " STEREO" : "", - (priv->tuner.audmode == V4L2_TUNER_MODE_LANG1) ? " LANG1" : "", - (priv->tuner.audmode == V4L2_TUNER_MODE_LANG2) ? " LANG2" : ""); - - if (priv->tv_param->volume >= 0) { - control.id = V4L2_CID_AUDIO_VOLUME; - control.value = priv->tv_param->volume; - set_control(priv, &control, 0); - } - if (priv->tv_param->bass >= 0) { - control.id = V4L2_CID_AUDIO_BASS; - control.value = priv->tv_param->bass; - set_control(priv, &control, 0); - } - if (priv->tv_param->treble >= 0) { - control.id = V4L2_CID_AUDIO_TREBLE; - control.value = priv->tv_param->treble; - set_control(priv, &control, 0); - } - if (priv->tv_param->balance >= 0) { - control.id = V4L2_CID_AUDIO_BALANCE; - control.value = priv->tv_param->balance; - set_control(priv, &control, 0); - } - } - - return 1; -} - -static int get_capture_buffer_size(priv_t *priv) -{ - uint64_t bufsize; - int cnt; - - if (priv->tv_param->buffer_size >= 0) { - bufsize = priv->tv_param->buffer_size*1024*1024; - } else { - bufsize = 16*1024*1024; - } - - cnt = bufsize/priv->format.fmt.pix.sizeimage; - if (cnt < 2) cnt = 2; - - return cnt; -} - -/* that's the real start, we'got the format parameters (checked with control) */ -static int start(priv_t *priv) -{ - struct v4l2_requestbuffers request; - unsigned int i; - - /* setup audio parameters */ - - init_audio(priv); - if (priv->tv_param->audio && !priv->audio_initialized) return 0; - - priv->video_buffer_size_max = get_capture_buffer_size(priv); - - if (priv->tv_param->audio) { - setup_audio_buffer_sizes(priv); - priv->audio_skew_buffer = calloc(priv->aud_skew_cnt, sizeof(long long)); - if (!priv->audio_skew_buffer) { - MP_ERR(priv, "cannot allocate skew buffer: %s\n", mp_strerror(errno)); - return 0; - } - priv->audio_skew_delta_buffer = calloc(priv->aud_skew_cnt, sizeof(long long)); - if (!priv->audio_skew_delta_buffer) { - MP_ERR(priv, "cannot allocate skew buffer: %s\n", mp_strerror(errno)); - return 0; - } - - priv->audio_ringbuffer = calloc(priv->audio_in.blocksize, priv->audio_buffer_size); - if (!priv->audio_ringbuffer) { - MP_ERR(priv, "cannot allocate audio buffer: %s\n", mp_strerror(errno)); - return 0; - } - - priv->audio_secs_per_block = (double)priv->audio_in.blocksize/(priv->audio_in.samplerate - *priv->audio_in.channels - *priv->audio_in.bytes_per_sample); - priv->audio_usecs_per_block = 1e6*priv->audio_secs_per_block; - priv->audio_head = 0; - priv->audio_tail = 0; - priv->audio_cnt = 0; - priv->audio_drop = 0; - priv->audio_skew = 0; - priv->audio_skew_total = 0; - priv->audio_skew_delta_total = 0; - priv->audio_recv_blocks_total = 0; - priv->audio_sent_blocks_total = 0; - priv->audio_null_blocks_inserted = 0; - priv->audio_insert_null_samples = 0; - priv->dropped_frames_timeshift = 0; - priv->dropped_frames_compensated = 0; - - pthread_mutex_init(&priv->skew_mutex, NULL); - pthread_mutex_init(&priv->audio_mutex, NULL); - } - - /* setup video parameters */ - if (priv->tv_param->audio) { - if (priv->video_buffer_size_max < 3*getfps(priv)*priv->audio_secs_per_block) { - MP_ERR(priv, "Video buffer shorter than 3 times audio frame duration.\n" - "You will probably experience heavy framedrops.\n"); - } - } - - { - int bytesperline = priv->format.fmt.pix.width*pixfmt2depth(priv->format.fmt.pix.pixelformat)/8; - - MP_VERBOSE(priv, "Using a ring buffer for maximum %d frames, %d MB total size.\n", - priv->video_buffer_size_max, - priv->video_buffer_size_max*priv->format.fmt.pix.height*bytesperline/(1024*1024)); - } - - priv->video_ringbuffer = calloc(priv->video_buffer_size_max, sizeof(video_buffer_entry)); - if (!priv->video_ringbuffer) { - MP_ERR(priv, "cannot allocate video buffer: %s\n", mp_strerror(errno)); - return 0; - } - pthread_mutex_init(&priv->video_buffer_mutex, NULL); - - priv->video_head = 0; - priv->video_tail = 0; - priv->video_cnt = 0; - - /* request buffers */ - request.count = BUFFER_COUNT; - - request.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - request.memory = V4L2_MEMORY_MMAP; - if (v4l2_ioctl(priv->video_fd, VIDIOC_REQBUFS, &request) < 0) { - MP_ERR(priv, "ioctl request buffers failed: %s\n", mp_strerror(errno)); - return 0; - } - - /* query buffers */ - if (!(priv->map = calloc(request.count, sizeof(struct map)))) { - MP_ERR(priv, "malloc capture buffers failed: %s\n", mp_strerror(errno)); - return 0; - } - - /* map and queue buffers */ - for (i = 0; i < request.count; i++) { - priv->map[i].buf.index = i; - priv->map[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - priv->map[i].buf.memory = V4L2_MEMORY_MMAP; - if (v4l2_ioctl(priv->video_fd, VIDIOC_QUERYBUF, &(priv->map[i].buf)) < 0) { - MP_ERR(priv, "ioctl query buffer failed: %s\n", mp_strerror(errno)); - free(priv->map); - priv->map = NULL; - return 0; - } - priv->map[i].addr = v4l2_mmap (0, priv->map[i].buf.length, PROT_READ | - PROT_WRITE, MAP_SHARED, priv->video_fd, priv->map[i].buf.m.offset); - if (priv->map[i].addr == MAP_FAILED) { - MP_ERR(priv, "mmap capture buffer failed: %s\n", mp_strerror(errno)); - priv->map[i].len = 0; - return 0; - } - priv->map[i].len = priv->map[i].buf.length; -#ifdef HAVE_CLOCK_GETTIME - priv->clk_id = (priv->map[i].buf.flags & V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC) - ? CLOCK_MONOTONIC : CLOCK_REALTIME; -#else - if (priv->map[i].buf.flags & V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC) - MP_WARN(priv, "compiled without clock_gettime() that is needed to handle monotone video timestamps from the kernel. Expect desync.\n"); -#endif - /* count up to make sure this is correct every time */ - priv->mapcount++; - - if (v4l2_ioctl(priv->video_fd, VIDIOC_QBUF, &(priv->map[i].buf)) < 0) { - MP_ERR(priv, "ioctl queue buffer failed: %s\n", mp_strerror(errno)); - return 0; - } - } - - /* start audio thread */ - priv->shutdown = 0; - priv->audio_skew_measure_time = 0; - priv->first_frame = 0; - priv->audio_skew = 0; - priv->first = 1; - - set_mute(priv, 0); - - return 1; -} - -// copies a video frame -static inline void copy_frame(priv_t *priv, video_buffer_entry *dest, unsigned char *source,int len) -{ - dest->framesize=len; - if(priv->tv_param->automute>0){ - if (v4l2_ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) >= 0) { - if(priv->tv_param->automute<<8>priv->tuner.signal){ - fill_blank_frame(dest->data,dest->framesize,fcc_vl2mp(priv->format.fmt.pix.pixelformat)); - set_mute(priv,1); - return; - } - } - set_mute(priv,0); - } - memcpy(dest->data, source, len); -} - -// maximum skew change, in frames -#define MAX_SKEW_DELTA 0.6 -static void *video_grabber(void *data) -{ - priv_t *priv = (priv_t*)data; - long long skew, prev_skew, xskew, interval, prev_interval, delta; - int i; - int framesize = priv->format.fmt.pix.sizeimage; - fd_set rdset; - struct timeval timeout; - struct v4l2_buffer buf; - - xskew = 0; - skew = 0; - interval = 0; - prev_interval = 0; - prev_skew = 0; - - MP_VERBOSE(priv, "going to capture\n"); - if (v4l2_ioctl(priv->video_fd, VIDIOC_STREAMON, &(priv->format.type)) < 0) { - MP_ERR(priv, "ioctl streamon failed: %s\n", mp_strerror(errno)); - return 0; - } - priv->streamon = 1; - - if (priv->tv_param->audio) { - pthread_create(&priv->audio_grabber_thread, NULL, audio_grabber, priv); - } - - for (priv->frames = 0; !priv->shutdown;) - { - int ret; - - while (priv->video_cnt == priv->video_buffer_size_max) { - usleep(10000); - if (priv->shutdown) { - return NULL; - } - } - - FD_ZERO (&rdset); - FD_SET (priv->video_fd, &rdset); - - timeout.tv_sec = 1; - timeout.tv_usec = 0; - - i = select(priv->video_fd + 1, &rdset, NULL, NULL, &timeout); - if (i < 0) { - MP_ERR(priv, "select failed: %s\n", mp_strerror(errno)); - continue; - } - else if (i == 0) { - MP_ERR(priv, "select timeout\n"); - continue; - } - else if (!FD_ISSET(priv->video_fd, &rdset)) { - continue; - } - - memset(&buf,0,sizeof(buf)); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - ret = v4l2_ioctl(priv->video_fd, VIDIOC_DQBUF, &buf); - - if (ret < 0) { - /* - if there's no signal, the buffer might me dequeued - so we query all the buffers to see which one we should - put back to queue - - observed with saa7134 0.2.8 - don't know if is it a bug or (mis)feature - */ - MP_ERR(priv, "ioctl dequeue buffer failed: %s, idx = %d\n", - mp_strerror(errno), buf.index); - for (i = 0; i < priv->mapcount; i++) { - memset(&buf,0,sizeof(buf)); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - buf.index = i; - ret = v4l2_ioctl(priv->video_fd, VIDIOC_QUERYBUF, &buf); - if (ret < 0) { - MP_ERR(priv, "ioctl query buffer failed: %s, idx = %d\n", - mp_strerror(errno), buf.index); - return 0; - } - if ((buf.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE)) == V4L2_BUF_FLAG_MAPPED) { - if (v4l2_ioctl(priv->video_fd, VIDIOC_QBUF, &(priv->map[i].buf)) < 0) { - MP_ERR(priv, "ioctl queue buffer failed: %s\n", - mp_strerror(errno)); - return 0; - } - } - } - continue; - } - - /* store the timestamp of the very first frame as reference */ - if (!priv->frames++) { - if (priv->tv_param->audio) pthread_mutex_lock(&priv->skew_mutex); - priv->first_frame = buf.timestamp.tv_sec * 1000000LL + buf.timestamp.tv_usec; - if (priv->tv_param->audio) pthread_mutex_unlock(&priv->skew_mutex); - } - priv->curr_frame = buf.timestamp.tv_sec * 1000000LL + buf.timestamp.tv_usec; -// fprintf(stderr, "idx = %d, ts = %f\n", buf.index, (double)(priv->curr_frame) / 1e6); - - interval = priv->curr_frame - priv->first_frame; - delta = interval - prev_interval; - - // interpolate the skew in time - if (priv->tv_param->audio) pthread_mutex_lock(&priv->skew_mutex); - xskew = priv->audio_skew + (interval - priv->audio_skew_measure_time)*priv->audio_skew_factor; - if (priv->tv_param->audio) pthread_mutex_unlock(&priv->skew_mutex); - // correct extreme skew changes to avoid (especially) moving backwards in time - if (xskew - prev_skew > delta*MAX_SKEW_DELTA) { - skew = prev_skew + delta*MAX_SKEW_DELTA; - } else if (xskew - prev_skew < -delta*MAX_SKEW_DELTA) { - skew = prev_skew - delta*MAX_SKEW_DELTA; - } else { - skew = xskew; - } - - MP_TRACE(priv, "\nfps = %f, interval = %f, a_skew = %f, corr_skew = %f\n", - delta ? (double)1e6/delta : -1, - (double)1e-6*interval, (double)1e-6*xskew, (double)1e-6*skew); - MP_TRACE(priv, "vcnt = %d, acnt = %d\n", priv->video_cnt, priv->audio_cnt); - - prev_skew = skew; - prev_interval = interval; - - /* allocate a new buffer, if needed */ - pthread_mutex_lock(&priv->video_buffer_mutex); - if (priv->video_buffer_size_current < priv->video_buffer_size_max) { - if (priv->video_cnt == priv->video_buffer_size_current) { - unsigned char *newbuf = malloc(framesize); - if (newbuf) { - memmove(priv->video_ringbuffer+priv->video_tail+1, priv->video_ringbuffer+priv->video_tail, - (priv->video_buffer_size_current-priv->video_tail)*sizeof(video_buffer_entry)); - priv->video_ringbuffer[priv->video_tail].data = newbuf; - if ((priv->video_head >= priv->video_tail) && (priv->video_cnt > 0)) priv->video_head++; - priv->video_buffer_size_current++; - } - } - } - pthread_mutex_unlock(&priv->video_buffer_mutex); - - if (priv->video_cnt == priv->video_buffer_size_current) { - MP_ERR(priv, "\nvideo buffer full - dropping frame\n"); - if (!priv->immediate_mode || priv->audio_insert_null_samples) { - pthread_mutex_lock(&priv->audio_mutex); - priv->dropped_frames_timeshift += delta; - pthread_mutex_unlock(&priv->audio_mutex); - } - } else { - if (priv->immediate_mode) { - priv->video_ringbuffer[priv->video_tail].timestamp = interval - skew; - } else { - // compensate for audio skew - // negative skew => there are more audio samples, increase interval - // positive skew => less samples, shorten the interval - priv->video_ringbuffer[priv->video_tail].timestamp = interval - skew; - if (priv->audio_insert_null_samples && priv->video_ringbuffer[priv->video_tail].timestamp > 0) { - pthread_mutex_lock(&priv->audio_mutex); - priv->video_ringbuffer[priv->video_tail].timestamp += - (priv->audio_null_blocks_inserted - - priv->dropped_frames_timeshift/priv->audio_usecs_per_block) - *priv->audio_usecs_per_block; - pthread_mutex_unlock(&priv->audio_mutex); - } - } - copy_frame(priv, priv->video_ringbuffer+priv->video_tail, priv->map[buf.index].addr,buf.bytesused); - priv->video_tail = (priv->video_tail+1)%priv->video_buffer_size_current; - priv->video_cnt++; - } - if (v4l2_ioctl(priv->video_fd, VIDIOC_QBUF, &buf) < 0) { - MP_ERR(priv, "ioctl queue buffer failed: %s\n", mp_strerror(errno)); - return 0; - } - } - return NULL; -} - -#define MAX_LOOP 500 -static double grab_video_frame(priv_t *priv, char *buffer, int len) -{ - int loop_cnt = 0; - - if (priv->first) { - pthread_create(&priv->video_grabber_thread, NULL, video_grabber, priv); - priv->first = 0; - } - - while (priv->video_cnt == 0) { - usleep(1000); - if (loop_cnt++ > MAX_LOOP) return 0; - } - - pthread_mutex_lock(&priv->video_buffer_mutex); - long long interval = priv->video_ringbuffer[priv->video_head].timestamp; - memcpy(buffer, priv->video_ringbuffer[priv->video_head].data, len); - priv->video_cnt--; - priv->video_head = (priv->video_head+1)%priv->video_buffer_size_current; - pthread_mutex_unlock(&priv->video_buffer_mutex); - - return interval == -1 ? MP_NOPTS_VALUE : interval*1e-6; -} - -static int get_video_framesize(priv_t *priv) -{ - /* - this routine will be called before grab_video_frame - thus let's return topmost frame's size - */ - if (priv->video_cnt) - return priv->video_ringbuffer[priv->video_head].framesize; - /* - no video frames yet available. i don't know what to do in this case, - thus let's return some fallback result (for compressed format this will be - maximum allowed frame size. - */ - return priv->format.fmt.pix.sizeimage; -} - -static void *audio_grabber(void *data) -{ - priv_t *priv = (priv_t*)data; - int i, audio_skew_ptr = 0; - long long current_time, prev_skew = 0, prev_skew_uncorr = 0; - long long start_time_avg, curr_timestamp; - - start_time_avg = priv->audio_start_time = get_curr_timestamp(priv->clk_id); - audio_in_start_capture(&priv->audio_in); - for (i = 0; i < priv->aud_skew_cnt; i++) - priv->audio_skew_buffer[i] = 0; - for (i = 0; i < priv->aud_skew_cnt; i++) - priv->audio_skew_delta_buffer[i] = 0; - - for (; !priv->shutdown;) - { - if (audio_in_read_chunk(&priv->audio_in, priv->audio_ringbuffer+priv->audio_tail*priv->audio_in.blocksize) < 0) - continue; - pthread_mutex_lock(&priv->skew_mutex); - if (priv->first_frame == 0) { - // there is no first frame yet (unlikely to happen) - start_time_avg = priv->audio_start_time = get_curr_timestamp(priv->clk_id); -// fprintf(stderr, "warning - first frame not yet available!\n"); - pthread_mutex_unlock(&priv->skew_mutex); - continue; - } - pthread_mutex_unlock(&priv->skew_mutex); - - priv->audio_recv_blocks_total++; - curr_timestamp = get_curr_timestamp(priv->clk_id); - current_time = curr_timestamp - priv->audio_start_time; - - if (priv->audio_recv_blocks_total < priv->aud_skew_cnt*2) { - start_time_avg += curr_timestamp - priv->audio_usecs_per_block*priv->audio_recv_blocks_total; - priv->audio_start_time = start_time_avg/(priv->audio_recv_blocks_total+1); - } - -// fprintf(stderr, "spb = %f, bs = %d, skew = %f\n", priv->audio_secs_per_block, priv->audio_in.blocksize, -// (double)(current_time - 1e6*priv->audio_secs_per_block*priv->audio_recv_blocks_total)/1e6); - - // put the current skew into the ring buffer - priv->audio_skew_total -= priv->audio_skew_buffer[audio_skew_ptr]; - priv->audio_skew_buffer[audio_skew_ptr] = current_time - - priv->audio_usecs_per_block*priv->audio_recv_blocks_total; - priv->audio_skew_total += priv->audio_skew_buffer[audio_skew_ptr]; - - pthread_mutex_lock(&priv->skew_mutex); - - // skew calculation - - // compute the sliding average of the skews - if (priv->audio_recv_blocks_total > priv->aud_skew_cnt) { - priv->audio_skew = priv->audio_skew_total/priv->aud_skew_cnt; - } else { - priv->audio_skew = priv->audio_skew_total/priv->audio_recv_blocks_total; - } - - // put the current skew change (skew-prev_skew) into the ring buffer - priv->audio_skew_delta_total -= priv->audio_skew_delta_buffer[audio_skew_ptr]; - priv->audio_skew_delta_buffer[audio_skew_ptr] = priv->audio_skew - prev_skew_uncorr; - priv->audio_skew_delta_total += priv->audio_skew_delta_buffer[audio_skew_ptr]; - prev_skew_uncorr = priv->audio_skew; // remember the _uncorrected_ average value - - audio_skew_ptr = (audio_skew_ptr+1) % priv->aud_skew_cnt; // rotate the buffer pointer - - // sliding average approximates the value in the middle of the interval - // so interpolate the skew value further to the current time - priv->audio_skew += priv->audio_skew_delta_total/2; - - // now finally, priv->audio_skew contains fairly good approximation - // of the current value - - // current skew factor (assuming linearity) - // used for further interpolation in video_grabber - // probably overkill but seems to be necessary for - // stress testing by dropping half of the audio frames ;) - // especially when using ALSA with large block sizes - // where audio_skew remains a long while behind - if ((priv->audio_skew_measure_time != 0) && (current_time - priv->audio_skew_measure_time != 0)) { - priv->audio_skew_factor = (double)(priv->audio_skew-prev_skew)/(current_time - priv->audio_skew_measure_time); - } else { - priv->audio_skew_factor = 0.0; - } - - priv->audio_skew_measure_time = current_time; - prev_skew = priv->audio_skew; - priv->audio_skew += priv->audio_start_time - priv->first_frame; - pthread_mutex_unlock(&priv->skew_mutex); - -// fprintf(stderr, "audio_skew = %f, delta = %f\n", (double)priv->audio_skew/1e6, (double)priv->audio_skew_delta_total/1e6); - - pthread_mutex_lock(&priv->audio_mutex); - if ((priv->audio_tail+1) % priv->audio_buffer_size == priv->audio_head) { - MP_ERR(priv, "\ntoo bad - dropping audio frame !\n"); - priv->audio_drop++; - } else { - priv->audio_tail = (priv->audio_tail+1) % priv->audio_buffer_size; - priv->audio_cnt++; - } - pthread_mutex_unlock(&priv->audio_mutex); - } - return NULL; -} - -static double grab_audio_frame(priv_t *priv, char *buffer, int len) -{ - MP_DBG(priv, "grab_audio_frame(priv=%p, buffer=%p, len=%d)\n", - priv, buffer, len); - - // hack: if grab_audio_frame is called first, it means we are used by mplayer - // => switch to the mode which outputs audio immediately, even if - // it should be silence - if (priv->first) priv->audio_insert_null_samples = 1; - - pthread_mutex_lock(&priv->audio_mutex); - while (priv->audio_insert_null_samples - && priv->dropped_frames_timeshift - priv->dropped_frames_compensated >= priv->audio_usecs_per_block) { - // some frames were dropped - drop the corresponding number of audio blocks - if (priv->audio_drop) { - priv->audio_drop--; - } else { - if (priv->audio_head == priv->audio_tail) break; - priv->audio_head = (priv->audio_head+1) % priv->audio_buffer_size; - } - priv->dropped_frames_compensated += priv->audio_usecs_per_block; - } - - // compensate for dropped audio frames - if (priv->audio_drop && (priv->audio_head == priv->audio_tail)) { - priv->audio_drop--; - memset(buffer, 0, len); - goto out; - } - - if (priv->audio_insert_null_samples && (priv->audio_head == priv->audio_tail)) { - // return silence to avoid desync and stuttering - memset(buffer, 0, len); - priv->audio_null_blocks_inserted++; - goto out; - } - - pthread_mutex_unlock(&priv->audio_mutex); - while (priv->audio_head == priv->audio_tail) { - // this is mencoder => just wait until some audio is available - usleep(10000); - } - pthread_mutex_lock(&priv->audio_mutex); - memcpy(buffer, priv->audio_ringbuffer+priv->audio_head*priv->audio_in.blocksize, len); - priv->audio_head = (priv->audio_head+1) % priv->audio_buffer_size; - priv->audio_cnt--; -out: - pthread_mutex_unlock(&priv->audio_mutex); - priv->audio_sent_blocks_total++; - return (double)priv->audio_sent_blocks_total*priv->audio_secs_per_block; -} - -static int get_audio_framesize(priv_t *priv) -{ - return priv->audio_in.blocksize; -} diff --git a/wscript b/wscript index c808f9b8ce..d1e330280f 100644 --- a/wscript +++ b/wscript @@ -342,35 +342,6 @@ iconv support use --disable-iconv.", check_statement('zlib.h', 'inflate(0, Z_NO_FLUSH)')), 'req': True, 'fmsg': 'Unable to find development files for zlib.' - }, { - 'name': '--libbluray', - 'desc': 'Bluray support', - 'func': check_pkg_config('libbluray', '>= 0.3.0'), - #'default': 'disable', - }, { - 'name': '--dvdread', - 'desc': 'dvdread support', - 'deps': 'gpl', - 'func': check_pkg_config('dvdread', '>= 4.1.0'), - 'default': 'disable', - }, { - 'name': '--dvdnav', - 'desc': 'dvdnav support', - 'deps': 'gpl', - 'func': check_pkg_config('dvdnav', '>= 4.2.0', - 'dvdread', '>= 4.1.0'), - 'default': 'disable', - }, { - 'name': 'dvdread-common', - 'desc': 'DVD/IFO support', - 'deps': 'gpl && (dvdread || dvdnav)', - 'func': check_true, - }, { - 'name': '--cdda', - 'desc': 'cdda support (libcdio)', - 'deps': 'gpl', - 'func': check_pkg_config('libcdio_paranoia'), - 'default': 'disable', }, { 'name': '--uchardet', 'desc': 'uchardet support', @@ -846,47 +817,6 @@ hwaccel_features = [ } ] -radio_and_tv_features = [ - { - 'name': '--tv', - 'desc': 'TV interface', - 'deps': 'gpl', - 'func': check_true, - 'default': 'disable', - }, { - 'name': 'sys_videoio_h', - 'desc': 'videoio.h', - 'func': check_cc(header_name=['sys/time.h', 'sys/videoio.h']), - 'deps': 'tv', - }, { - 'name': 'videodev', - 'desc': 'videodev2.h', - 'func': check_cc(header_name=['sys/time.h', 'linux/videodev2.h']), - 'deps': 'tv && !sys_videoio_h', - }, { - 'name': '--tv-v4l2', - 'desc': 'Video4Linux2 TV interface', - 'deps': 'tv && (sys_videoio_h || videodev)', - 'func': check_true, - }, { - 'name': '--libv4l2', - 'desc': 'libv4l2 support', - 'func': check_pkg_config('libv4l2'), - 'deps': 'tv-v4l2', - }, { - 'name': '--audio-input', - 'desc': 'audio input support', - 'deps': 'tv-v4l2', - 'func': check_true - } , { - 'name': '--dvbin', - 'desc': 'DVB input module', - 'deps': 'gpl', - 'func': check_true, - 'default': 'disable', - } -] - standalone_features = [ { 'name': 'win32-executable', @@ -955,7 +885,6 @@ def options(opt): opt.parse_features('audio outputs', audio_output_features) opt.parse_features('video outputs', video_output_features) opt.parse_features('hwaccels', hwaccel_features) - opt.parse_features('tv features', radio_and_tv_features) opt.parse_features('standalone app', standalone_features) group = opt.get_option_group("optional features") @@ -1020,7 +949,6 @@ def configure(ctx): ctx.parse_dependencies(video_output_features) ctx.parse_dependencies(libav_dependencies) ctx.parse_dependencies(hwaccel_features) - ctx.parse_dependencies(radio_and_tv_features) if ctx.options.LUA_VER: ctx.options.enable_lua = True diff --git a/wscript_build.py b/wscript_build.py index 066ede1274..c9d5adce8c 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -274,7 +274,6 @@ def build(ctx): ( "demux/cue.c" ), ( "demux/demux.c" ), ( "demux/demux_cue.c" ), - ( "demux/demux_disc.c" ), ( "demux/demux_edl.c" ), ( "demux/demux_lavf.c" ), ( "demux/demux_libarchive.c", "libarchive" ), @@ -283,10 +282,8 @@ def build(ctx): ( "demux/demux_mkv_timeline.c" ), ( "demux/demux_null.c" ), ( "demux/demux_playlist.c" ), - ( "demux/demux_rar.c" ), ( "demux/demux_raw.c" ), ( "demux/demux_timeline.c" ), - ( "demux/demux_tv.c", "tv" ), ( "demux/ebml.c" ), ( "demux/packet.c" ), ( "demux/timeline.c" ), @@ -353,23 +350,10 @@ def build(ctx): ( "player/video.c" ), ## Streams - ( "stream/ai_alsa1x.c", "alsa && audio-input" ), - ( "stream/ai_oss.c", "oss-audio && audio-input" ), - ( "stream/ai_sndio.c", "sndio && audio-input" ), - ( "stream/audio_in.c", "audio-input" ), ( "stream/cookies.c" ), - ( "stream/dvb_tune.c", "dvbin" ), - ( "stream/frequencies.c", "tv" ), - ( "stream/rar.c" ), ( "stream/stream.c" ), ( "stream/stream_avdevice.c" ), - ( "stream/stream_bluray.c", "libbluray" ), ( "stream/stream_cb.c" ), - ( "stream/stream_cdda.c", "cdda" ), - ( "stream/stream_dvb.c", "dvbin" ), - ( "stream/stream_dvd.c", "dvdread-common" ), - ( "stream/stream_dvd_common.c", "dvdread-common" ), - ( "stream/stream_dvdnav.c", "dvdnav" ), ( "stream/stream_edl.c" ), ( "stream/stream_file.c" ), ( "stream/stream_lavf.c" ), @@ -377,12 +361,6 @@ def build(ctx): ( "stream/stream_memory.c" ), ( "stream/stream_mf.c" ), ( "stream/stream_null.c" ), - ( "stream/stream_rar.c" ), - ( "stream/stream_smb.c", "libsmbclient" ), - ( "stream/stream_tv.c", "tv" ), - ( "stream/tv.c", "tv" ), - ( "stream/tvi_dummy.c", "tv" ), - ( "stream/tvi_v4l2.c", "tv-v4l2"), ## Subtitles ( "sub/ass_mp.c", "libass"),