changeset 2345:182effc4b0ee

for MultimediaPlayer
author Ritor1
date Mon, 07 Apr 2014 19:15:13 +0600
parents d6887ee81068
children 37bb43874e59
files Game.cpp MMT.cpp MediaPlayer.cpp MediaPlayer.h UI/UIHouses.cpp VideoPlayer.cpp VideoPlayer.h
diffstat 7 files changed, 427 insertions(+), 94 deletions(-) [+]
line wrap: on
line diff
--- a/Game.cpp	Wed Apr 02 23:21:34 2014 +0200
+++ b/Game.cpp	Mon Apr 07 19:15:13 2014 +0600
@@ -4486,7 +4486,7 @@
           pVideoPlayer->bStopBeforeSchedule = 1;
           viewparams->bRedrawGameUI = 1;
           viewparams->field_48 = 1;
-          if ( !GetCurrentMenuID() || GetCurrentMenuID() == MENU_CREATEPARTY || GetCurrentMenuID() == MENU_NAMEPANELESC )
+          if ( !GetCurrentMenuID() || GetCurrentMenuID() == MENU_MMT_MAIN_MENU || GetCurrentMenuID() == MENU_CREATEPARTY || GetCurrentMenuID() == MENU_NAMEPANELESC )
           {
             //if ( pCurrentScreen == SCREEN_VIDEO )
               //pVideoPlayer->FastForwardToFrame(pVideoPlayer->pResetflag);			  
--- a/MMT.cpp	Wed Apr 02 23:21:34 2014 +0200
+++ b/MMT.cpp	Mon Apr 07 19:15:13 2014 +0600
@@ -184,17 +184,9 @@
   pAudioPlayer->StopChannels(-1, -1);//остановить/подготовить канал
 
   if (!bNoSound )
-  {
-    Media::Player *p = new Media::Player;//создаётся плеер
-    Media::ITrack *track = p->LoadTrack(L"Sounds\\New_Sounds/Stronghold_Theme.mp3");
-    track->Play();
-  }
-  /*if (!bNoVideo )
-  {
-    Media::Player *p = new Media::Player;//создаётся плеер
-	Media::IMovie *track = p->LoadMovie(L"Anims\\New_Video/3DOLOGO.smk", 640, 480, 0);
-    track->Play();
-  }	 */
+    pVideoPlayer->PlayAudio(L"Sounds\\New_Sounds/Stronghold_Theme.mp3");//воспроизводим мп3
+  //if (!bNoVideo )
+    //pVideoPlayer->PlayMovie(L"Anims\\New_Video/3DOLOGO.smk");
 
   pMouse->RemoveHoldingItem();//избавить курсор от вещи
 
--- a/MediaPlayer.cpp	Wed Apr 02 23:21:34 2014 +0200
+++ b/MediaPlayer.cpp	Mon Apr 07 19:15:13 2014 +0600
@@ -119,7 +119,11 @@
 };
 
 
-
+bool end_current_file;
+bool loop_current_file;
+DWORD time_video_begin;
+int current_movie_width;
+int current_movie_height;
 
 OpenALSoundProvider *provider = nullptr;
 
@@ -175,6 +179,7 @@
     dec = nullptr;
     if (dec_ctx)
     {
+      // закрытие видео кодека
       avcodec_close(dec_ctx);
       dec_ctx = nullptr;
     }
@@ -213,14 +218,19 @@
 
 static bool av_open_stream(AVFormatContext *format_ctx, AVMediaType type, AVStreamWrapper *out_stream)
 {
+// номер видеопотока
   int stream_idx = av_find_best_stream(format_ctx, type, -1, -1, nullptr, 0);
   if (stream_idx >= 0)
   {
     auto stream = format_ctx->streams[stream_idx];
+//Информация о кодеке в потоке называется «контекстом кодека» (AVCodecContext).
+//Используя эту информацию, мы можем найти необходимый кодек (AVCodec) и открыть его.
     auto dec_ctx = stream->codec;
+    // ищем декодер
     auto dec = avcodec_find_decoder(dec_ctx->codec_id);
     if (dec)
     {
+      // открываем декодер
       if (avcodec_open2(dec_ctx, dec, nullptr) >= 0)
       {
         out_stream->type = type;
@@ -231,6 +241,7 @@
         return true;
       }
     }
+    fprintf(stderr, "ffmpeg: Unable to open codec\n");
   }
   return false;
 }
@@ -241,11 +252,11 @@
     return Error("Audio stream not found"), false;
   
   // we support only 2-channel audio for now
-  if (out_stream->dec_ctx->channels != 2)
-  {
-    out_stream->Release();
-    return Error("Unsupported number of channels: %u", out_stream->dec_ctx->channels), false;
-  }
+  //if (out_stream->dec_ctx->channels != 2)//закомментировал потому что при воспроизведении jvc.bik вылетает на этом месте
+  //{
+   // out_stream->Release();
+   // return Error("Unsupported number of channels: %u", out_stream->dec_ctx->channels), false;
+  //}
   
   out_stream->bytes_per_sample = av_num_bytes_per_sample(out_stream->dec_ctx->sample_fmt);
   out_stream->bytes_per_second = out_stream->dec_ctx->channels * out_stream->dec_ctx->sample_rate * out_stream->bytes_per_sample;
@@ -339,6 +350,7 @@
   volatile int decoded = false;
   do
   {
+//Декодирование аудио-пакета осуществляется функцией avcodec_decode_audio4
     if (avcodec_decode_audio4(dec_ctx, avframe, (int *)&decoded, avpacket) < 0)
     {
       log("Cannot decode audio frame\n");
@@ -462,14 +474,18 @@
 {
   out_audio_stream->Reset();
 
+//воспроизведение audio.
+//Данные из файла читаются пакетами (AVPacket), а для воспроизведения используется фрейм (AVFrame).
   AVFrame  *frame = avcodec_alloc_frame();
   AVPacket *packet = new AVPacket;
   av_init_packet(packet);
 
   int num_audio_frames = 0;
   int num_audio_samples = 0;
+  //чтение пакетов
   while (av_read_frame(format_ctx, packet) >= 0)
   {
+    //Принадлежит ли пакет к аудиопотоку
     if (packet->stream_index != audio_stream_idx)
     {
       //log("Suspicious stream id %u in %s", packet->stream_index, filenamea);
@@ -511,6 +527,7 @@
       audio.Release();
       if (format_ctx)
       {
+        // закрытия контекста файла
         av_close_input_file(format_ctx);
         format_ctx = nullptr;
       }
@@ -520,11 +537,22 @@
     {
       char filenamea[1024];
       sprintf(filenamea, "%S", filename);
-
+// Open audio file
+//откроем входной файл(Шаг 2)
+//Функция avformat_open_input читает файловый заголовок и сохраняет информацию о найденных форматах в структуре
+//AVFormatContext. Остальные аргументы могут быть установлены в NULL, в этом случае libavformat использует 
+//автоматическое определение параметров.
       if (avformat_open_input(&format_ctx, filenamea, nullptr, nullptr) >= 0)
       {
+// Retrieve stream information
+//Т.к. avformat_open_input читает только заголовок файла, то следующим шагом нужно получить информацию о потоках
+//в файле. Это делается функцией avformat_find_stream_info.
         if (avformat_find_stream_info(format_ctx, nullptr) >= 0)
         {
+// Dump information about file onto standard error
+//После этого format_context->streams содержит все существующие потоки файла. 
+//Их количество равно format_context->nb_streams.
+//Вывести подробную информацию о файле и обо всех потоках можно функцией av_dump_format.
           av_dump_format(format_ctx, 0, filenamea, 0);
 
           if (!av_open_audio_stream(format_ctx, &audio))
@@ -559,7 +587,10 @@
           }
         }
         Release();
+        fprintf(stderr, "ffmpeg: Unable to find stream info\n");
+        return false;
       }
+      fprintf(stderr, "ffmpeg: Unable to open input file\n");
       return false;
     }
 
@@ -574,6 +605,8 @@
     AVAudioStream    audio;
     int              audio_num_samples;
 
+    bool             stopped;
+
     OpenALSoundProvider::TrackBuffer *device_buffer;
 };
 
@@ -582,6 +615,18 @@
 class Movie: public Media::IMovie
 {
   public:
+	int              audio_stream_idx;
+	AVStream        *audio_stream;//содержат информацию о аудио потоке
+	AVCodec         *audio_stream_dec;
+	AVCodecContext  *audio_stream_dec_ctx;
+
+	int              video_stream_idx;
+	AVStream        *video_stream;//содержат информацию о видео потоке
+	AVCodec         *video_stream_dec;
+	AVCodecContext  *video_stream_dec_ctx;
+	bool Stopped() { return stopped; }
+	bool End_file() { return end_of_file; }
+
     inline Movie()
     {
       this->movie_filename[0] = 0;
@@ -597,6 +642,11 @@
       this->last_resampled_frame_num = -1;
       memset(last_resampled_frame_data, 0, sizeof(last_resampled_frame_data));
       memset(last_resampled_frame_linesize, 0, sizeof(last_resampled_frame_linesize));
+
+		decoding_packet = nullptr;
+		ioBuffer = nullptr;
+		format_ctx = nullptr;
+		avioContext = nullptr;
     }
 
 
@@ -611,6 +661,7 @@
       video.Release();
       if (format_ctx)
       {
+        // закрытия контекста файла
         av_close_input_file(format_ctx);
         format_ctx = nullptr;
       }
@@ -624,10 +675,22 @@
 
       width = dst_width;
       height = dst_height;
+// Open video file
+//откроем входной файл(Шаг 2)
+//Функция avformat_open_input читает файловый заголовок и сохраняет информацию о найденных форматах в структуре
+//AVFormatContext. Остальные аргументы могут быть установлены в NULL, в этом случае libavformat использует 
+//автоматическое определение параметров.
       if (avformat_open_input(&format_ctx, filenamea, nullptr, nullptr) >= 0)
       {
+// Retrieve stream information
+//Т.к. avformat_open_input читает только заголовок файла, то следующим шагом нужно получить информацию о потоках
+//в файле. Это делается функцией avformat_find_stream_info.(Шаг 3)
         if (avformat_find_stream_info(format_ctx, nullptr) >= 0)
         {
+// Dump information about file onto standard error
+//После этого format_context->streams содержит все существующие потоки файла. 
+//Их количество равно format_context->nb_streams.
+//Вывести подробную информацию о файле и обо всех потоках можно функцией av_dump_format.
           av_dump_format(format_ctx, 0, filenamea, 0);
 
           if (!av_open_audio_stream(format_ctx, &audio))
@@ -642,6 +705,17 @@
             return Release(), false;
           }
           
+		if (_stricmp("binkvideo", video.dec->name) )
+		{
+			current_movie_width = video.dec_ctx->width;
+			current_movie_height = video.dec_ctx->height;
+		}
+		else
+		{
+			current_movie_width = width;
+			current_movie_height = height;
+		} 
+
           decoding_packet = new AVPacket;
           av_init_packet(decoding_packet);
       
@@ -651,9 +725,95 @@
 
           return true;
         }
+        fprintf(stderr, "ffmpeg: Unable to find stream info\n");
+        return false;
       }
+      fprintf(stderr, "ffmpeg: Unable to open input file\n");
       return false;
     }
+	bool LoadFromLOD(HANDLE h, int readFunction(void*, uint8_t*, int), int64_t seekFunction(void*, int64_t, int), int width, int height)
+	{
+		if (!ioBuffer)
+			ioBuffer = (unsigned char *)av_malloc(16384 + FF_INPUT_BUFFER_PADDING_SIZE); // can get av_free()ed by libav
+		if (!avioContext)
+			avioContext = avio_alloc_context(ioBuffer, 16384, 0, h, readFunction, NULL, seekFunction);
+		if (!format_ctx)
+			format_ctx = avformat_alloc_context();
+		format_ctx->pb = avioContext;
+		return Load(L"dummyFilename", width, height, 0);
+	}
+
+	bool Load(const char *video_filename, int width, int height)
+	{
+		this->width = width;
+		this->height = height;
+// Open video file
+//откроем входной файл(Шаг 2)
+//Функция avformat_open_input читает файловый заголовок и сохраняет информацию о найденных форматах в структуре
+//AVFormatContext. Остальные аргументы могут быть установлены в NULL, в этом случае libavformat использует 
+//автоматическое определение параметров.
+		if (avformat_open_input(&format_ctx, video_filename, nullptr, nullptr) >= 0)
+		{
+// Retrieve stream information
+//Т.к. avformat_open_input читает только заголовок файла, то следующим шагом нужно получить информацию о потоках
+//в файле. Это делается функцией avformat_find_stream_info.(Шаг 3)
+			if (avformat_find_stream_info(format_ctx, nullptr) >= 0)
+			{
+// Dump information about file onto standard error
+//После этого format_context->streams содержит все существующие потоки файла. 
+//Их количество равно format_context->nb_streams.
+//Вывести подробную информацию о файле и обо всех потоках можно функцией av_dump_format.
+				av_dump_format(format_ctx, 0, video_filename, 0);
+				
+				video_stream_idx = OpenStream(AVMEDIA_TYPE_VIDEO, &video_stream, &video_stream_dec, &video_stream_dec_ctx);
+				if (video_stream_idx < 0)
+					return Release(), false;
+				if (_stricmp("binkvideo", video_stream_dec->name) )//Ritor1: include
+				{
+					this->width = video_stream_dec_ctx->width;
+					this->height = video_stream_dec_ctx->height;
+				}
+
+				audio_stream_idx = OpenStream(AVMEDIA_TYPE_AUDIO, &audio_stream, &audio_stream_dec, &audio_stream_dec_ctx);
+				if (audio_stream_idx < 0)
+					return Release(), false;
+
+				strcpy(movie_filename, video_filename);
+//Данные из файла читаются пакетами (AVPacket)
+				decoding_packet = new AVPacket;
+				av_init_packet(decoding_packet);
+				return true;
+			}
+			fprintf(stderr, "ffmpeg: Unable to find stream info\n");
+			return Release(), false;
+		}
+		fprintf(stderr, "ffmpeg: Unable to open input file\n");
+		return Release(), false;
+	}
+	int OpenStream(AVMediaType type, AVStream **out_stream, AVCodec **out_dec, AVCodecContext **out_dec_ctx)
+	{
+		int stream_idx = av_find_best_stream(format_ctx, type, -1, -1, nullptr, 0);
+		if (stream_idx < 0)
+			return stream_idx;
+
+		auto stream = format_ctx->streams[stream_idx];
+//Информация о кодеке в потоке называется «контекстом кодека» (AVCodecContext).
+//Используя эту информацию, мы можем найти необходимый кодек (AVCodec) и открыть его.
+		auto dec_ctx = stream->codec;
+		auto dec = avcodec_find_decoder(dec_ctx->codec_id);
+		if (dec)
+		{
+			if (avcodec_open2(dec_ctx, dec, nullptr) >= 0)
+			{
+				*out_stream = stream;
+				*out_dec = dec;
+				*out_dec_ctx = dec_ctx;
+				return stream_idx;
+			}
+		}
+		fprintf(stderr, "ffmpeg: Unable to open codec\n");
+		return -1;
+	}
 
     virtual void Play()
     {
@@ -663,8 +823,11 @@
     {
       playback_time += dt;//изменение времени
 
+//Данные из файла читаются пакетами (AVPacket), а для отображения используется фрейм (AVFrame).
+//(помните мы сохранили номер видео потока в переменной video_stream).
       AVPacket *avpacket = decoding_packet;
       AVFrame *avframe = decoding_frame;
+//декодтрование
       avcodec_get_frame_defaults(avframe);
 
       int desired_frame_number = floor(playback_time * video.dec_ctx->time_base.den / video.dec_ctx->time_base.num + 0.5);
@@ -675,65 +838,134 @@
       }
 
       volatile int decoded = false;
-      do
+      //чтение пакетов
+    // keep reading packets until we hit the end or find a video packet
+      while (av_read_frame(format_ctx, avpacket) >= 0)
       {
-        if (av_read_frame(format_ctx, avpacket) < 0) //воспроизведение завершено
+        /*if (av_read_frame(format_ctx, avpacket) < 0) //воспроизведение завершено
         {
+			if (loop_current_file)
+			{
+			  av_seek_frame(format_ctx, video.stream_idx, 0, AVSEEK_FLAG_ANY);
+			}
+			else
+			{
           // probably movie is finished
-          __debugbreak();
-        }
+          //__debugbreak();
+				end_of_file = true;
+				end_current_file = true;
+				return;// nullptr;
+			}
+        } */
 
+        // Is this a packet from the video stream?
         // audio packet - queue into playing
+        //Принадлежит ли пакет к аудиопотоку
         if (avpacket->stream_index == audio.stream_idx)
         {
           MemoryStream audio_data;
           if (DecodeAudioFrame(audio.dec_ctx, avpacket, avframe, &audio_data, &num_audio_samples))
             provider->Stream16(audio_data_in_device, num_audio_samples, audio_data.Ptr());
+		  continue;
         }
-        // video packet - decode & maybe show
+        // Decode video frame
+        //пакет к видеопотоку
         else if (avpacket->stream_index == video.stream_idx)
         {
-          do
+//Функция avcodec_decode_video2 осуществляет декодирование пакета в фрейм с использованием кодека,
+//который мы получили раньше (codec_context). Функция устанавливает положительное значение frame_finished в случае
+//если фрейм декодирован целиком (то есть один фрейм может занимать несколько пакетов и frame_finished будет 
+//установлен только при декодировании последнего пакета).
+          avcodec_decode_video2(video.dec_ctx, avframe, (int *)&decoded, avpacket);
+          if (decoded)
           {
-            if (avcodec_decode_video2(video.dec_ctx, avframe, (int *)&decoded, avpacket) < 0)
-              __debugbreak();
-          } while (!decoded);
-        }
-
-      } while (avpacket->stream_index != video.stream_idx ||
-               avpacket->pts != desired_frame_number);
-
-      if (decoded)
-      {
-        if (last_resampled_frame_data[0])
-          av_freep(&last_resampled_frame_data[0]);
+            if (last_resampled_frame_data[0])
+              av_freep(&last_resampled_frame_data[0]);
 
-        AVPixelFormat  rescaled_format = AV_PIX_FMT_RGB32;
-        uint8_t       *rescaled_data[4] = {nullptr, nullptr, nullptr, nullptr};
-        int            rescaled_linesize[4] = {0, 0, 0, 0};
-        if (av_image_alloc(rescaled_data, rescaled_linesize, width, height, rescaled_format, 1) >= 0)
-        {
-          SwsContext *converter = sws_getContext(avframe->width, avframe->height, (AVPixelFormat)avframe->format,
-                                                 width, height, rescaled_format,
+            AVPixelFormat  rescaled_format = AV_PIX_FMT_RGB32;
+            uint8_t       *rescaled_data[4] = {nullptr, nullptr, nullptr, nullptr};
+            int            rescaled_linesize[4] = {0, 0, 0, 0};
+            if (av_image_alloc(rescaled_data, rescaled_linesize, current_movie_width, current_movie_height, rescaled_format, 1) >= 0)
+            {
+              // создание контекста для преобразования
+              SwsContext *converter = sws_getContext(avframe->width, avframe->height, (AVPixelFormat)avframe->format,
+                                                 current_movie_width, current_movie_height, rescaled_format,
                                                  SWS_BICUBIC, nullptr, nullptr, nullptr);
-          sws_scale(converter, avframe->data, avframe->linesize, 0, avframe->height, rescaled_data, rescaled_linesize);
-          sws_freeContext(converter);
+              // преобразование кадра
+              sws_scale(converter, avframe->data, avframe->linesize, 0, avframe->height, rescaled_data, rescaled_linesize);
+              sws_freeContext(converter);
 
-          memcpy(dst_surface, rescaled_data[0], height * rescaled_linesize[0]);
+              memcpy(dst_surface, rescaled_data[0], current_movie_height * rescaled_linesize[0]);
 
-          last_resampled_frame_num = desired_frame_number;
-          memcpy(last_resampled_frame_data, rescaled_data, sizeof(rescaled_data));
-          memcpy(last_resampled_frame_linesize, rescaled_linesize, sizeof(rescaled_linesize));
+              last_resampled_frame_num = desired_frame_number;
+              memcpy(last_resampled_frame_data, rescaled_data, sizeof(rescaled_data));
+              memcpy(last_resampled_frame_linesize, rescaled_linesize, sizeof(rescaled_linesize));
+            }
+          }
+          else
+            memset(dst_surface, 0, current_movie_width * current_movie_height * 4);
         }
+        return;
+      }// while (avpacket->stream_index != video.stream_idx ||
+         //      avpacket->pts != desired_frame_number);
+      if (loop_current_file)
+      {
+        av_seek_frame(format_ctx, video.stream_idx, 0, AVSEEK_FLAG_ANY);
       }
       else
-        memset(dst_surface, 0, width * height * 4);
+      {
+        // probably movie is finished
+        //__debugbreak();
+        end_of_file = true;
+        end_current_file = true;
+        return;// nullptr;
+      }
     }
 
+	/*inline char *DoFrame()
+	{
+		if (!current_movie)
+			return nullptr;
+
+		while (true)
+		{
+			auto frame = current_movie->GetNextFrame();
+			if (!frame)
+				return nullptr;
+
+			if (frame->Type() == AVMEDIA_TYPE_AUDIO)
+			{
+				//continue;
+//				uint8_t *data;
+				if (frame->Decode() >= 0)
+				{
+					auto f = frame->GetAVFrame();
+					provider->PlaySample(f->channels, f->sample_rate, f->nb_samples, frame->GetData());
+					Sleep(20);
+					continue;
+				}
+			}
+			else if (frame->Type() == AVMEDIA_TYPE_VIDEO)
+			{
+				uint8_t *dst_data[4] = { 0 };
+				int      dst_linesize[4] = { 0 };
+				if (frame->Decode() >= 0)
+				{
+					auto image = new char[current_movie_width * current_movie_height * 4];
+					memcpy(image, frame->GetData(), current_movie_height * frame->GetDataPitch());
+
+					return image;
+				}
+			}
+			return nullptr;
+		}
+	}*/
+
   protected:
     char             movie_filename[256];
     int              width;
     int              height;
+    bool             stopped;
     AVFormatContext *format_ctx;
     double           playback_time;
     bool             end_of_file;
@@ -744,6 +976,8 @@
     AVAudioStream   audio;
     int             num_audio_frames;
     int             num_audio_samples;
+	unsigned char * ioBuffer;
+	AVIOContext *avioContext;
     OpenALSoundProvider::StreamingTrackBuffer *audio_data_in_device;
 
     AVVideoStream   video;
@@ -800,6 +1034,11 @@
   {
     av_log_set_callback(av_logger);
     avcodec_register_all();
+
+// Register all available file formats and codecs
+//инициализируем библиотеку ffmpeg(Шаг 1)
+//Во время инициализации регистрируются все имеющиеся в библиотеке форматы файлов и кодеков.
+//После этого они будут использоваться автоматически при открытии файлов этого формата и с этими кодеками.
     av_register_all();
 
     libavcodec_initialized = true;
@@ -814,4 +1053,27 @@
 
 Player::~Player()
 {
-}
\ No newline at end of file
+}
+	IMovie *Player::LoadMovieFromLOD(HANDLE h, int readFunction(void*, uint8_t*, int), int64_t seekFunction(void*, int64_t, int), int width, int height)
+	{
+		auto movie = new Movie;
+		if (movie)
+		{
+			if (movie->LoadFromLOD(h, readFunction, seekFunction, width, height))
+			{
+				/*if (_stricmp("binkvideo", movie->video_stream_dec->name) )
+				{
+					current_movie_width = movie->video_stream_dec_ctx->width;
+					current_movie_height = movie->video_stream_dec_ctx->height;
+				}
+				else
+				{
+					current_movie_width = width;
+					current_movie_height = height;
+				}  */
+				return movie;
+			}
+			delete movie;
+		}
+		return nullptr;
+	}
\ No newline at end of file
--- a/MediaPlayer.h	Wed Apr 02 23:21:34 2014 +0200
+++ b/MediaPlayer.h	Mon Apr 07 19:15:13 2014 +0600
@@ -11,6 +11,8 @@
   {
     public: virtual void Play() = 0;
             virtual void GetNextFrame(double dt, void *target_surface) = 0;
+            bool Stopped();
+            bool End_file();
   };
 
   class Player
@@ -19,8 +21,17 @@
                Player();
       virtual ~Player();
 
-
       ITrack *LoadTrack(const wchar_t *name);
       IMovie *LoadMovie(const wchar_t *name, int width, int height, int cache_ms);
+      IMovie *LoadMovieFromLOD(HANDLE h, int readFunction(void*, uint8_t*, int), int64_t seekFunction(void*, int64_t, int), int width, int height);
+      bool LoadFromLOD(HANDLE h, int readFunction(void*, uint8_t*, int), int64_t seekFunction(void*, int64_t, int), int width, int height);
+	  char *DoFrame();
+
   };
-};
\ No newline at end of file
+};
+
+extern bool end_current_file;
+extern bool loop_current_file;
+extern DWORD time_video_begin;
+extern int current_movie_width;
+extern int current_movie_height;
--- a/UI/UIHouses.cpp	Wed Apr 02 23:21:34 2014 +0200
+++ b/UI/UIHouses.cpp	Mon Apr 07 19:15:13 2014 +0600
@@ -881,7 +881,7 @@
 		uTextureID_right_panel_loop = uTextureID_right_panel;
 		if ( uNumDialogueNPCPortraits == 1 )
 			pDialogueNPCCount = 1;
-		pVideoPlayer->OpenHouseMovie(pAnimatedRooms[uCurrentHouse_Animation].video_name, 1u);  
+		pVideoPlayer->OpenHouseMovie(pAnimatedRooms[uCurrentHouse_Animation].video_name, 1u);
 		dword_5C35D4 = 1;
 		if ( (signed int)uHouseID < 139 || (signed int)uHouseID > 172 )
         {
--- a/VideoPlayer.cpp	Wed Apr 02 23:21:34 2014 +0200
+++ b/VideoPlayer.cpp	Mon Apr 07 19:15:13 2014 +0600
@@ -8,6 +8,7 @@
 #include "Mouse.h"
 
 #include "VideoPlayer.h"
+#include "MediaPlayer.h"
 #include "AudioPlayer.h"
 #include "Game.h"
 #include "Render.h"
@@ -357,7 +358,8 @@
     HDC     back_dc = CreateCompatibleDC(dc);
     HBITMAP back_bmp;
     SelectObject(back_dc, back_bmp = CreateCompatibleBitmap(dc, client_width, client_height));
-
+	DWORD t = GetTickCount();
+	end_current_file = false;
     while (true)
     {
       if ( pVideoPlayer->bStopBeforeSchedule )
@@ -373,9 +375,17 @@
       }
       GUI_MainMenuMessageProc();
 
-      if (pMovie->Stopped())
+      double dt = (GetTickCount() - t) / 1000.0;
+      //dt = 1.0/15.0;
+      t = GetTickCount();
+
+      //log("dt=%.5f\n", dt);
+
+      auto image = new char[client_width * client_height * 4];
+
+      pMovie->GetNextFrame(dt, image);
+      if (end_current_file)
         break;
-      char *image = pPlayer->DoFrame();
       if (image)
       {
         // draw to hwnd
@@ -862,9 +872,9 @@
 void VideoPlayer::UpdatePalette()
 {
   Log::Warning(L"smacker");
-
+  loop_current_file = true;
   pRenderer->BeginScene();
-  if (pMovie->Stopped())//видео завершено/перезагрузка
+  /*if (pMovie->Stopped())//видео завершено/перезагрузка
   {
     int width = game_viewport_width;
     int height = game_viewport_height;
@@ -872,11 +882,21 @@
 
     SetFilePointer(hVidFile, uOffset, nullptr, FILE_BEGIN);
 
-    pMovie = pPlayer->LoadMovieFromLOD(hVidFile, &readFunction, &seekFunction, width, height);
+    //pMovie = pPlayer->LoadMovieFromLOD(hVidFile, &readFunction, &seekFunction, width, height);
   }
-  else
+  else */
   {
-    char *image = pPlayer->DoFrame();
+      double dt = (GetTickCount() - time_video_begin) / 1000.0;
+      //dt = 1.0/15.0;
+      time_video_begin = GetTickCount();
+
+      //log("dt=%.5f\n", dt);
+
+      auto image = new char[current_movie_width * current_movie_height * 4];
+
+      pMovie->GetNextFrame(dt, image);
+      Sleep(70);  //Ritor1:it's my include
+
     int image_array[460 * 344];//game_viewport_width * game_viewport_height
     if (image)
     {
@@ -1041,6 +1061,7 @@
     }
 
     LoadMovie(pMovieName);
+	time_video_begin = GetTickCount();
     /*
     this->pSmackerMovie = OpenSmack(Str2);
     if ( !this->pSmackerMovie )
@@ -1237,22 +1258,23 @@
   //RGBTexture::RGBTexture(&pVideoPlayer->pVideoFrame);
   bStopBeforeSchedule = false;
   pResetflag = 0;
-  pPlayer = new MultimediaPlayer();
-  pPlayer->Initialize();
+  //pPlayer = new MultimediaPlayer();
+  //pPlayer->Initialize();
+  pPlayer = new Media::Player;//создаётся плеер
   pMovie = nullptr;
   //pBinkMovie = nullptr;
 }
 
-bool MultimediaPlayer::libavcodec_initialized = false;
+//bool MultimediaPlayer::libavcodec_initialized = false;
 
-void MultimediaPlayer::Logger(void *, int, const char *format, va_list args)
+/*void MultimediaPlayer::Logger(void *, int, const char *format, va_list args)
 {
   char msg[1024];
   vsprintf(msg, format, args);
 
   DWORD w;
   WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), msg, lstrlenA(msg), &w, nullptr);
-}
+}	 */
 
 int VideoPlayer::readFunction(void* opaque, uint8_t* buf, int buf_size)
 {
@@ -1343,4 +1365,14 @@
 
   pMovie = pPlayer->LoadMovieFromLOD(hVidFile, &readFunction, &seekFunction, client_width, client_height);
 
+}
+void VideoPlayer::PlayAudio(const wchar_t * pFilename)
+{
+  Media::ITrack *track = pPlayer->LoadTrack(pFilename);
+  track->Play();
+}
+void VideoPlayer::PlayMovie(const wchar_t * pFilename)
+{
+  Media::IMovie *track = pPlayer->LoadMovie(pFilename, 640, 480, 0);
+  track->Play();
 }
\ No newline at end of file
--- a/VideoPlayer.h	Wed Apr 02 23:21:34 2014 +0200
+++ b/VideoPlayer.h	Mon Apr 07 19:15:13 2014 +0600
@@ -1,6 +1,7 @@
 #pragma once
 #include "OSWindow.h"
 #include "Texture.h"
+#include "MediaPlayer.h"
 
 
 
@@ -388,6 +389,10 @@
 		do
 		{
 			int ret;
+//Функция avcodec_decode_video2 осуществляет декодирование пакета в фрейм с использованием кодека,
+//который мы получили раньше (codec_context). Функция устанавливает положительное значение frame_finished в случае
+//если фрейм декодирован целиком (то есть один фрейм может занимать несколько пакетов и frame_finished будет 
+//установлен только при декодировании последнего пакета).
 			if ((ret = avcodec_decode_video2(dec_ctx, f, (int *)&done, p)) < 0)
 				return ret;
 		} while (!done);
@@ -409,10 +414,10 @@
 	{
 		if (av_image_alloc(out_data, out_linesize, dst_width, dst_height, format, 1) < 0)
 			return false;
-
+// создание контекста для преобразования
 		SwsContext *converter = sws_getContext(frame->width, frame->height, (AVPixelFormat)frame->format,
-			dst_width, dst_height, format,
-			SWS_BICUBIC, nullptr, nullptr, nullptr);
+			dst_width, dst_height, format, SWS_BICUBIC, nullptr, nullptr, nullptr);
+// преобразование кадра
 		sws_scale(converter, frame->data, frame->linesize, 0, frame->height, out_data, out_linesize);
 		sws_freeContext(converter);
 
@@ -444,6 +449,7 @@
 		volatile int done = false;
 		do
 		{
+//Декодирование аудио-пакета осуществляется функцией avcodec_decode_audio4
 			int ret;
 			if ((ret = avcodec_decode_audio4(dec_ctx, f, (int *)&done, p)) < 0)
 				return ret;
@@ -522,7 +528,7 @@
 class MovieCached
 {
 public:
-	bool Stopped() { return stopped; }
+	//bool Stopped() { return stopped; }
 	int GetWidth() { return width; }
 	int GetHeight() { return height; }
 	inline ~MovieCached()
@@ -553,7 +559,7 @@
 		avioContext = nullptr;
 	}
 
-	bool LoadFromLOD(HANDLE h, int readFunction(void*, uint8_t*, int), int64_t seekFunction(void*, int64_t, int), int width, int height)
+	/*bool LoadFromLOD(HANDLE h, int readFunction(void*, uint8_t*, int), int64_t seekFunction(void*, int64_t, int), int width, int height)
 	{
 		if (!ioBuffer)
 			ioBuffer = (unsigned char *)av_malloc(16384 + FF_INPUT_BUFFER_PADDING_SIZE); // can get av_free()ed by libav
@@ -563,17 +569,28 @@
 			format_ctx = avformat_alloc_context();
 		format_ctx->pb = avioContext;
 		return Load("dummyFilename", width, height);
-	}
+	}  */
 
-	bool Load(const char *video_filename, int width, int height)
+	/*bool Load(const char *video_filename, int width, int height)
 	{
 		this->width = width;
 		this->height = height;
-		
+// Open video file
+//откроем входной файл(Шаг 2)
+//Функция avformat_open_input читает файловый заголовок и сохраняет информацию о найденных форматах в структуре
+//AVFormatContext. Остальные аргументы могут быть установлены в NULL, в этом случае libavformat использует 
+//автоматическое определение параметров.
 		if (avformat_open_input(&format_ctx, video_filename, nullptr, nullptr) >= 0)
 		{
+// Retrieve stream information
+//Т.к. avformat_open_input читает только заголовок файла, то следующим шагом нужно получить информацию о потоках
+//в файле. Это делается функцией avformat_find_stream_info.(Шаг 3)
 			if (avformat_find_stream_info(format_ctx, nullptr) >= 0)
 			{
+// Dump information about file onto standard error
+//После этого format_context->streams содержит все существующие потоки файла. 
+//Их количество равно format_context->nb_streams.
+//Вывести подробную информацию о файле и обо всех потоках можно функцией av_dump_format.
 				av_dump_format(format_ctx, 0, video_filename, 0);
 				
 				video_stream_idx = OpenStream(AVMEDIA_TYPE_VIDEO, &video_stream, &video_stream_dec, &video_stream_dec_ctx);
@@ -590,13 +607,17 @@
 					return Release(), false;
 
 				strcpy(movie_name, video_filename);
+//Данные из файла читаются пакетами (AVPacket)
 				packet = new AVPacket;
 				av_init_packet(packet);
 				return true;
 			}
+			fprintf(stderr, "ffmpeg: Unable to find stream info\n");
+			return Release(), false;
 		}
+		fprintf(stderr, "ffmpeg: Unable to open input file\n");
 		return Release(), false;
-	}
+	} */
 
 	bool Release()
 	{
@@ -612,6 +633,8 @@
 			video_stream_idx = -1;
 			video_stream = nullptr;
 			video_stream_dec = nullptr;
+
+			// закрытие видео кодека
 			avcodec_close(video_stream_dec_ctx);
 			video_stream_dec_ctx = nullptr;
 		}
@@ -621,6 +644,8 @@
 			audio_stream_idx = -1;
 			audio_stream = nullptr;
 			audio_stream_dec = nullptr;
+
+			// закрытие аудио кодека
 			avcodec_close(audio_stream_dec_ctx);
 
 		}
@@ -638,13 +663,15 @@
 	}
 
 
-	int OpenStream(AVMediaType type, AVStream **out_stream, AVCodec **out_dec, AVCodecContext **out_dec_ctx)
+	/*int OpenStream(AVMediaType type, AVStream **out_stream, AVCodec **out_dec, AVCodecContext **out_dec_ctx)
 	{
 		int stream_idx = av_find_best_stream(format_ctx, type, -1, -1, nullptr, 0);
 		if (stream_idx < 0)
 			return stream_idx;
 
 		auto stream = format_ctx->streams[stream_idx];
+//Информация о кодеке в потоке называется «контекстом кодека» (AVCodecContext).
+//Используя эту информацию, мы можем найти необходимый кодек (AVCodec) и открыть его.
 		auto dec_ctx = stream->codec;
 		auto dec = avcodec_find_decoder(dec_ctx->codec_id);
 		if (dec)
@@ -657,8 +684,9 @@
 				return stream_idx;
 			}
 		}
+		fprintf(stderr, "ffmpeg: Unable to open codec\n");
 		return -1;
-	}
+	}  */
 
 	MultimediaFrame::Ptr GetNextFrame()
 	{
@@ -666,6 +694,7 @@
 		packet->size = 0;
 
 		volatile int got_frame = false;
+		//чтение пакетов
 		do
 		{
 			if (av_read_frame(format_ctx, packet) < 0)
@@ -673,8 +702,8 @@
 				stopped = true;
 				return nullptr;
 			}
-		} while (packet->stream_index != video_stream_idx &&
-			packet->stream_index != audio_stream_idx);
+		} while (packet->stream_index != video_stream_idx &&  //пока пакет не пренадлежит к видеопотоку
+			packet->stream_index != audio_stream_idx); //и не принадлежит аудиопотоку
 
 		if (packet->stream_index == video_stream_idx)
 			return MultimediaFrame::Ptr(new MultimediaVideoFrame(AVMEDIA_TYPE_VIDEO, packet, video_stream_dec_ctx, width, height));
@@ -688,7 +717,7 @@
 	char                 movie_name[256];
 	int                  width;
 	int                  height;
-	bool                 stopped;
+	//bool                 stopped;
 	AVFormatContext     *format_ctx;
 	//AVFrame             *frame;
 	AVPacket            *packet;
@@ -696,23 +725,23 @@
 	OpenALSoundProvider *sound_provider;
 
 	int              video_stream_idx;
-	AVStream        *video_stream;
+	AVStream        *video_stream;//содержат информацию о видео потоке
 	AVCodec         *video_stream_dec;
 	AVCodecContext  *video_stream_dec_ctx;
 
 	int              audio_stream_idx;
-	AVStream        *audio_stream;
+	AVStream        *audio_stream;//содержат информацию о аудио потоке
 	AVCodec         *audio_stream_dec;
 	AVCodecContext  *audio_stream_dec_ctx;
 	unsigned char * ioBuffer;
 	AVIOContext *avioContext;
 };
-typedef MovieCached<10> Movie;
+//typedef MovieCached<10> Movie;
 
 
 
 
-class MultimediaPlayer
+/*class MultimediaPlayer
 {
 public:
 	inline MultimediaPlayer()
@@ -725,6 +754,11 @@
 		{
 			av_log_set_callback(Logger);
 			avcodec_register_all();
+
+// Register all available file formats and codecs
+//инициализируем библиотеку ffmpeg(Шаг 1)
+//Во время инициализации регистрируются все имеющиеся в библиотеке форматы файлов и кодеков.
+//После этого они будут использоваться автоматически при открытии файлов этого формата и с этими кодеками.
 			av_register_all();
 
 			libavcodec_initialized = true;
@@ -736,7 +770,7 @@
 		return true;
 	}
 
-	Movie *LoadMovieFromLOD(HANDLE h, int readFunction(void*, uint8_t*, int), int64_t seekFunction(void*, int64_t, int), int width, int height)
+	/*Movie *LoadMovieFromLOD(HANDLE h, int readFunction(void*, uint8_t*, int), int64_t seekFunction(void*, int64_t, int), int width, int height)
 	{
 		auto movie = new Movie(sound_provider);
 		if (movie)
@@ -758,9 +792,9 @@
 			delete movie;
 		}
 		return nullptr;
-	}
+	}  */
 
-	Movie *LoadMovie(const char *filename, int width, int height)
+	/*Movie *LoadMovie(const char *filename, int width, int height)
 	{
 		auto movie = new Movie(sound_provider);
 		if (movie)
@@ -774,7 +808,7 @@
 			delete movie;
 		}
 		return nullptr;
-	}
+	} 
 
 	inline char *DoFrame()
 	{
@@ -821,12 +855,12 @@
 	static void Logger(void *, int, const char *format, va_list args);
 
 	OpenALSoundProvider *sound_provider;
-	Movie               *current_movie;
+	//Movie               *current_movie;
 	int                  current_movie_width;
 	int                  current_movie_height;
 
 	static bool libavcodec_initialized;
-};
+};*/
 
 
 
@@ -900,8 +934,8 @@
   char pCurrentMovieName[64];
   char pVideoFrameTextureFilename[32];
   int field_104;
-  MultimediaPlayer *pPlayer;
-  Movie *pMovie;
+  Media::Player *pPlayer;
+  Media::IMovie *pMovie;
   HANDLE hVidFile;
   int uSize;
   int uOffset;
@@ -909,6 +943,8 @@
   static int readFunction(void *, uint8_t *, int);
   static int64_t seekFunction(void *, int64_t, int);
   void LoadMovie(const char *);
+  void PlayAudio(const wchar_t * pFilename);
+  void PlayMovie(const wchar_t * pFilename);
 };
 #pragma pack(pop)