[WINDOWS] Socket initialization issue and possible solution
#1
Hello everyone,

while implementing a UPnP streaming server in one of our DVB devices, i discovered an issue with WSAStartup/WSACleanup calls on windows.

First, i made the following change to be able to playback the transportstream. Without that change the auto detection sometimes believes that the stream is an MP3 stream.
Code:
bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)
...
    else if( content.compare("video/x-mpeg2-ts") == 0 )
      iformat = m_dllAvFormat.av_find_input_format("mpegts");

Anyway, the following happens: When XBMC is started, WSAStartup is called twice. The first time it is called by NPT_WinsockSystem::NPT_WinsockSystem() the second time by libcurl.

So far so good. When i try to play a transportstream, CDVDDemuxFFmpeg is created and the stream is played. As soon as i stop the stream the following happens:
Code:
CDVDDemuxFFmpeg::Dispose() is called
m_dllAvFormat.url_fclose(m_ioContext); is executed
avformat-52.dll calls WSACleanup
That WSACleanup call is wrong here, because no WSAStartup has been done by avformat-52.dll. The result of this error is that i can only playback two streams. Any upcoming socket function call in XBMC fails with WSAGetLastError() == WSANOTINITIALISED. I added a workaround by replacing
Code:
CDVDDemuxFFmpeg::Dispose()
...
m_dllAvFormat.av_close_input_stream(m_pFormatContext);
m_dllAvFormat.url_fclose(m_ioContext);
with
Code:
CDVDDemuxFFmpeg::Dispose()
...
m_dllAvFormat.av_close_input_stream(m_pFormatContext);
#ifdef _WIN32
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);
#endif
m_dllAvFormat.url_fclose(m_ioContext);
This works perfectly fine but seems wrong because the bug is actually in avformat and i don't really know if these FFMPEG libraries are custom build for XBMC.

Any suggestions on that one?
Reply
#2
bug must be upstream. while we do modify the ffmpeg libraries slightly, none of those modifications influence the behavior here.
Reply
#3
It seems to me that a url_fdclose function is missing in FFMPEG.

url_open and url_close implements the socket initialization/release.
url_fopen calls url_open and url_open calls url_fdopen
url_fclose calls url_close

IMHO, adding WSAStartup() before url_fdopen would do it
Reply
#4
it would cure the symptom, not fix the bug.
Reply
#5
We probably suffer from the same bug: http://trac.xbmc.org/ticket/9004
Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.
Reply
#6
Yeah, seems to be the same issue. I posted a possible patch to the FFMPEG list that adds an url_fdclose but according to bobo1on1's post there seems to be more issues.

Quote:It seems url_open_protocol in libavformat calls ff_network_close when it fails, which calls WSACleanup. However url_close also calls ff_network_close so you have two calls to WSACleanup.
Reply
#7
I have uploaded a patch for the XBMC copy of FFMPEG here. The same patch has been posted to the FFMPEG bug tracker.

Basically, it moves the url_fdopen code to url_fdopen_internal. url_fdopen calls the network init code and finally url_fdopen_internal.

Of course, a MinGW rebuld of avformat is needed...

@WiSo

i saw your checkings for the bug you have posted. IMHO they are not needed anymore if the above patch is applied.

And here is another patch for XBMC to support the mpeg2 transportstream content type i have posted above.
Reply
#8
Unfortunately your patch was rejected.
Not sure if we will use it anyway because the IRSS suffers from the same bug and it needs some more rewrites to get it working again.
Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.
Reply
#9
Can anyone of you please reply to the following comment from mstorsjo about this avformat bug in the FFMPEG bug tracking system?

Quote:Could the code in
http://trac.xbmc.org/browser/trunk/xbmc/...Fmpeg.cpp#
L319 be rewritten to call url_open_protocol instead of manually initializing things?
That would perhaps be the cleanest solution.

https://roundup.ffmpeg.org/issue1849
Reply
#10
I dropped elupus a mail and he'll check it.
Maybe it's already done with r29242
Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.
Reply
#11
Works perfectly Laugh Thank you.

I saw there were some checkins concerning the format auto detection. Unfortunatly this still doesn't work well. Without the following code
Code:
bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput)
...
    else if( content.compare("video/x-mpeg2-ts") == 0 )
      iformat = m_dllAvFormat.av_find_input_format("mpegts");
the transport stream is still detected as mp3. Why not creating some kind of key/value XML document where all these content-type/demux mappings are present?

Also with the current SVN code, starting the playback takes a few seconds longer than before.
Reply
#12
Milenko Wrote:Also with the current SVN code, starting the playback takes a few seconds longer than before.
hmmm, this was added on purpose with revision 29194 and 28813 to fix another issue...
Reply
#13
It seems the problem is because there is not enough data buffered to figure out the type of the stream. The result of
Code:
pd.buf_size = m_dllAvFormat.get_partial_buffer(m_ioContext, pd.buf, m_ioContext->max_packet_size);
is very small. Sometimes 188 bytes (one TS packet) other times it is 376 bytes.
I changed the code to buffer at least max_packet_size bytes
Code:
if(m_ioContext->is_streamed)
      {
          while(true)
          {
                int nReaden = m_dllAvFormat.get_partial_buffer(m_ioContext, pd.buf+pd.buf_size, m_ioContext->max_packet_size-pd.buf_size);
                pd.buf_size += nReaden;
                if (m_ioContext->max_packet_size == pd.buf_size)
                    break;
          }
      }
      else
and now the auto detection seems to work fine.
Reply

Logout Mark Read Team Forum Stats Members Help
[WINDOWS] Socket initialization issue and possible solution0