Permalink
Browse files

Broken state of refactoring media structure

  • Loading branch information...
1 parent abc722f commit c2a26e14ed042ac01f6f9eb34bb2766cb55d65cf @maxlapshin maxlapshin committed Nov 21, 2009
Showing with 113 additions and 101 deletions.
  1. +0 −16 include/ems.hrl
  2. +4 −10 src/formats/flv.erl
  3. +1 −1 src/formats/gen_format.erl
  4. +13 −18 src/formats/mp4.erl
  5. +2 −0 src/media/ems_play.erl
  6. +15 −8 src/media/file_media.erl
  7. +77 −47 src/media/file_play.erl
  8. +1 −1 src/rtmp_client.erl
View
@@ -223,22 +223,6 @@
}).
--record(video_player, {
- consumer,
- media_info,
- client_buffer = ?MIN_CLIENT_BUFFER,
- sent_video_config = false,
- sent_audio_config = false,
- prepush = 0,
- stream_id,
- buffer,
- timer_start,
- timer_ref,
- playing_from = 0,
- ts_prev = 0,
- pos = 0
-}).
-
-record(file_frame, {
View
@@ -38,7 +38,7 @@
-include("../../include/flv.hrl").
-include("../../include/media_info.hrl").
--export([init/1, read_frame/2, read_frame_list/3, header/1]).
+-export([init/1, read_frame/2, codec_config/2, read_frame_list/3, header/1]).
-behaviour(gen_format).
@@ -107,25 +107,19 @@ read_frame_list(#media_info{device = Device, frames = FrameTable} = MediaInfo, O
{error, Reason}
end.
-
+codec_config(_, _) -> undefined.
% Reads a tag from IoDev for position Pos.
% @param IoDev
% @param Pos
% @return a valid video_frame record type
-read_frame(#video_player{pos = undefined} = Player, #media_info{frames = FrameTable} = MediaInfo) ->
- read_frame(Player#video_player{pos = ets:first(FrameTable)}, MediaInfo);
-
-read_frame(#video_player{pos = '$end_of_table'}, _MediaInfo) ->
- {ok, done};
-
-read_frame(#video_player{pos = Key} = Player, #media_info{device = IoDev, frames = FrameTable}) ->
+read_frame(#media_info{device = IoDev, frames = FrameTable}, Key) ->
[Frame] = ets:lookup(FrameTable, Key),
#file_frame{offset = Offset, size = Size} = Frame,
case file:pread(IoDev, Offset, Size) of
{ok, Data} ->
VideoFrame = video_frame(Frame, Data),
- {ok, VideoFrame#video_frame{nextpos = ets:next(FrameTable, Key)}, Player};
+ {ok, VideoFrame#video_frame{nextpos = ets:next(FrameTable, Key)}};
eof ->
{ok, done};
{error, Reason} ->
@@ -42,5 +42,5 @@
%% @hidden
%% @end
%%-------------------------------------------------------------------------
-behaviour_info(callbacks) -> [{init, 1}, {read_frame, 2}];
+behaviour_info(callbacks) -> [{init, 1}, {read_frame, 2}, {codec_config, 2}];
behaviour_info(_Other) -> ?D({"Behaviour", _Other}), undefined.
View
@@ -38,35 +38,29 @@
-include("../../include/mp4.hrl").
-include("../../include/media_info.hrl").
--export([init/1, read_frame/2, metadata/1]).
+-export([init/1, read_frame/2, metadata/1, codec_config/2]).
-behaviour(gen_format).
% -export([read_header/1,read_frame/1,read_frame/2,to_tag/2,header/1, parse_meta/1, encodeTag/2]).
-
-
-read_frame(#video_player{pos = '$end_of_table'}, _MediaInfo) ->
- {ok, done};
-
-
-read_frame(#video_player{sent_video_config = false} = Player, #media_info{frames = FrameTable} = MediaInfo) ->
+codec_config(video, MediaInfo) ->
Config = decoder_config(video, MediaInfo),
- ?D({"Decoder config", Config}),
- {ok, #video_frame{
+ ?D({"Video config", Config}),
+ #video_frame{
type = ?FLV_TAG_TYPE_VIDEO,
decoder_config = true,
timestamp_abs = 0,
body = Config,
frame_type = ?FLV_VIDEO_FRAME_TYPE_KEYFRAME,
codec_id = ?FLV_VIDEO_CODEC_AVC,
raw_body = false,
- nextpos = ets:first(FrameTable)
- }, Player#video_player{sent_video_config = true}};
+ nextpos = 0
+ };
-read_frame(#video_player{sent_audio_config = false} = Player, #media_info{frames = FrameTable} = MediaInfo) ->
+codec_config(audio, MediaInfo) ->
Config = decoder_config(audio, MediaInfo),
?D({"Audio config", Config}),
- {ok, #video_frame{
+ #video_frame{
type = ?FLV_TAG_TYPE_AUDIO,
decoder_config = true,
timestamp_abs = 0,
@@ -76,16 +70,17 @@ read_frame(#video_player{sent_audio_config = false} = Player, #media_info{frames
sound_size = ?FLV_AUDIO_SIZE_16BIT,
sound_rate = ?FLV_AUDIO_RATE_44,
raw_body = false,
- nextpos = ets:first(FrameTable)
- }, Player#video_player{sent_audio_config = true}};
+ nextpos = 0
+ }.
+
-read_frame(#video_player{pos = Key} = Player, #media_info{frames = FrameTable} = MediaInfo) ->
+read_frame(#media_info{frames = FrameTable} = MediaInfo, Key) ->
[Frame] = ets:lookup(FrameTable, Key),
#file_frame{offset = Offset, size = Size} = Frame,
case read_data(MediaInfo, Offset, Size) of
{ok, Data, _} ->
VideoFrame = video_frame(Frame, Data),
- {ok, VideoFrame#video_frame{nextpos = ets:next(FrameTable, Key)}, Player};
+ {ok, VideoFrame#video_frame{nextpos = ets:next(FrameTable, Key)}};
eof ->
{ok, done};
{error, Reason} ->
View
@@ -54,6 +54,8 @@
send(undefined, _) -> {error, undefined_consumer};
+send(_, undefined) -> ok;
+
send(Consumer, #video_frame{type = Type, streamid=StreamId,timestamp_abs = TimeStamp,body=Body, raw_body = false} = Frame) when is_binary(Body) ->
Channel = #channel{id = channel_id(Type, StreamId),timestamp=TimeStamp,length=size(Body),type=Type,stream=StreamId},
gen_fsm:send_event(Consumer, {send, {Channel, ems_flv:encode(Frame)}});
View
@@ -9,20 +9,19 @@
-behaviour(gen_server).
%% External API
--export([start_link/2, first/1, read/2, file_name/1, seek/2, metadata/1]).
+-export([start_link/2, codec_config/2, read_frame/2, file_name/1, seek/2, metadata/1]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
start_link(Path, Type) ->
gen_server:start_link(?MODULE, [Path, Type], []).
-
-first(Server) ->
- gen_server:call(Server, {first}).
-read(Server, Player) ->
- gen_server:call(Server, {read, Player}).
+
+codec_config(MediaEntry, Type) -> gen_server:call(MediaEntry, {codec_config, Type}).
+
+read_frame(MediaEntry, Key) -> gen_server:call(MediaEntry, {read, Key}).
file_name(Server) ->
gen_server:call(Server, {file_name}).
@@ -68,9 +67,17 @@ handle_call({create_player, Options}, _From, #media_info{file_name = Name, clien
handle_call({first}, _From, #media_info{frames = FrameTable} = MediaInfo) ->
{reply, ets:first(FrameTable), MediaInfo};
+handle_call({codec_config, Type}, _From, #media_info{format = FileFormat} = MediaInfo) ->
+ {reply, FileFormat:codec_config(Type, MediaInfo), MediaInfo};
+
+handle_call({read, '$end_of_table'}, _From, MediaInfo) ->
+ {reply, {ok, done}, MediaInfo};
+
+handle_call({read, undefined}, _From, #media_info{frames = FrameTable, format = FileFormat} = MediaInfo) ->
+ {reply, FileFormat:read_frame(MediaInfo, ets:first(FrameTable)), MediaInfo};
-handle_call({read, State}, _From, #media_info{format = FileFormat} = MediaInfo) ->
- {reply, FileFormat:read_frame(State, MediaInfo), MediaInfo};
+handle_call({read, Key}, _From, #media_info{format = FileFormat} = MediaInfo) ->
+ {reply, FileFormat:read_frame(MediaInfo, Key), MediaInfo};
handle_call({file_name}, _From, #media_info{file_name = FileName} = MediaInfo) ->
{reply, FileName, MediaInfo};
View
@@ -44,6 +44,26 @@
-export([init/2, ready/1]).
+
+-record(file_player, {
+ consumer,
+ media_info,
+ client_buffer = ?MIN_CLIENT_BUFFER,
+ sent_video_config = false,
+ sent_audio_config = false,
+ prepush = 0,
+ stream_id,
+ buffer,
+ timer_start,
+ timer_ref,
+ playing_from = 0,
+ ts_prev = 0,
+ pos = 0,
+ paused = false
+}).
+
+
+
start(MediaEntry) -> start(MediaEntry, []).
start(MediaEntry, Options) ->
@@ -52,96 +72,106 @@ start(MediaEntry, Options) ->
init(MediaEntry, Options) ->
?D({"Starting file play for consumer", proplists:get_value(consumer, Options)}),
- ready(#video_player{consumer = proplists:get_value(consumer, Options),
+ ready(#file_player{consumer = proplists:get_value(consumer, Options),
stream_id = proplists:get_value(stream_id, Options, 1),
pos = undefined,
media_info = MediaEntry,
client_buffer = proplists:get_value(client_buffer, Options, 10000),
timer_start = erlang:now()}).
-ready(#video_player{media_info = MediaInfo,
+ready(#file_player{media_info = MediaInfo,
consumer = Consumer,
client_buffer = ClientBuffer,
- timer_ref = Timer,
- stream_id = StreamId} = State) ->
+ timer_ref = Timer} = State) ->
receive
- {client_buffer, ClientBuffer} -> ready(State#video_player{client_buffer = ClientBuffer});
+ {client_buffer, ClientBuffer} ->
+ ready(State#file_player{client_buffer = ClientBuffer});
start ->
- case media_entry:metadata(MediaInfo) of
+ case file_media:metadata(MediaInfo) of
undefined -> ok;
MetaData -> gen_fsm:send_event(Consumer, {metadata, ?AMF_COMMAND_ONMETADATA, MetaData, 1})
end,
self() ! play,
- NextState = State#video_player{prepush = ClientBuffer},
?D({"Player starting with pid", self(), MediaInfo}),
- ?MODULE:ready(NextState);
+ ?MODULE:ready(State#file_player{prepush = ClientBuffer, paused = false});
pause ->
?D("Player paused"),
timer:cancel(Timer),
- ?MODULE:ready(State);
+ ?MODULE:ready(State#file_player{paused = true});
resume ->
?D("Player resumed"),
self() ! play,
- ?MODULE:ready(State);
+ ?MODULE:ready(State#file_player{paused = false});
{seek, Timestamp} ->
- {Pos, NewTimestamp} = media_entry:seek(MediaInfo, Timestamp),
+ {Pos, NewTimestamp} = file_media:seek(MediaInfo, Timestamp),
timer:cancel(Timer),
% ?D({"Player seek to", Timestamp, Pos, NewTimestamp}),
- self() ! {play},
- ?MODULE:ready(State#video_player{pos = Pos, ts_prev = NewTimestamp, playing_from = NewTimestamp, prepush = ClientBuffer});
+ self() ! play,
+ ?MODULE:ready(State#file_player{pos = Pos, ts_prev = NewTimestamp, playing_from = NewTimestamp, prepush = ClientBuffer});
stop ->
?D("Player stopping"),
timer:cancel(Timer),
- ?MODULE:ready(State#video_player{ts_prev = 0, pos = media_entry:first(MediaInfo), playing_from = 0});
+ ?MODULE:ready(State#file_player{ts_prev = 0, pos = undefined, playing_from = 0});
exit ->
ok;
play ->
% {_, Sec1, MSec1} = erlang:now(),
- case media_entry:read(MediaInfo, State) of
- {ok, done} ->
- ?D("Video file finished"),
- gen_fsm:send_event(Consumer, {status, ?NS_PLAY_COMPLETE, 1}),
- ?MODULE:ready(State);
- {ok, #video_frame{type = _Type} = Frame, Player} ->
- TimeStamp = Frame#video_frame.timestamp_abs - State#video_player.ts_prev,
- ems_play:send(Consumer, Frame#video_frame{timestamp=TimeStamp, streamid = StreamId}),
- {Timeout, Player1} = timeout(Frame, Player),
- % ?D({"Frame", Frame#video_frame.timestamp_abs, Player#video_player.timer_start, TimeStamp, Timeout}),
- NextState = Player1#video_player{
- timer_ref = timer:send_after(Timeout, play),
- ts_prev = Frame#video_frame.timestamp_abs,
- pos = Frame#video_frame.nextpos},
- % {_, Sec2, MSec2} = erlang:now(),
- % _Delta = (Sec2*1000 + MSec2) - (Sec1*1000 + MSec1),
- % ?D({"Read frame", Delta}),
- ?MODULE:ready(NextState);
- {error, _Reason} ->
- ?D({"Ems player stopping", _Reason}),
- erlang:error(_Reason)
- end;
+ play(State);
- {tcp_closed, _Socket} ->
- error_logger:info_msg("~p Video player lost connection.\n", [self()]),
- ok;
- Else ->
- ?D({"Unknown message", Else}),
- ?MODULE:ready(State)
- end.
+ {tcp_closed, _Socket} ->
+ error_logger:info_msg("~p Video player lost connection.\n", [self()]),
+ ok;
+ Else ->
+ ?D({"Unknown message", Else}),
+ ?MODULE:ready(State)
+ end.
+
+play(#file_player{paused = true} = State) ->
+ ?MODULE:ready(State);
-% ready(file_name, _From, #video_player{media_info = MediaInfo} = State) ->
-% {reply, media_entry:file_name(MediaInfo), ready, State}.
+play(#file_player{sent_audio_config = false, media_info = MediaInfo, consumer = Consumer} = State) ->
+ ems_play:send(Consumer, file_media:codec_config(MediaInfo, audio)),
+ ?D({"Sent audio config"}),
+ play(State#file_player{sent_audio_config = true});
+play(#file_player{sent_video_config = false, media_info = MediaInfo, consumer = Consumer} = State) ->
+ ems_play:send(Consumer, file_media:codec_config(MediaInfo, video)),
+ ?D({"Sent video config"}),
+ play(State#file_player{sent_video_config = true});
+
+
+play(#file_player{media_info = MediaInfo, pos = Key} = Player) ->
+ send_frame(Player, file_media:read_frame(MediaInfo, Key)).
+
+send_frame(#file_player{consumer = Consumer} = Player, {ok, done}) ->
+ ?D("Video file finished"),
+ gen_fsm:send_event(Consumer, {status, ?NS_PLAY_COMPLETE, 1}),
+ ?MODULE:ready(Player);
+send_frame(#file_player{consumer = Consumer, stream_id = StreamId} = Player, {ok, #video_frame{nextpos = NextPos} = Frame}) ->
+ % ?D({"Frame", Key, Frame#video_frame.timestamp_abs, NextPos}),
+ TimeStamp = Frame#video_frame.timestamp_abs - Player#file_player.ts_prev,
+ ems_play:send(Consumer, Frame#video_frame{timestamp=TimeStamp, streamid = StreamId}),
+ {Timeout, Player1} = timeout(Frame, Player),
+ % ?D({"Frame", Consumer, Frame#video_frame.timestamp_abs, Player#file_player.timer_start, TimeStamp, Timeout}),
+ NextState = Player1#file_player{
+ timer_ref = timer:send_after(Timeout, play),
+ ts_prev = Frame#video_frame.timestamp_abs,
+ pos = NextPos},
+ % {_, Sec2, MSec2} = erlang:now(),
+ % _Delta = (Sec2*1000 + MSec2) - (Sec1*1000 + MSec1),
+ % ?D({"Read frame", Delta}),
+ ?MODULE:ready(NextState).
@@ -174,13 +204,13 @@ file_format(Name) ->
%% @end
%%-------------------------------------------------------------------------
-timeout(#video_frame{timestamp_abs = AbsTime}, #video_player{timer_start = TimerStart, client_buffer = ClientBuffer, playing_from = PlayingFrom, prepush = Prepush} = Player) ->
+timeout(#video_frame{timestamp_abs = AbsTime}, #file_player{timer_start = TimerStart, client_buffer = ClientBuffer, playing_from = PlayingFrom, prepush = Prepush} = Player) ->
SeekTime = AbsTime - PlayingFrom,
Timeout = SeekTime - ClientBuffer - trunc(timer:now_diff(now(), TimerStart) / 1000),
% ?D({"Timeout", Timeout, SeekTime, ClientBuffer, trunc(timer:now_diff(now(), TimerStart) / 1000)}),
if
(Prepush > SeekTime) ->
- {0, Player#video_player{prepush = Prepush - SeekTime}};
+ {0, Player#file_player{prepush = Prepush - SeekTime}};
(Timeout > 0) ->
{Timeout, Player};
true ->
View
@@ -284,7 +284,7 @@ handle_info(_Info, StateName, StateData) ->
%%-------------------------------------------------------------------------
terminate(_Reason, _StateName, #rtmp_client{socket=Socket, video_player = Player}) ->
rtmp_server:logout(),
- (catch gen_fsm:send_event(Player, {exit})),
+ Player ! exit,
(catch gen_tcp:close(Socket)),
ok.

0 comments on commit c2a26e1

Please sign in to comment.