Any way to multi-thread OnLoadExternalResource events?

F-IN-BOX for Delphi / Builder C++ / VCL
jpierce
Posts: 23
Joined: Thu Jan 11, 2007 4:22 pm

Any way to multi-thread OnLoadExternalResource events?

Postby jpierce » Fri Nov 07, 2008 8:41 pm

Is there some way that you can make the flash player control handle LoadExternalResource in a separate thread? Inside of the flash player, the flash code handles each call as a separate network thread. But so far I'm stuck to my f-in-box client doing all of it in the main thread.

Softanics
Site Admin
Posts: 1402
Joined: Sat Sep 18, 2004 3:03 am
Location: Russia, St. Petersburg
Contact:

Postby Softanics » Fri Nov 07, 2008 9:01 pm

Thank you for your question.

Have you tried OnLoadExternalResourceEx ?

http://www.f-in-box.com/delphi/help/ind ... _streaming

Code sample:

Code: Select all

procedure TMainForm.FlashPlayerControl1LoadExternalResourceEx(
  ASender: TObject;
  const URL: WideString;
  Stream: TStream;
  var bHandled: Boolean);
var
   ContentProviderThread: TContentProviderThread;
begin
   if URL = 'images/embedded_image1.jpg' then
   begin
      ContentProviderThread := TContentProviderThread.Create(Stream);

      bHandled := true;
   end;
end;
...

TContentProviderThread = class(TThread)
private
   FResourceStream: TStream;
   FBuffer: TMemoryStream;
...

end;
...

procedure TContentProviderThread.DoWrite;
var
   nWrittenBytes: integer;
begin
   nWrittenBytes := FResourceStream.Write(FBuffer.Memory^, FBuffer.Size);

   if nWrittenBytes = 0 then
      // Write returns 0, if loading was cancelled by some reason
      FStop := true;
end;
...

procedure TContentProviderThread.Execute;
begin
   while not FStop do
   begin
      // preparing buffer
      PrepareBuffer;

      if FBuffer.Size > 0 then
         // always call DoWrite using Synchronize!
         Synchronize(DoWrite);
   end;

   // free the stream after providing all amount of data!
   FResourceStream.Free;
end;


Thank you.
Best regards, Artem A. Razin,
F-IN-BOX support
Ask your question here: http://www.f-in-box.com/support.html

jpierce
Posts: 23
Joined: Thu Jan 11, 2007 4:22 pm

Postby jpierce » Fri Nov 07, 2008 9:04 pm

No, I did not, because I am an idiot. :D

Thanks!

jpierce
Posts: 23
Joined: Thu Jan 11, 2007 4:22 pm

Postby jpierce » Wed Nov 12, 2008 7:33 pm

Well, this seemed good at first, but I'm having a bit of a problem getting it working. Here's the code I'm using:

Delphi:

Code: Select all

type
  TSimpleThread = class(TThread)
  private
    ResourceStream: TStream;
    procedure DoWrite;
  protected
    procedure Execute; override;
  public
    constructor Create(Stream: TStream);
  end;

constructor TSimpleThread.Create(Stream: TStream);
begin
  inherited Create(False);

  ResourceStream := Stream;
end;

procedure TSimpleThread.DoWrite;
var
  x: Integer;
begin
  x := 42;
  ResourceStream.Write(x, SizeOf(x));
end;

procedure TSimpleThread.Execute;
begin
  try
    Synchronize(DoWrite);
  finally
    ResourceStream.Free;
  end;
end;



procedure TMainForm.FlashGlobalLoadExternalResourceEx(const URL: WideString; Stream: TStream; out bHandled: Boolean);
begin
  TSimpleThread.Create(Stream);
  bHandled := True;
end;

...  SetGlobalOnLoadExternalResourceHandlerEx(FlashGlobalLoadExternalResourceEx);
...



Flex:

Code: Select all

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
  paddingRight="0"
  paddingLeft="0"
  paddingTop="0"
  paddingBottom="0"
  creationComplete="cc()"
  >
  <mx:Script>
    <![CDATA[
      import mx.collections.ArrayCollection;

      [Bindable] private var d1:ArrayCollection = new ArrayCollection([]);

      private function cc():void
      {
        var loader:URLLoader = new URLLoader;
        loader.dataFormat = URLLoaderDataFormat.BINARY;
        loader.addEventListener(Event.COMPLETE, testHandler2);
        loader.load(new URLRequest("http://us.i1.yimg.com/us.yimg.com/i/ww/sp/pacg7.gif"));
      }
     
      private function testHandler2(e:Event):void
      {
        //callLater(testHandler, [e]);
        testHandler(e);
      }

      private function testHandler(e:Event):void
      {
        var loader:URLLoader = URLLoader(e.currentTarget);
        loader.data.endian = Endian.LITTLE_ENDIAN;
        while (loader.data.bytesAvailable)
          d1.addItem(loader.data.readInt());
      }
    ]]>

  </mx:Script>

  <mx:List width="100%" dataProvider="{d1}"/>
</mx:Application>


If I run it as shown, I get very strange problems. If you put a breakpoint anywhere inside testHandler2, it stops on it in the debugger and says:

Code: Select all

undefined
   at flash.utils::Timer/_timerDispatch()
   at flash.utils::Timer/tick()


If you then hit run to resume, you get a Stack Overflow error popup in the Flash Player.

If you don't put a breakpoint in and just let it run, you get errors in several different places. Sometimes the error is in line 2072 of ListCollectionView.as and the error is:

Code: Select all

undefined
   at ListCollectionViewCursor/seek()[E:\dev\3.1.0\frameworks\projects\framework\src\mx\collections\ListCollectionView.as:2072]
   at mx.controls.listClasses::ListBase/seekPositionSafely()[E:\dev\3.1.0\frameworks\projects\framework\src\mx\controls\listClasses\ListBase.as:4035]
   at mx.controls.listClasses::ListBase/adjustScrollPosition()[E:\dev\3.1.0\frameworks\projects\framework\src\mx\controls\listClasses\ListBase.as:3739]
   at mx.controls.listClasses::ListBase/updateDisplayList()[E:\dev\3.1.0\frameworks\projects\framework\src\mx\controls\listClasses\ListBase.as:3626]
   at mx.controls::List/updateDisplayList()[E:\dev\3.1.0\frameworks\projects\framework\src\mx\controls\List.as:1003]
   at mx.controls.listClasses::ListBase/validateDisplayList()[E:\dev\3.1.0\frameworks\projects\framework\src\mx\controls\listClasses\ListBase.as:3279]
   at mx.managers::LayoutManager/validateDisplayList()[E:\dev\3.1.0\frameworks\projects\framework\src\mx\managers\LayoutManager.as:605]
   at mx.managers::LayoutManager/doPhasedInstantiation()[E:\dev\3.1.0\frameworks\projects\framework\src\mx\managers\LayoutManager.as:678]
   at Function/http://adobe.com/AS3/2006/builtin::apply()
   at mx.core::UIComponent/callLaterDispatcher2()[E:\dev\3.1.0\frameworks\projects\framework\src\mx\core\UIComponent.as:8565]
   at mx.core::UIComponent/callLaterDispatcher()[E:\dev\3.1.0\frameworks\projects\framework\src\mx\core\UIComponent.as:8508]


Sometimes the error is in line 8046 in ListBase.as, also showing undefined and a stack trace.

Basically, this really has the flavor of a multithreaded application where one thread is trying to access data in another thread and everything's just getting fouled up.

If you uncomment the callLater call and comment out the testHandler(e) line, it works without errors. This further makes me wonder about threading issues.

And if you comment out the Delphi setting of the resource handler, it loads that yimg.com data fine and doesn't get errors (even without the callLater).

Again, these things are sounding more and more like threading issues. Any idea how I can get around it? I've posted to flexcoders in hopes of shedding a light on things. I'm not sure how much they'll help as this issue only happens when running in f-in-box. There's no equivalent call to Synchronize in Flex, so I can't try that.

jpierce
Posts: 23
Joined: Thu Jan 11, 2007 4:22 pm

Postby jpierce » Wed Nov 12, 2008 7:39 pm

In case it's helpful, I just got this reply back from the Flex support:

"Everything is single-threaded. Network calls are async, but results are serviced in the one and only thread

The thread constantly rotates from servicing code to async events like mouse, keyboard and networks to rendering and back to code."

Softanics
Site Admin
Posts: 1402
Joined: Sat Sep 18, 2004 3:03 am
Location: Russia, St. Petersburg
Contact:

Postby Softanics » Wed Nov 12, 2008 7:51 pm

Thank you for your question.

What I noticed:

Code: Select all

procedure TMainForm.FlashGlobalLoadExternalResourceEx(const URL: WideString; Stream: TStream; out bHandled: Boolean);
begin
  TSimpleThread.Create(Stream);
  bHandled := True;
end;


You should compare URL with which one/ones you would like to handle.

Regarding multithreading, no problems: we call Write using Synchronize, so writing is performing inside a main thread.

Thank you.
Best regards, Artem A. Razin,

F-IN-BOX support

Ask your question here: http://www.f-in-box.com/support.html

jpierce
Posts: 23
Joined: Thu Jan 11, 2007 4:22 pm

Postby jpierce » Wed Nov 12, 2008 7:53 pm

The reason I'm not testing URL is that this is a simple test app.

So do you have a test case you use to test this code? Do you use Flex? Can you replicate my errors?

Thanks.

Softanics
Site Admin
Posts: 1402
Joined: Sat Sep 18, 2004 3:03 am
Location: Russia, St. Petersburg
Contact:

Postby Softanics » Wed Nov 12, 2008 7:56 pm

jpierce wrote:The reason I'm not testing URL is that this is a simple test app.

So do you have a test case you use to test this code? Do you use Flex? Can you replicate my errors?

Thanks.


It would be great if you can send me your SWF, and, if possible, the sample code. I would like to test it more, and it will be faster if you can provide me what you already have. My email is support (at) f-in-box.com

Thank you in advance.
Best regards, Artem A. Razin,

F-IN-BOX support

Ask your question here: http://www.f-in-box.com/support.html

jpierce
Posts: 23
Joined: Thu Jan 11, 2007 4:22 pm

Postby jpierce » Wed Nov 12, 2008 8:36 pm

Sent!

Softanics
Site Admin
Posts: 1402
Joined: Sat Sep 18, 2004 3:03 am
Location: Russia, St. Petersburg
Contact:

Postby Softanics » Thu Nov 13, 2008 9:16 am

jpierce wrote:Sent!


Received, thank you!
Best regards, Artem A. Razin,

F-IN-BOX support

Ask your question here: http://www.f-in-box.com/support.html

Softanics
Site Admin
Posts: 1402
Joined: Sat Sep 18, 2004 3:03 am
Location: Russia, St. Petersburg
Contact:

Postby Softanics » Fri Nov 14, 2008 4:37 pm

The problem has been solved by calling ResourceStream.Free using Synchronize.

Any methods of TStream that you receive in handlers like TMainForm.FlashGlobalLoadExternalResourceEx should be called using Synchronize.

Thank you.
Best regards, Artem A. Razin,

F-IN-BOX support

Ask your question here: http://www.f-in-box.com/support.html

andreaarg
Posts: 14
Joined: Tue Aug 26, 2008 11:53 pm

Postby andreaarg » Thu Mar 12, 2009 11:50 pm

Is it possible to catch OnLoadExternalResourceEx AND OnLoadExternalResource for one TFlashPlayerControl, based on some criteria? For example, using OnLoadExternalResource to handle small data requests (such as some text) that are non threaded handled, and using OnLoadExternalResourceEx for data requests that need more processing (such as generating an image thumbnail)

Softanics
Site Admin
Posts: 1402
Joined: Sat Sep 18, 2004 3:03 am
Location: Russia, St. Petersburg
Contact:

Postby Softanics » Fri Mar 13, 2009 10:06 am

andreaarg wrote:Is it possible to catch OnLoadExternalResourceEx AND OnLoadExternalResource for one TFlashPlayerControl, based on some criteria? For example, using OnLoadExternalResource to handle small data requests (such as some text) that are non threaded handled, and using OnLoadExternalResourceEx for data requests that need more processing (such as generating an image thumbnail)


If a handler returns a small piece of data immediately, you can use OnLoadExternalResource. If data is huge, use OnLoadExternalResourceEx.

I hope I understand your question well...

Thank you.
Best regards, Artem A. Razin,

F-IN-BOX support

Ask your question here: http://www.f-in-box.com/support.html

coolshadow
Posts: 67
Joined: Fri Oct 10, 2008 7:42 am

Postby coolshadow » Fri Mar 13, 2009 3:20 pm

Softanics wrote:
andreaarg wrote:Is it possible to catch OnLoadExternalResourceEx AND OnLoadExternalResource for one TFlashPlayerControl, based on some criteria? For example, using OnLoadExternalResource to handle small data requests (such as some text) that are non threaded handled, and using OnLoadExternalResourceEx for data requests that need more processing (such as generating an image thumbnail)


If a handler returns a small piece of data immediately, you can use OnLoadExternalResource. If data is huge, use OnLoadExternalResourceEx.

I hope I understand your question well...

Thank you.


I think his question is that if OnLoadExternalResourceEx AND OnLoadExternalResource can be called together. use the first one to process big files, the other to process small ones.

BTW: Have you any idea about the new version?
For example to make the TFlashplayercontrol and Ttransparentflashplayercontrol to be one component ,not two :wink:

or any other good idea

Softanics
Site Admin
Posts: 1402
Joined: Sat Sep 18, 2004 3:03 am
Location: Russia, St. Petersburg
Contact:

Postby Softanics » Fri Mar 13, 2009 3:48 pm

coolshadow wrote:BTW: Have you any idea about the new version?
For example to make the TFlashplayercontrol and Ttransparentflashplayercontrol to be one component ,not two :wink:


Not yet... :oops:
Best regards, Artem A. Razin,

F-IN-BOX support

Ask your question here: http://www.f-in-box.com/support.html


Return to “Delphi / Builder / VCL Edition”

Who is online

Users browsing this forum: No registered users and 9 guests