Play 16 videoclips at once, acting interactively (Like a Rolling Stone)

497 views Asked by At

Recently, I saw a very good idea to put on a video clip. It's about 'Like a Rolling Stone', that we can see here: http://video.bobdylan.com/desktop.html

As you can see, you can interact with it, changing channel with up/down keys.

I downloaded all 16 individual subclips.

Now, the challenge is to make a program, a single player to do the same and a little bit more.

I tried to get some help in another forum, but now I'm stuck at the programming stage.

Please, have a look here:

Edited: [link removed] It's Videohelp forum, thread with same title as this question]

I wrote a small program to load the videos and show them in a mosaic. This is the first step toward to the feature to "change channels". I'm using DSPack components, which uses DirectShow and Direct9 libraries, with Delphi 7.

Here, what I got so far:

Mosaic with 12 videos

As seen on picture, 12 videos were loaded.

I'm planning to turn off visible property for all other videos, when seeing one video by time, when implementing feature "change channels", to alleviate the system. But when in mosaic layout, it's not possible.

When solve this step, I'll implement the "changing channel" feature using hotkeys.

The problem is that I'm confused with the Visible and Active properties for VideoWindow and FilterGraph and I'm not using them accordingly.

Here is the code, so far:

procedure TFormPlayWin.FormActivate(Sender: TObject);
begin
  BigScreen := true;
  SmallScreen := false;
  VideoWindow01.Width := 1425;
  VideoWindow01.Height := 761;

  VideoWindow01.Visible := true;
  VideoWindow02.Visible := false;
  VideoWindow03.Visible := false;
  VideoWindow04.Visible := false;
  VideoWindow05.Visible := false;
  VideoWindow06.Visible := false;
  VideoWindow07.Visible := false;
  VideoWindow08.Visible := false;
  VideoWindow09.Visible := false;
  VideoWindow10.Visible := false;
  VideoWindow11.Visible := false;
  VideoWindow12.Visible := false;

    if not FilterGraph01.Active then FilterGraph01.Active := true;
    if not FilterGraph02.Active then FilterGraph02.Active := true;
    if not FilterGraph03.Active then FilterGraph03.Active := true;
    if not FilterGraph04.Active then FilterGraph04.Active := true;
{
    if not FilterGraph05.Active then FilterGraph05.Active := true;
    if not FilterGraph06.Active then FilterGraph06.Active := true;
    if not FilterGraph07.Active then FilterGraph07.Active := true;
    if not FilterGraph08.Active then FilterGraph08.Active := true;
    if not FilterGraph09.Active then FilterGraph09.Active := true;
    if not FilterGraph10.Active then FilterGraph10.Active := true;
    if not FilterGraph11.Active then FilterGraph11.Active := true;
    if not FilterGraph12.Active then FilterGraph12.Active := true;
}
    FilterGraph01.ClearGraph;
    FilterGraph02.ClearGraph;
    FilterGraph03.ClearGraph;
    FilterGraph04.ClearGraph;
{
    FilterGraph05.ClearGraph;
    FilterGraph06.ClearGraph;
    FilterGraph07.ClearGraph;
    FilterGraph08.ClearGraph;
    FilterGraph09.ClearGraph;
    FilterGraph10.ClearGraph;
    FilterGraph11.ClearGraph;
    FilterGraph12.ClearGraph;
}
    FilterGraph01.RenderFile('D:\Meus documentos\Downloads\Bob Dylan\Joined01.flv');
    FilterGraph02.RenderFile('D:\Meus documentos\Downloads\Bob Dylan\Joined02.flv');
    FilterGraph03.RenderFile('D:\Meus documentos\Downloads\Bob Dylan\Joined03.flv');
    FilterGraph04.RenderFile('D:\Meus documentos\Downloads\Bob Dylan\Joined04.flv');
{
    FilterGraph05.RenderFile('D:\Meus documentos\Downloads\Bob Dylan\Joined05.flv');
    FilterGraph06.RenderFile('D:\Meus documentos\Downloads\Bob Dylan\Joined06.flv');
    FilterGraph07.RenderFile('D:\Meus documentos\Downloads\Bob Dylan\Joined07.flv');
    FilterGraph08.RenderFile('D:\Meus documentos\Downloads\Bob Dylan\Joined08.flv');
    FilterGraph09.RenderFile('D:\Meus documentos\Downloads\Bob Dylan\Joined09.flv');
    FilterGraph10.RenderFile('D:\Meus documentos\Downloads\Bob Dylan\Joined10.flv');
    FilterGraph11.RenderFile('D:\Meus documentos\Downloads\Bob Dylan\Joined11.flv');
    FilterGraph12.RenderFile('D:\Meus documentos\Downloads\Bob Dylan\Joined12.flv');
}
    VideoWindow01.PopupMenu := PopupMenu;
    SoundLevel.Position := FilterGraph01.Volume;

    FilterGraph01.Play;
    FilterGraph02.Play;
    FilterGraph03.Play;
    FilterGraph04.Play;
{
    FilterGraph05.Play;
    FilterGraph06.Play;
    FilterGraph07.Play;
    FilterGraph08.Play;
    FilterGraph09.Play;
    FilterGraph10.Play;
    FilterGraph11.Play;
    FilterGraph12.Play;

      FilterGraph02.Active := false;
      FilterGraph03.Active := false;
      FilterGraph04.Active := false;
      FilterGraph05.Active := false;
      FilterGraph06.Active := false;
      FilterGraph07.Active := false;
      FilterGraph08.Active := false;
      FilterGraph09.Active := false;
      FilterGraph10.Active := false;
      FilterGraph11.Active := false;
      FilterGraph12.Active := false;

      VideoWindow02.Visible := false;
      VideoWindow03.Visible := false;
      VideoWindow04.Visible := false;
      VideoWindow05.Visible := false;
      VideoWindow06.Visible := false;
      VideoWindow07.Visible := false;
      VideoWindow08.Visible := false;
      VideoWindow09.Visible := false;
      VideoWindow10.Visible := false;
      VideoWindow11.Visible := false;
      VideoWindow12.Visible := false;
}
end;

Above, I'm trying to make the first Clip covering the whole area and keep the other videos unseen. But the thhings are going bad, because I can see VideoWindow 2,3 and 4, over the big one VideoWindow1.

The idea is to use hotkeys to switch Big and Small Screen, and to "change channels".

To preserve processing and syncing, I'd like to run just only one audio track. How to detach this from DirectShow filter? I need that to play just only one audio. Bad idea to run all audio tracks if I need just one of them. I have to mute the other ones.

Said that, I have two questions:

1 - How to make better the code above to handle too many videos at once.

2 - How to mute audio track from all others video, but first one keeps alive.

2

There are 2 answers

1
Pericles On

It seems to be a good task for using OOP. But you can do it easy even with out arrays.. I´ll tell you an idea..

Description/functionality

12 mini screens simultaneously (one with sound) one big screen when you want (with the possibility of change to 12 again for select new channel)

implementation:

1)load twelve videos and turn on sound of screen one 2)change active miniScreen (changing focus and active sound) 3)openBigScreen with selected movie 4)return to 12miniScreens

components:

var ActiveMiniScreen : TScreen;

minScr01 ... minScr12 (12 screens like you did) bigScr (extra screen with aling allClient, visible=false or a second form) backTo12Button (bigScr.onDoubleClick or button in second form)

You ´ll need 4 methods..

onFormCreate()

load all videos and set active (start sound and make it visual diferente of others)

ActiveMiniScreen := miniScr1;
miniScr1.loadVideo()
miniScr1.soundOn
miniScr1.BorderColor:= red

miniScr2.loadVideo()
miniScr2.soundOff
miniScr2.BorderColor:= black
      ...
miniScr12.loadVideo()
miniScr12.soundOff
miniScr12.BorderColor:= black

onMinScreenClick() all the miniSreens share the same onMiniScreen1Click method

ActiveMiniScreen := Tscreen(Sender)
Tscreen(Sender).SoundOn
Tscreen(Sender).BorderColor:= red

onMinDoubleScreenClick()

BigScreen.visible:=true
BigScreen.align:=alClient
BigScreen.loadVideo( ActiveMiniScreen.video )  //load miniScreen active 's video)
BigScreen.soundOn
ActiveMiniScreen.soundOff

onBigScreenDoubleClick() (DoubleClick or onClick) or button in form2

BigScreen.visible:=false
BigScreen.soundOff
ActiveMiniScreen.soundOn
2
haz On

If you want all videos to play in sync - so when you switch between videos they are at the same position, load all videos into a single filtergraph and connect them to a single renderer like the VMR9 that supports up to 16 streams. Switch between videos by setting the z-order of the streams and the volume of the associated audio renderers.

Here's some code to get you going. The trick is using a Capture Graph to render the video and audio to a specific renderer, that way you can use a single video and multiple audio renderers.

Note: i've provided no error handling and you will need to clean up resources allocated.

  GraphBuilder: IGraphBuilder;
  CaptureGraph: ICaptureGraphBuilder2;
  VMR9: IBaseFilter;
  VMRFilterConfig9: IVMRFilterConfig9;
  VMRWindowlessControl9: IVMRWindowlessControl9;
  vw_position: TRect;
  VMRMixerControl9: IVMRMixerControl9;

  // create the fitler graph
  CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER, IID_IFilterGraph2, GraphBuilder);
  // create the capture graph
  CoCreateInstance(CLSID_CaptureGraphBuilder2, nil, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, CaptureGraph);
  CaptureGraph.SetFiltergraph(IGraphBuilder(GraphBuilder));
  // create add the video renderer filter
  CoCreateInstance(CLSID_VideoMixingRenderer9, nil, CLSCTX_INPROC, IID_IBaseFilter, VMR9);
  GraphBuilder.AddFilter(VMR9, 'Renderer');
  // assign renderer to a TPanel
  VMR9.QueryInterface(IID_IVMRFilterConfig9, VMRFilterConfig9);
  VMRFilterConfig9.SetRenderingMode(VMR9Mode_Windowless);
  VMR9.QueryInterface(IID_IVMRWindowlessControl9, VMRWindowlessControl9);
  vw_position.Left := 0;
  vw_position.Top  := 0;
  vw_position.Right  := Panel.width;
  vw_position.Bottom := Panel.height;
  VMRWindowlessControl9.SetVideoPosition(nil, @vw_position);
  VMRWindowlessControl9.SetVideoClippingWindow(Panel.handle);
  // get mixer control
  VMR9.QueryInterface(IID_IVMRMixerControl9, VMRMixerControl9);
  // to control z-order, alpha etc.. see
  // http://msdn.microsoft.com/en-us/library/windows/desktop/dd390457%28v=vs.85%29.aspx


  // encapsluate the following into a class so you can reuse for each video
  SourceFilter: IBaseFilter;
  AudioRenderer: IBaseFilter;
  // create and file source and render video
  GraphBuilder.AddSourceFilter(stringtoolestr(Filename), stringtoolestr(ExtractFileName(Filename)), FileSource);
  CaptureGraph.RenderStream(nil, nil, FileSource, nil, VMR9 as IBaseFilter);
  // create audio renderer and render audio
  CoCreateInstance(StringToGUID('{79376820-07D0-11CF-A24D-0020AFD79767}'), nil, CLSCTX_INPROC, IID_IBaseFilter, AudioRenderer);
  GraphBuilder.AddFilter(AudioRenderer, 'DirectSound Audio Renderer');
  CaptureGraph.RenderStream(nil, nil, FileSource, nil, AudioRenderer);