PlayerEndpoint.cpp 播放的流程解析
补充一个将源项目各个子项目整合并编译以后的工程地址
https://github.com/ywcai/JKms.git
针对如何编译源代码并在vscode中跑起来,后续文章再进行介绍。
----------------------------------------------------------------------------------------------------------------------------------------------------------------
Playendpoint 收到java层的rpc指令,启动play方法
Play方直接调了start()方法,start方法来自继承的父类,UriEndpoint.cpp的start方法;
UriEndpoint.cpp的调用方法调用了
if (!kms_uri_endpoint_set_state (KMS_URI_ENDPOINT (getGstreamerElement() ),
KMS_URI_ENDPOINT_STATE_START, &error) ) {
GST_ERROR_OBJECT (getGstreamerElement(), "Error: %s", error->message);
g_error_free (error);
}
通过kms_uri_endpoint_set_state()方法,设置了基类中Eelement的状态。
gboolean
kms_uri_endpoint_set_state (KmsUriEndpoint * self, KmsUriEndpointState next,
GError ** err)
{
gboolean ret;
KMS_ELEMENT_LOCK (KMS_ELEMENT (self));
ret = kms_uri_endpoint_change_state (self, next, err);
KMS_ELEMENT_UNLOCK (KMS_ELEMENT (self));
return ret;
}
kms_uri_endpoint_set_state方法则是在 kmsuriendpoint.c代码中。在这个方法中,访问了C层的指针。并且返回一个设置是否成功的布尔值
kms_uri_endpoint_change_state (self, next, err);
具体设置C层对象(GOBJECT模拟的对象)状态的方法:
static gboolean
kms_uri_endpoint_change_state (KmsUriEndpoint * self, KmsUriEndpointState next,
GError ** err)
{
if (self->priv->state == next) {
g_set_error (err, KMS_URI_ENDPOINT_ERROR,
KMS_URI_ENDPOINT_INVALID_TRANSITION, "Already in state %s",
kms_uriendpoint_state_to_string (next));
return FALSE;
}
switch (next) {
case KMS_URI_ENDPOINT_STATE_STOP:
return CALL_IF_DEFINED (self, KMS_URI_ENDPOINT_GET_CLASS (self)->stopped,
err);
case KMS_URI_ENDPOINT_STATE_START:
return CALL_IF_DEFINED (self, KMS_URI_ENDPOINT_GET_CLASS (self)->started,
err);
case KMS_URI_ENDPOINT_STATE_PAUSE:
return CALL_IF_DEFINED (self, KMS_URI_ENDPOINT_GET_CLASS (self)->paused,
err);
}
g_set_error (err, KMS_URI_ENDPOINT_ERROR,
KMS_URI_ENDPOINT_UNEXPECTED_ERROR, "Invalid state %u", next);
return FALSE;
}
具体下面的代码调用了C 层的方法。
case KMS_URI_ENDPOINT_STATE_START:
return CALL_IF_DEFINED (self, KMS_URI_ENDPOINT_GET_CLASS (self)->started,
err);
CALL_IF_DEFINED (self, KMS_URI_ENDPOINT_GET_CLASS (self)->started,err) 这个宏可以在头文件中看到,实际上则是调用self的started
而当前的self实际上是kmsplayerelement.c创建的模拟对象。 这个具体创建的需要参考PlayerEndpoint.cpp的对象初始化方法,里面通过传递factoryname,在基类的构造方法中通过make方式创建了一个gobject的模拟对象.而PlayerEndpoint.cpp传递的是playerendpoint的模拟对象。再次回到上面的
CALL_IF_DEFINED (self, KMS_URI_ENDPOINT_GET_CLASS (self)->started, err) 这个方法。
而kmsuriendpoint.c中的stared是一个虚方法,他实际上是调用了playerendpoint.c中的started方法,我们继续查找playerendpoint.c文件中的started方法的实现,调用如下:
static gboolean
kms_player_endpoint_started (KmsUriEndpoint *obj, GError **error)
{
KmsPlayerEndpoint *self = KMS_PLAYER_ENDPOINT (obj);
GST_INFO_OBJECT (self, "PlayerEndpoint Pipeline started");
g_object_set (G_OBJECT (self->priv->uridecodebin), "uri",
KMS_URI_ENDPOINT (self)->uri, NULL);
gst_element_set_state (self->priv->pipeline, GST_STATE_PLAYING);
KMS_URI_ENDPOINT_GET_CLASS (self)->change_state (
KMS_URI_ENDPOINT (self), KMS_URI_ENDPOINT_STATE_START);
return TRUE;
}
在这里,设置了uridecodebin的 uri地址,并设置这个self->priv->pipeline上的所有bin为playing状态,pipeline是gstreame的基本结构,这个需要自行对gstreamer进行了解。 下面一句,同时把kmsuriendpoint的状态进行了同步处理,并且在里面将该状态通过信号系统向CPP层进行了回调发送。
KMS_URI_ENDPOINT_GET_CLASS(self)->change_state (KMS_URI_ENDPOINT (self),KMS_URI_ENDPOINT_STATE_START);
实现代码如下:
static void
kms_uri_endpoint_change_state_impl (KmsUriEndpoint * self,
KmsUriEndpointState state)
{
if (self->priv->state == state)
return;
GST_DEBUG_OBJECT (self, "State changed from %s to %s",
kms_uriendpoint_state_to_string (self->priv->state),
kms_uriendpoint_state_to_string (state));
self->priv->state = state;
g_signal_emit (G_OBJECT (self), kms_uri_endpoint_signals[STATE_CHANGED], 0,
state);
}
到此, palyerendpoint就开始了多媒体资源的播放。但开始播放后,又是如何进行解析的,下一篇文章进行分析。