diff mbox

[v8,09/12] media: Pipelines and media streams

Message ID 1296131437-29954-10-git-send-email-laurent.pinchart@ideasonboard.com (mailing list archive)
State RFC
Headers show

Commit Message

Laurent Pinchart Jan. 27, 2011, 12:30 p.m. UTC
None
diff mbox

Patch

diff --git a/Documentation/DocBook/v4l/media-ioc-enum-links.xml b/Documentation/DocBook/v4l/media-ioc-enum-links.xml
index daf0360..b204bfb 100644
--- a/Documentation/DocBook/v4l/media-ioc-enum-links.xml
+++ b/Documentation/DocBook/v4l/media-ioc-enum-links.xml
@@ -179,6 +179,11 @@ 
 	    <entry>The link enabled state can't be modified at runtime. An
 	    immutable link is always enabled.</entry>
 	  </row>
+	  <row>
+	    <entry><constant>MEDIA_LNK_FL_DYNAMIC</constant></entry>
+	    <entry>The link enabled state can be modified during streaming. This
+	    flag is set by drivers and is read-only for applications.</entry>
+	  </row>
 	</tbody>
       </tgroup>
     </table>
diff --git a/Documentation/DocBook/v4l/media-ioc-setup-link.xml b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
index 09ab3d2..2331e76 100644
--- a/Documentation/DocBook/v4l/media-ioc-setup-link.xml
+++ b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
@@ -60,6 +60,9 @@ 
     <para>Link configuration has no side effect on other links. If an enabled
     link at the sink pad prevents the link from being enabled, the driver
     returns with an &EBUSY;.</para>
+    <para>Only links marked with the <constant>DYNAMIC</constant> link flag can
+    be enabled/disabled while streaming media data. Attempting to enable or
+    disable a streaming non-dynamic link will return an &EBUSY;.</para>
     <para>If the specified link can't be found the driver returns with an
     &EINVAL;.</para>
   </refsect1>
diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
index 634845e..435d0c4 100644
--- a/Documentation/media-framework.txt
+++ b/Documentation/media-framework.txt
@@ -313,3 +313,41 @@  Link configuration must not have any side effect on other links. If an enabled
 link at a sink pad prevents another link at the same pad from being disabled,
 the link_setup operation must return -EBUSY and can't implicitly disable the
 first enabled link.
+
+
+Pipelines and media streams
+---------------------------
+
+When starting streaming, drivers must notify all entities in the pipeline to
+prevent link states from being modified during streaming by calling
+
+	media_entity_pipeline_start(struct media_entity *entity,
+				    struct media_pipeline *pipe);
+
+The function will mark all entities connected to the given entity through
+enabled links, either directly or indirectly, as streaming.
+
+The media_pipeline instance pointed to by the pipe argument will be stored in
+every entity in the pipeline. Drivers should embed the media_pipeline structure
+in higher-level pipeline structures and can then access the pipeline through
+the media_entity pipe field.
+
+Calls to media_entity_pipeline_start() can be nested. The pipeline pointer must
+be identical for all nested calls to the function.
+
+When stopping the stream, drivers must notify the entities with
+
+	media_entity_pipeline_stop(struct media_entity *entity);
+
+If multiple calls to media_entity_pipeline_start() have been made the same
+number of media_entity_pipeline_stop() calls are required to stop streaming. The
+media_entity pipe field is reset to NULL on the last nested stop call.
+
+Link configuration will fail with -EBUSY by default if either end of the link is
+a streaming entity. Links that can be modified while streaming must be marked
+with the MEDIA_LNK_FL_DYNAMIC flag.
+
+If other operations need to be disallowed on streaming entities (such as
+changing entities configuration parameters) drivers can explictly check the
+media_entity stream_count field to find out if an entity is streaming. This
+operation must be done with the media_device graph_mutex held.
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index d703ce8..e63e089 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -197,6 +197,75 @@  media_entity_graph_walk_next(struct media_entity_graph *graph)
 EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
 
 /* -----------------------------------------------------------------------------
+ * Pipeline management
+ */
+
+/**
+ * media_entity_pipeline_start - Mark a pipeline as streaming
+ * @entity: Starting entity
+ * @pipe: Media pipeline to be assigned to all entities in the pipeline.
+ *
+ * Mark all entities connected to a given entity through enabled links, either
+ * directly or indirectly, as streaming. The given pipeline object is assigned to
+ * every entity in the pipeline and stored in the media_entity pipe field.
+ *
+ * Calls to this function can be nested, in which case the same number of
+ * media_entity_pipeline_stop() calls will be required to stop streaming. The
+ * pipeline pointer must be identical for all nested calls to
+ * media_entity_pipeline_start().
+ */
+void media_entity_pipeline_start(struct media_entity *entity,
+				 struct media_pipeline *pipe)
+{
+	struct media_device *mdev = entity->parent;
+	struct media_entity_graph graph;
+
+	mutex_lock(&mdev->graph_mutex);
+
+	media_entity_graph_walk_start(&graph, entity);
+
+	while ((entity = media_entity_graph_walk_next(&graph))) {
+		entity->stream_count++;
+		WARN_ON(entity->pipe && entity->pipe != pipe);
+		entity->pipe = pipe;
+	}
+
+	mutex_unlock(&mdev->graph_mutex);
+}
+EXPORT_SYMBOL_GPL(media_entity_pipeline_start);
+
+/**
+ * media_entity_pipeline_stop - Mark a pipeline as not streaming
+ * @entity: Starting entity
+ *
+ * Mark all entities connected to a given entity through enabled links, either
+ * directly or indirectly, as not streaming. The media_entity pipe field is
+ * reset to NULL.
+ *
+ * If multiple calls to media_entity_pipeline_start() have been made, the same
+ * number of calls to this function are required to mark the pipeline as not
+ * streaming.
+ */
+void media_entity_pipeline_stop(struct media_entity *entity)
+{
+	struct media_device *mdev = entity->parent;
+	struct media_entity_graph graph;
+
+	mutex_lock(&mdev->graph_mutex);
+
+	media_entity_graph_walk_start(&graph, entity);
+
+	while ((entity = media_entity_graph_walk_next(&graph))) {
+		entity->stream_count--;
+		if (entity->stream_count == 0)
+			entity->pipe = NULL;
+	}
+
+	mutex_unlock(&mdev->graph_mutex);
+}
+EXPORT_SYMBOL_GPL(media_entity_pipeline_stop);
+
+/* -----------------------------------------------------------------------------
  * Module use count
  */
 
@@ -364,6 +433,10 @@  int __media_entity_setup_link(struct media_link *link, u32 flags)
 	source = link->source->entity;
 	sink = link->sink->entity;
 
+	if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
+	    (source->stream_count || sink->stream_count))
+		return -EBUSY;
+
 	mdev = source->parent;
 
 	if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) {
diff --git a/include/linux/media.h b/include/linux/media.h
index 2f67ed2..29039e8 100644
--- a/include/linux/media.h
+++ b/include/linux/media.h
@@ -106,6 +106,7 @@  struct media_pad_desc {
 
 #define MEDIA_LNK_FL_ENABLED		(1 << 0)
 #define MEDIA_LNK_FL_IMMUTABLE		(1 << 1)
+#define MEDIA_LNK_FL_DYNAMIC		(1 << 2)
 
 struct media_link_desc {
 	struct media_pad_desc source;
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 60fc7bd..450ba12 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -26,6 +26,9 @@ 
 #include <linux/list.h>
 #include <linux/media.h>
 
+struct media_pipeline {
+};
+
 struct media_link {
 	struct media_pad *source;	/* Source pad */
 	struct media_pad *sink;		/* Sink pad  */
@@ -67,8 +70,11 @@  struct media_entity {
 
 	const struct media_entity_operations *ops;	/* Entity operations */
 
+	int stream_count;		/* Stream count for the entity. */
 	int use_count;			/* Use count for the entity. */
 
+	struct media_pipeline *pipe;	/* Pipeline this entity belongs to. */
+
 	union {
 		/* Node specifications */
 		struct {
@@ -114,6 +120,7 @@  struct media_entity_graph {
 int media_entity_init(struct media_entity *entity, u16 num_pads,
 		struct media_pad *pads, u16 extra_links);
 void media_entity_cleanup(struct media_entity *entity);
+
 int media_entity_create_link(struct media_entity *source, u16 source_pad,
 		struct media_entity *sink, u16 sink_pad, u32 flags);
 int __media_entity_setup_link(struct media_link *link, u32 flags);
@@ -129,6 +136,9 @@  void media_entity_graph_walk_start(struct media_entity_graph *graph,
 		struct media_entity *entity);
 struct media_entity *
 media_entity_graph_walk_next(struct media_entity_graph *graph);
+void media_entity_pipeline_start(struct media_entity *entity,
+		struct media_pipeline *pipe);
+void media_entity_pipeline_stop(struct media_entity *entity);
 
 #define media_entity_call(entity, operation, args...)			\
 	(((entity)->ops && (entity)->ops->operation) ?			\