Exemple #1
0
MpvAudioOutput::MpvAudioOutput() : state_(AudioState::Stopped), seek_offset_(-1), volumeNeverSet_(true) {
    setlocale(LC_NUMERIC, "C");
    handle_ = mpv::qt::Handle::FromRawHandle(mpv_create());
    if (static_cast<mpv_handle *>(handle_) == nullptr)
        qDebug() << "Cannot mpv_create()";
    set_option("video", "no");
    set_option("softvol", "yes");
    set_option("ytdl", "yes");
    set_property("audio-client-name", "fubar");
    int r = mpv_initialize(handle_);
    if (r < 0) {
        qDebug() << "Failed to initialize mpv backend: " << mpv_error_string(r);
        //         raise Exception("");
    }
    thread_.reset(new std::thread([this] { event_loop(); }));
    observe_property("playback-time");
    observe_property("idle", MPV_FORMAT_FLAG);
    observe_property("pause", MPV_FORMAT_FLAG);
    observe_property("duration", MPV_FORMAT_DOUBLE);
    observe_property("metadata", MPV_FORMAT_NODE);

    r = mpv_request_log_messages(handle_, "warn");
    if (r < 0)
        qDebug() << "mpv_request_log_messages failed: " << mpv_error_string(r);
}
static inline void check_error(int status)
{
    if (status < 0) {
        printf("mpv API error: %s\n", mpv_error_string(status));
        exit(1);
    }
}
Exemple #3
0
void MpvHandler::HandleErrorCode(int error_code)
{
    if(error_code >= 0)
        return;
    QString error = mpv_error_string(error_code);
    if(error != QString())
        emit messageSignal(error+"\n");
}
Exemple #4
0
bool MpvAudioOutput::set_property(const QString &name, const QVariant &v) {
    int r = set_property_variant(handle_, name, v);
    if (r < 0) {
        qDebug() << "Failed to set property: " << name << " to " << v << ": "
                 << mpv_error_string(r);
        return false;
    }
    return true;
}
Exemple #5
0
void mpv_check_error(int status)
{
	void *array[10];
	size_t size;

	if(status < 0)
	{
		size = (size_t)backtrace(array, 10);

		g_critical("MPV API error: %s\n", mpv_error_string(status));

		backtrace_symbols_fd(array, (int)size, STDERR_FILENO);

		exit(EXIT_FAILURE);
	}
}
Exemple #6
0
gint gmpv_mpv_obj_command_string(GmpvMpvObj *mpv, const gchar *cmd)
{
	gint rc = MPV_ERROR_UNINITIALIZED;

	if(mpv->mpv_ctx)
	{
		rc = mpv_command_string(mpv->mpv_ctx, cmd);
	}

	if(rc < 0)
	{
		g_warning(	"Failed to run mpv command string \"%s\". "
				"Reason: %s.",
				cmd,
				mpv_error_string(rc) );
	}

	return rc;
}
Exemple #7
0
gint gmpv_mpv_obj_set_property_string(	GmpvMpvObj *mpv,
					const gchar *name,
					const char *data )
{
	gint rc = MPV_ERROR_UNINITIALIZED;

	if(mpv->mpv_ctx)
	{
		rc = mpv_set_property_string(mpv->mpv_ctx, name, data);
	}

	if(rc < 0)
	{
		g_info(	"Failed to set property \"%s\" as string. Reason: %s.",
			name,
			mpv_error_string(rc) );
	}

	return rc;
}
Exemple #8
0
gint gmpv_mpv_obj_set_property_flag(	GmpvMpvObj *mpv,
					const gchar *name,
					gboolean value )
{
	gint rc = MPV_ERROR_UNINITIALIZED;

	if(mpv->mpv_ctx)
	{
		rc =	mpv_set_property
			(mpv->mpv_ctx, name, MPV_FORMAT_FLAG, &value);
	}

	if(rc < 0)
	{
		g_info(	"Failed to set property \"%s\" as flag. Reason: %s.",
			name,
			mpv_error_string(rc) );
	}

	return rc;
}
Exemple #9
0
gint gmpv_mpv_obj_command(GmpvMpvObj *mpv, const gchar **cmd)
{
	gint rc = MPV_ERROR_UNINITIALIZED;

	if(mpv->mpv_ctx)
	{
		rc = mpv_command(mpv->mpv_ctx, cmd);
	}

	if(rc < 0)
	{
		gchar *cmd_str = g_strjoinv(" ", (gchar **)cmd);

		g_warning(	"Failed to run mpv command \"%s\". Reason: %s.",
				cmd_str,
				mpv_error_string(rc) );

		g_free(cmd_str);
	}

	return rc;
}
Exemple #10
0
gint gmpv_mpv_obj_set_property(	GmpvMpvObj *mpv,
				const gchar *name,
				mpv_format format,
				void *data )
{
	gint rc = MPV_ERROR_UNINITIALIZED;

	if(mpv->mpv_ctx)
	{
		rc = mpv_set_property(mpv->mpv_ctx, name, format, data);
	}

	if(rc < 0)
	{
		g_info(	"Failed to set property \"%s\" using mpv format %d. "
			"Reason: %s.",
			name,
			format,
			mpv_error_string(rc) );
	}

	return rc;
}
Exemple #11
0
static gboolean mpv_event_handler(gpointer data)
{
	GmpvMpvObj *mpv = data;
	gboolean done = !mpv;

	while(!done)
	{
		mpv_event *event =	mpv->mpv_ctx?
					mpv_wait_event(mpv->mpv_ctx, 0):
					NULL;

		if(!event)
		{
			done = TRUE;
		}
		else if(event->event_id == MPV_EVENT_PROPERTY_CHANGE)
		{
			mpv_event_property *prop = event->data;

			mpv_prop_change_handler(mpv, prop);

			g_signal_emit_by_name(	mpv,
						"mpv-prop-change",
						prop->name );
		}
		else if(event->event_id == MPV_EVENT_IDLE)
		{
			if(mpv->state.loaded)
			{
				mpv->state.loaded = FALSE;

				gmpv_mpv_obj_set_property_flag
					(mpv, "pause", TRUE);
				gmpv_playlist_reset(mpv->playlist);
			}

			mpv->state.init_load = FALSE;
		}
		else if(event->event_id == MPV_EVENT_FILE_LOADED)
		{
			mpv->state.loaded = TRUE;
			mpv->state.init_load = FALSE;

			mpv_obj_update_playlist(mpv);
		}
		else if(event->event_id == MPV_EVENT_END_FILE)
		{
			mpv_event_end_file *ef_event = event->data;

			mpv->state.init_load = FALSE;

			if(mpv->state.loaded)
			{
				mpv->state.new_file = FALSE;
			}

			if(ef_event->reason == MPV_END_FILE_REASON_ERROR)
			{
				const gchar *err;
				gchar *msg;

				err = mpv_error_string(ef_event->error);
				msg = g_strdup_printf
					(	_("Playback was terminated "
						"abnormally. Reason: %s."),
						err );

				gmpv_mpv_obj_set_property_flag
					(mpv, "pause", TRUE);
				g_signal_emit_by_name(mpv, "mpv-error", msg);

				g_free(msg);
			}
		}
		else if(event->event_id == MPV_EVENT_VIDEO_RECONFIG)
		{
			if(mpv->state.new_file)
			{
				gmpv_mpv_opt_handle_autofit(mpv);
			}
		}
		else if(event->event_id == MPV_EVENT_PLAYBACK_RESTART)
		{
			g_signal_emit_by_name(mpv, "mpv-playback-restart");
		}
		else if(event->event_id == MPV_EVENT_LOG_MESSAGE)
		{
			mpv_obj_log_handler(mpv, event->data);
		}
		else if(event->event_id == MPV_EVENT_SHUTDOWN
		|| event->event_id == MPV_EVENT_NONE)
		{
			done = TRUE;
		}

		if(event)
		{
			if(mpv->event_callback)
			{
				mpv->event_callback
					(event, mpv->event_callback_data);
			}

			if(mpv->mpv_ctx)
			{
				g_signal_emit_by_name
					(mpv, "mpv-event", event->event_id);
			}
			else
			{
				done = TRUE;
			}
		}
	}

	return FALSE;
}
Exemple #12
0
bool MpvHandler::event(QEvent *event)
{
    if(event->type() == QEvent::User)
    {
        while(mpv)
        {
            mpv_event *event = mpv_wait_event(mpv, 0);
            if(event == nullptr ||
               event->event_id == MPV_EVENT_NONE)
            {
                break;
            }
            if(event->error < 0)
            {
                ShowText(mpv_error_string(event->error));
                emit messageSignal(mpv_error_string(event->error));
            }
            switch (event->event_id)
            {
            case MPV_EVENT_PROPERTY_CHANGE:
            {
                mpv_event_property *prop = (mpv_event_property*)event->data;
                if(QString(prop->name) == "playback-time") // playback-time does the same thing as time-pos but works for streaming media
                {
                    if(prop->format == MPV_FORMAT_DOUBLE)
                    {
                        setTime((int)*(double*)prop->data);
                        lastTime = time;
                    }
                }
                else if(QString(prop->name) == "volume")
                {
                    if(prop->format == MPV_FORMAT_DOUBLE)
                        setVolume((int)*(double*)prop->data);
                }
                else if(QString(prop->name) == "sid")
                {
                    if(prop->format == MPV_FORMAT_INT64)
                        setSid(*(int*)prop->data);
                }
                else if(QString(prop->name) == "aid")
                {
                    if(prop->format == MPV_FORMAT_INT64)
                        setAid(*(int*)prop->data);
                }
                else if(QString(prop->name) == "sub-visibility")
                {
                    if(prop->format == MPV_FORMAT_FLAG)
                        setSubtitleVisibility((bool)*(unsigned*)prop->data);
                }
                else if(QString(prop->name) == "mute")
                {
                    if(prop->format == MPV_FORMAT_FLAG)
                        setMute((bool)*(unsigned*)prop->data);
                }
                break;
            }
            case MPV_EVENT_IDLE:
                fileInfo.length = 0;
                setTime(0);
                setPlayState(Mpv::Idle);
                break;
                // these two look like they're reversed but they aren't. the names are misleading.
            case MPV_EVENT_START_FILE:
                setPlayState(Mpv::Loaded);
                break;
            case MPV_EVENT_FILE_LOADED:
                setPlayState(Mpv::Started);
                LoadFileInfo();
                SetProperties();
            case MPV_EVENT_UNPAUSE:
                setPlayState(Mpv::Playing);
                break;
            case MPV_EVENT_PAUSE:
                setPlayState(Mpv::Paused);
                break;
            case MPV_EVENT_END_FILE:
                setPlayState(Mpv::Stopped);
                break;
            case MPV_EVENT_SHUTDOWN:
                QCoreApplication::quit();
                break;
            case MPV_EVENT_LOG_MESSAGE:
            {
                mpv_event_log_message *message = static_cast<mpv_event_log_message*>(event->data);
                if(message != nullptr)
                    emit messageSignal(message->text);
                break;
            }
            default: // unhandled events
                break;
            }
        }
        return true;
    }
    return QObject::event(event);
}
Exemple #13
0
void MpvAudioOutput::set_option(const QString &name, const QVariant &value) {
    auto r = mpv::qt::set_option_variant(handle_, name, value);
    if (r < 0)
        qDebug() << "Failed mpv_set_option " << name << ": " << mpv_error_string(r);
}
Exemple #14
0
void MpvAudioOutput::observe_property(const std::string &name, mpv_format format) {
    auto r = mpv_observe_property(handle_, 0, name.c_str(), format);
    if (r < 0)
        qDebug() << "Failed mpv_observe_property " << name.c_str() << ": " << mpv_error_string(r);
}
Exemple #15
0
void MpvAudioOutput::command(const QVariant &args) {
    int r = mpv::qt::command_variant2(handle_, args);
    if (r < 0)
        qDebug() << "Command failed: " << args << " " << mpv_error_string(r);
}
Exemple #16
0
void MpvAudioOutput::event_loop() {
    while (true) {
        auto event = mpv_wait_event(handle_, -1);
        //         qDebug() << "mpv event " << mpv_event_name(event->event_id);
        switch (event->event_id) {
        case MPV_EVENT_SHUTDOWN:
            return;
        case MPV_EVENT_QUEUE_OVERFLOW:
            qWarning() << "mpv queue overflow";
            break;
        case MPV_EVENT_START_FILE:
            setState(AudioState::Buffering);
            break;
        case MPV_EVENT_FILE_LOADED:
            setState(AudioState::Playing);
            emit currentSourceChanged();
            setVolume();
            if (seek_offset_ != -1) {
                seek(seek_offset_);
                seek_offset_ = -1;
            }
            break;
        case MPV_EVENT_END_FILE: {
            auto end_ev = reinterpret_cast<mpv_event_end_file *>(event->data);
            if (end_ev->reason == MPV_END_FILE_REASON_ERROR)
                qWarning() << "Ended file: " << mpv_error_string(end_ev->error);
            break;
        }
        case MPV_EVENT_LOG_MESSAGE: {
            auto log = reinterpret_cast<mpv_event_log_message *>(event->data);
            qDebug() << "mpv [" << log->prefix << "] " << log->text;
            break;
        }
        case MPV_EVENT_PROPERTY_CHANGE: {
            auto prop = reinterpret_cast<mpv_event_property *>(event->data);
            if (prop->format != MPV_FORMAT_NONE && prop->data) {
                if (std::string(prop->name) == "playback-time") {
                    std::string pos(*(reinterpret_cast<char **>(prop->data)));
                    emit tick(pos_to_qint64(pos));
                    if (volumeNeverSet_)
                        setVolume();
                } else if (std::string(prop->name) == "idle") {
                    int idle = *reinterpret_cast<int *>(prop->data);
                    if (idle) {
                        setState(AudioState::Stopped);
                        emit finished();
                    } else
                        setState(AudioState::Playing);
                } else if (std::string(prop->name) == "pause") {
                    int pause = *reinterpret_cast<int *>(prop->data);
                    if (pause)
                        setState(AudioState::Paused);
                    else if (state_ == AudioState::Paused)
                        setState(AudioState::Playing);
                } else if (std::string(prop->name) == "duration") {
                    double v = *reinterpret_cast<double *>(prop->data);
                    emit durationChanged(v);
                } else if (std::string(prop->name) == "metadata") {
                    emit metadataChanged(get_property("media-title").toString(),
                                         get_property("audio-format").toString(),
                                         get_property("audio-params/samplerate").toInt());
                }
            }
            break;
        }
        default:
            break;
        }
    }
}
static inline void
check_mpv_error(int status)
{
    if (status < 0)
        ERRORF("Mpv error %s\n", mpv_error_string(status));
}
void PlayerComponent::handleMpvEvent(mpv_event *event)
{
  switch (event->event_id)
  {
    case MPV_EVENT_START_FILE:
    {
      m_CurrentUrl = mpv::qt::get_property_variant(m_mpv, "path").toString();
      m_playbackStartSent = false;
      break;
    }
    case MPV_EVENT_FILE_LOADED:
    {
      emit playing(m_CurrentUrl);
      break;
    }
    case MPV_EVENT_END_FILE:
    {
      mpv_event_end_file *end_file = (mpv_event_end_file *)event->data;
      switch (end_file->reason)
      {
        case MPV_END_FILE_REASON_EOF:
          emit finished(m_CurrentUrl);
          break;
        case MPV_END_FILE_REASON_ERROR:
          emit error(end_file->error, mpv_error_string(end_file->error));
          break;
        default:
          emit stopped(m_CurrentUrl);
          break;
      }

      emit playbackEnded(m_CurrentUrl);
      m_CurrentUrl = "";

      m_restoreDisplayTimer.start(0);
      break;
    }
    case MPV_EVENT_IDLE:
    {
      emit playbackAllDone();
      break;
    }
    case MPV_EVENT_PLAYBACK_RESTART:
    {
      // it's also sent after seeks are completed
      if (!m_playbackStartSent)
        emit playbackStarting();
      m_playbackStartSent = true;
      break;
    }
    case MPV_EVENT_PROPERTY_CHANGE:
    {
      mpv_event_property *prop = (mpv_event_property *)event->data;
      if (strcmp(prop->name, "pause") == 0 && prop->format == MPV_FORMAT_FLAG)
      {
        int state = *(int *)prop->data;
        emit paused(state);
      }
      else if (strcmp(prop->name, "cache-buffering-state") == 0 && prop->format == MPV_FORMAT_INT64)
      {
        int64_t percentage = *(int64_t *)prop->data;
        emit buffering(percentage);
      }
      else if (strcmp(prop->name, "playback-time") == 0 && prop->format == MPV_FORMAT_DOUBLE)
      {
        double pos = *(double*)prop->data;
        if (fabs(pos - m_lastPositionUpdate) > 0.25)
        {
          quint64 ms = (quint64)(qMax(pos * 1000.0, 0.0));
          emit positionUpdate(ms);
          m_lastPositionUpdate = pos;
        }
      }
      else if (strcmp(prop->name, "vo-configured") == 0)
      {
        int state = prop->format == MPV_FORMAT_FLAG ? *(int *)prop->data : 0;
        emit windowVisible(state);
      }
      else if (strcmp(prop->name, "duration") == 0)
      {
        if (prop->format == MPV_FORMAT_DOUBLE)
          emit updateDuration(*(double *)prop->data * 1000.0);
      }
      else if (strcmp(prop->name, "audio-device-list") == 0)
      {
        updateAudioDeviceList();
      }
      break;
    }
    case MPV_EVENT_LOG_MESSAGE:
    {
      mpv_event_log_message *msg = (mpv_event_log_message *)event->data;
      // Strip the trailing '\n'
      size_t len = strlen(msg->text);
      if (len > 0 && msg->text[len - 1] == '\n')
        len -= 1;
      QString logline = QString::fromUtf8(msg->prefix) + ": " + QString::fromUtf8(msg->text, len);
      if (msg->log_level >= MPV_LOG_LEVEL_V)
        QLOG_DEBUG() << qPrintable(logline);
      else if (msg->log_level >= MPV_LOG_LEVEL_INFO)
        QLOG_INFO() << qPrintable(logline);
      else if (msg->log_level >= MPV_LOG_LEVEL_WARN)
        QLOG_WARN() << qPrintable(logline);
      else
        QLOG_ERROR() << qPrintable(logline);
      break;
    }
    case MPV_EVENT_CLIENT_MESSAGE:
    {
      mpv_event_client_message *msg = (mpv_event_client_message *)event->data;
      // This happens when the player is about to load the file, but no actual loading has taken part yet.
      // We use this to block loading until we explicitly tell it to continue.
      if (msg->num_args >= 3 && !strcmp(msg->args[0], "hook_run") && !strcmp(msg->args[1], "1"))
      {
        QString resume_id = QString::fromUtf8(msg->args[2]);
        // Calling this lambda will instruct mpv to continue loading the file.
        auto resume = [=] {
          QLOG_INFO() << "resuming loading";
          mpv::qt::command_variant(m_mpv, QStringList() << "hook-ack" << resume_id);
        };
        if (switchDisplayFrameRate())
        {
          // Now wait for some time for mode change - this is needed because mode changing can take some
          // time, during which the screen is black, and initializing hardware decoding could fail due
          // to various strange OS-related reasons.
          // (Better hope the user doesn't try to exit Konvergo during mode change.)
          int pause = SettingsComponent::Get().value(SETTINGS_SECTION_VIDEO, "refreshrate.delay").toInt() * 1000;
          QLOG_INFO() << "waiting" << pause << "msec after rate switch before loading";
          QTimer::singleShot(pause, resume);
        }
        else
        {
          resume();
        }
        break;
      }
    }
    default:; /* ignore */
  }
}
Exemple #19
0
static inline void
check_mpv_error(int status)
{
    if (status < 0)
        g_error("{GtPlayerMpv} Mpv error %s\n", mpv_error_string(status));
}