Skip to content
Browse files

Adding document about media structure

  • Loading branch information...
1 parent ffa9069 commit 66c8d49a39be4121a8fbaf4def3160de50f4ff97 @maxlapshin maxlapshin committed Nov 21, 2009
Showing with 75 additions and 30 deletions.
  1. +61 −0 doc/media.edoc
  2. +8 −25 src/apps/apps_recording.erl
  3. +6 −5 src/media/media_provider.erl
View
61 doc/media.edoc
@@ -0,0 +1,61 @@
+@author Max Lapshin <max@maxidoors.ru> [http://maxidoors.ru]
+@copyright 2009 Max Lapshin
+@reference See <a href="http://github.com/maxlapshin/erlyvideo" target="_top">http://github.com/maxlapshin/erlyvideo</a> for more information
+@version
+@title Media structure in Erlyvideo
+@doc Erlyvideo has non-trivial structure of media delivery.
+
+Media provider.
+
+Central point is media_provider server. Basically it provides two functions:
+create media and play media. It's use is to cache opened streams and files.
+Opening new file is a rather expensive procedure, but its caching is very cheap.
+
+So, media_provider has a map of name -> instance of media entries.
+
+
+
+
+Media entry.
+
+All media entries are immutable across clients, i.e. they don't know what point
+of video user is watching now. Client adapters know this. Also, file entries
+are immutable in time: client adapter must track timer and send data to client.
+
+In any case, client code may just ask media_provider to subscribe him to media stream.
+
+Currently there are two kind of media entries: media_file and media_stream.
+
+File entry.
+
+Media_file detects whether it is mp4 or flv one.
+
+Stream entry.
+
+Media_stream may be a client of recorded stream from web camera or client of decoded MPEG TS.
+
+
+
+
+
+Media opening:
+
+1. media_provider makes lookup in table.
+
+2. if media is not found, reader is started, according to requested type. It is possible
+to open file or external stream, like MPEG TS.
+
+3. If media is found, it is asked to return a client adapter.
+File entry create file reader, that keeps track of user position in file and read frames at proper time.
+Stream entry create stream reader, that keeps track of user play/pause.
+
+Video stream creating:
+
+1. media_provider makes lookup in table
+
+2. if media is found, error is returned
+
+3. If media is not found, video stream is created with owner, set to creator.
+
+
+@end
View
33 src/apps/apps_recording.erl
@@ -42,27 +42,9 @@
-export(['WAIT_FOR_DATA'/2]).
-'WAIT_FOR_DATA'({publish, live, Name}, State) when is_list(Name) ->
- Recorder = media_provider:open(Name, live),
- media_entry:subscribe(Recorder, self()),
- {next_state, 'WAIT_FOR_DATA', State#rtmp_client{video_player = Recorder, video_state = publishing}};
-
-
-'WAIT_FOR_DATA'({publish, record, Name}, State) when is_list(Name) ->
- Recorder = media_provider:open(Name, record),
- {next_state, 'WAIT_FOR_DATA', State#rtmp_client{video_player = Recorder, video_state = publishing}};
-
-%% rsaccon: TODO get last timstamp of the exisiting FLV file, without that it won't playback propperly
-'WAIT_FOR_DATA'({publish, append, Name}, State) when is_list(Name) ->
- FileName = filename:join([file_play:file_dir(), Name]),
- case file:open(FileName, [write, append]) of
- {ok, IoDev} ->
- Recorder = #video_recorder{type=record_append, device = IoDev, file_name = FileName, ts_prev=0},
- {next_state, 'WAIT_FOR_DATA', State#rtmp_client{video_player = Recorder}, ?TIMEOUT};
- _ ->
- {next_state, 'WAIT_FOR_DATA', State, ?TIMEOUT}
- end;
-
+
+
+
'WAIT_FOR_DATA'({publish, #channel{} = Channel}, #rtmp_client{video_player = Recorder} = State) ->
media_entry:publish(Recorder, Channel),
{next_state, 'WAIT_FOR_DATA', State, ?TIMEOUT};
@@ -102,8 +84,8 @@
publish(#amf{args = [{null,null},{string,Name},{string,"record"}]} = _AMF, State) ->
?D({"Publish - Action - record",Name}),
- gen_fsm:send_event(self(), {publish, record, Name}),
- State;
+ Recorder = media_provider:create(Name, record),
+ State#rtmp_client{video_player = Recorder, video_state = publishing};
publish(#amf{args = [{null,null},{string,Name},{string,"append"}]} = _AMF, State) ->
@@ -114,8 +96,9 @@ publish(#amf{args = [{null,null},{string,Name},{string,"append"}]} = _AMF, State
publish(#amf{args = [{null,null},{string,Name},{string,"live"}]} = _AMF, State) ->
?D({"Publish - Action - live",Name}),
- gen_fsm:send_event(self(), {publish, live, Name}),
- State;
+ Recorder = media_provider:create(Name, live),
+ media_entry:subscribe(Recorder, self()),
+ State#rtmp_client{video_player = Recorder, video_state = publishing};
publish(#amf{args = [{null,null},{string,Name}]} = _AMF, State) ->
?D({"Publish - Action - live",Name}),
View
11 src/media/media_provider.erl
@@ -8,7 +8,7 @@
-behaviour(gen_server).
%% External API
--export([start_link/0, open/2, play/1, play/2]).
+-export([start_link/0, open/2, create/2, play/1, play/2]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
@@ -31,6 +31,10 @@ start_link() ->
% Opens media of type Type, named Name
open(Name, Type) ->
gen_server:call(?MODULE, {open, Name, Type}).
+
+create(Name, Type) ->
+ ?D({"Create", Name, Type}),
+ gen_server:call(?MODULE, {open, Name, Type}).
% Plays media with default options
@@ -42,16 +46,13 @@ play(Name) -> play(Name, []).
% stream_id: for RTMP, FLV stream id
% client_buffer: client buffer size
play(Name, OriginalOptions) ->
- Consumer = proplists:get_value(consumer, OriginalOptions, self()),
- Options = [{consumer, Consumer} | OriginalOptions],
-
case find(Name) of
undefined -> open_file(Name, Options);
Server -> connect_to_media(Server, Options)
end.
connect_to_media(Server, Options) ->
- Consumer = proplists:get_value(consumer, Options),
+ Consumer = proplists:get_value(consumer, OriginalOptions, self()),
case media_entry:is_stream(Server) of
true ->
media_entry:subscribe(Server, Consumer),

0 comments on commit 66c8d49

Please sign in to comment.
Something went wrong with that request. Please try again.