/*
* 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.
*/
#include <stddef.h>
#include <stdbool.h>
#include <inttypes.h>
#include <assert.h>
#include <libavutil/avutil.h>
#include "config.h"
#include "talloc.h"
#include "osdep/getch2.h"
#include "osdep/io.h"
#include "osdep/timer.h"
#include "mpvcore/mp_msg.h"
#include "mpvcore/path.h"
#include "mpvcore/m_config.h"
#include "mpvcore/parser-cfg.h"
#include "mpvcore/playlist.h"
#include "mpvcore/options.h"
#include "mpvcore/m_property.h"
#include "mpvcore/mp_common.h"
#include "mpvcore/resolve.h"
#include "mpvcore/encode.h"
#include "mpvcore/input/input.h"
#include "audio/mixer.h"
#include "audio/audio.h"
#include "audio/audio_buffer.h"
#include "audio/decode/dec_audio.h"
#include "audio/out/ao.h"
#include "demux/demux.h"
#include "stream/stream.h"
#include "sub/ass_mp.h"
#include "sub/dec_sub.h"
#include "sub/find_subfiles.h"
#include "video/decode/dec_video.h"
#include "video/out/vo.h"
#include "mp_core.h"
#include "command.h"
#if HAVE_DVBIN
#include "stream/dvbin.h"
#endif
void uninit_player(struct MPContext *mpctx, unsigned int mask)
{
struct MPOpts *opts = mpctx->opts;
mask &= mpctx->initialized_flags;
MP_DBG(mpctx, "\n*** uninit(0x%X)\n", mask);
if (mask & INITIALIZED_ACODEC) {
mpctx->initialized_flags &= ~INITIALIZED_ACODEC;
mixer_uninit_audio(mpctx->mixer);
audio_uninit(mpctx->d_audio);
mpctx->d_audio = NULL;
cleanup_demux_stream(mpctx, STREAM_AUDIO);
}
if (mask & INITIALIZED_SUB) {
mpctx->initialized_flags &= ~INITIALIZED_SUB;
if (mpctx->sh_sub)
sub_reset(mpctx->sh_sub->dec_sub);
cleanup_demux_stream(mpctx, STREAM_SUB);
mpctx->osd->dec_sub = NULL;
reset_subtitles(mpctx);
}
if (mask & INITIALIZED_LIBASS) {
mpctx->initialized_flags &= ~INITIALIZED_LIBASS;
#if HAVE_LIBASS
if (mpctx->osd->ass_renderer)
ass_renderer_done(mpctx->osd->ass_renderer);
mpctx->osd->ass_renderer = NULL;
ass_clear_fonts(mpctx->ass_library);
#endif
}
if (mask & INITIALIZED_VCODEC) {
mpctx->initialized_flags &= ~INITIALIZED_VCODEC;
if (mpctx->sh_video)
uninit_video(mpctx->sh_video);
cleanup_demux_stream(mpctx, STREAM_VIDEO);
mpctx->sync_audio_to_video = false;
}
if (mask & INITIALIZED_DEMUXER) {
mpctx->initialized_flags &= ~INITIALIZED_DEMUXER;
for (int i = 0; i < mpctx->num_tracks; i++) {
talloc_free(mpctx->tracks[i]);
}
mpctx->num_tracks = 0;
for (int t = 0; t < STREAM_TYPE_COUNT; t++)
mpctx->current_track[t] = NULL;
assert(!mpctx->sh_video && !mpctx->d_audio && !mpctx->sh_sub);
mpctx->master_demuxer = NULL;
for (int i = 0; i < mpctx->num_sources; i++) {
uninit_subs(mpctx->sources[i]);
struct demuxer *demuxer = mpctx->sources[i];
if (demuxer->stream != mpctx->stream)
free_stream(demuxer->stream);
free_demuxer(demuxer);
}
talloc_free(mpctx->sources);
mpctx->sources = NULL;
mpctx->demuxer = NULL;
mpctx->num_sources = 0;
talloc_free(mpctx->timeline);
mpctx->timeline = NULL;
mpctx->num_timeline_parts = 0;
talloc_free(mpctx->chapters);
mpctx->chapters = NULL;
mpctx->num_chapters = 0;
mpctx->video_offset = 0;
}
// kill the cache process:
if (mask & INITIALIZED_STREAM) {
mpctx->initialized_flags &= ~INITIALIZED_STREAM;
if (mpctx->stream)
free_stream(mpctx->stream);
mpctx->stream = NULL;
}
if (mask & INITIALIZED_VO) {
mpctx->initialized_flags &= ~INITIALIZED_VO;
vo_destroy(mpctx->video_out);
mpctx->video_out = NULL;
}
// Must be after libvo uninit, as few vo drivers (svgalib) have tty code.
if (mask & INITIALIZED_GETCH2) {
mpctx->initialized_flags &= ~INITIALIZED_GETCH2;
MP_DBG(mpctx, "\n[[[uninit getch2]]]\n");
// restore terminal:
getch2_disable();
}
if (mask & INITIALIZED_AO) {
struct ao *ao = mpctx->ao;
mpctx->initialized_flags &= ~INITIALIZED_AO;
if (ao) {
bool drain = false;
// Note: with gapless_audio, stop_play is not correctly set
if (opts->gapless_audio || mpctx->stop_play == AT_END_OF_FILE) {
drain = true;
struct mp_audio data;
mp_audio_buffer_peek(ao->buffer, &data);
int samples = ao->buffer_playable_samples;
assert(samples <= data.samples);
if (samples > 0) {
int played = ao_play(ao, data.planes, samples,
AOPLAY_FINAL_CHUNK);
if (played < samples)
MP_WARN(ao, "Audio output truncated at end.\n");
}
}
ao_uninit(ao, drain);
}
mpctx->ao = NULL;
}
if (mask & INITIALIZED_PLAYBACK)
mpctx->initialized_flags &= ~INITIALIZED_PLAYBACK;
}
static void print_stream(struct MPContext *mpctx, struct track *t)
{
struct sh_stream *s = t->stream;
const char *tname = "?";
const char *selopt = "?";
const char *langopt = "?";
const char *iid = NULL;
switch (t->type) {
case STREAM_VIDEO:
tname = "Video"; selopt = "vid"; langopt = NULL; iid = "VID";
break;
case STREAM_AUDIO:
tname = "Audio"; selopt = "aid"; langopt = "alang"; iid = "AID";
break;
case STREAM_SUB:
tname = "Subs"; selopt = "sid"; langopt = "slang"; iid = "SID";
break;
}
MP_INFO(mpctx, "[stream] %-5s %3s",
tname, mpctx->current_track[t->type] == t ? "(+)" : "");
MP_INFO(mpctx, " --%s=%d", selopt, t->user_tid);
if (t->lang && langopt)
MP_INFO(mpctx, " --%s=%s", langopt, t->lang);
if (t->default_track)
MP_INFO(mpctx, " (*)");
if (t->attached_picture)
MP_INFO(mpctx, " [P]");
if (t->title)
MP_INFO(mpctx, " '%s'", t->title);
const char *codec = s ? s->codec : NULL;
MP_INFO(mpctx, " (%s)", codec ? codec : "<unknown>");
if (t->is_external)
MP_INFO(mpctx, " (external)");
MP_INFO(mpctx, "\n");
// legacy compatibility
if (!iid)
return;
int id = t->user_tid;
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_%s_ID=%d\n", iid, id);
if (t->title)
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_%s_%d_NAME=%s\n", iid, id, t->title);
if (t->lang)
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_%s_%d_LANG=%s\n", iid, id, t->lang);
}
static void print_file_properties(struct MPContext *mpctx)
{
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_FILENAME=%s\n", mpctx->filename);
if (mpctx->sh_video) {
/* Assume FOURCC if all bytes >= 0x20 (' ') */
if (mpctx->sh_video->format >= 0x20202020)
mp_msg(MSGT_IDENTIFY, MSGL_INFO,
"ID_VIDEO_FORMAT=%.4s\n", (char *)&mpctx->sh_video->format);
else
mp_msg(MSGT_IDENTIFY, MSGL_INFO,
"ID_VIDEO_FORMAT=0x%08X\n", mpctx->sh_video->format);
mp_msg(MSGT_IDENTIFY, MSGL_INFO,
"ID_VIDEO_BITRATE=%d\n", mpctx->sh_video->i_bps * 8);
mp_msg(MSGT_IDENTIFY, MSGL_INFO,
"ID_VIDEO_WIDTH=%d\n", mpctx->sh_video->disp_w);
mp_msg(MSGT_IDENTIFY, MSGL_INFO,
"ID_VIDEO_HEIGHT=%d\n", mpctx->sh_video->disp_h);
mp_ms
|