[ANNOUNCE] H.264 updates for VDR-1.5.9

Message ID 46D4A316.8090409@gmx.de
State New
Headers

Commit Message

Reinhard Nissl Aug. 28, 2007, 10:35 p.m. UTC
  Hi,

the attached vdr-1.5.9-h264.patch adds H.264 support to VDR's remuxer.
The changes to earlier releases are:

- H264::cParser has been enhanced to provide information for
  H264::cContext::GetFramesPerSec() and therefore outsourced
  into separate files.
- cVideoRepacker generates Access Unit Delimiters in case they
  are not part of the stream.

These changes should make VDR ready for the upcoming IFA fair in regard
to the broadcasts on the temporary channel EinsFestival HD.

The other attached patch vdr-1.5.9-framespersec.patch tries to replace
the macro FRAMESPERSEC by a function call GetFramesPerSec() which
analyses a recordings first video frame to determine frames per second
which are used to calculated a recordings length. The changes to earlier
releases are:

- add support for H.264 recordings by making use of the above
  mentioned H264::cParser, as frame timing stuff is quite complex.
  H.264 support can be turned off by putting a comment around the
  macro ADD_H264_SUPPORT in tools.c.

This change provides correct recording length reports for recordings
taken on EinsFestival HD as this channel broadcasts 50p, i. e. without
the patch, VDR will report recording times which are twice the actual time.

The patch in general may especially be useful for people with PAL and
NTSC recordings, as in this scenario it was never possible to find a
single setting for FRAMESPERSEC.
Although FRAMESPERSEC has been replaced on many locations, it is still
used to read/write cutting marks file, to stay compatible.

Have fun while expecting the next vdr-xine-release ;-)

Bye.
  

Comments

Petri Helin Aug. 29, 2007, 8:38 p.m. UTC | #1
Reinhard Nissl wrote:
> Hi,
> 
> the attached vdr-1.5.9-h264.patch adds H.264 support to VDR's remuxer.
> The changes to earlier releases are:
> 
> - H264::cParser has been enhanced to provide information for
>   H264::cContext::GetFramesPerSec() and therefore outsourced
>   into separate files.
> - cVideoRepacker generates Access Unit Delimiters in case they
>   are not part of the stream.

Should this patch make it possible to record H.264 encoded stream? I 
have applied the patch and can see in the channels menu that Canal+ HD 
Film uses H.264 codec, but I can not record the channel (nor watch it...).

-Petri
  
Reinhard Nissl Aug. 29, 2007, 9:02 p.m. UTC | #2
Hi,

Petri Helin wrote:

>> the attached vdr-1.5.9-h264.patch adds H.264 support to VDR's remuxer.
>> The changes to earlier releases are:
>>
>> - H264::cParser has been enhanced to provide information for
>>   H264::cContext::GetFramesPerSec() and therefore outsourced
>>   into separate files.
>> - cVideoRepacker generates Access Unit Delimiters in case they
>>   are not part of the stream.
> 
> Should this patch make it possible to record H.264 encoded stream? I 

It should. It works for the German DVB-S2 HD channels on Astra and it
worked for LuxeTV HD on Hotbird in the past.

> have applied the patch and can see in the channels menu that Canal+ HD 
> Film uses H.264 codec, but I can not record the channel (nor watch it...).

Is this the channel you've mentioned (I've applied a DVB-S2 patch, so
the entry may differ from your's a little)?

CANAL+ FILM
HD;Harmonic:11470:vC56M2S0Z0:S13.0E:27500:10331+331:332=pol;333=ORY:551:100:15423:318:1400:0

On my system, VDR says this channel is encrypted. Do you have the
necessary means to receive this channel?

Bye.
  
Hannu Tirkkonen Aug. 29, 2007, 9:05 p.m. UTC | #3
On Wed, Aug 29, 2007 at 11:38:39PM +0300, Petri Helin wrote:
> Reinhard Nissl wrote:
> > Hi,
> > 
> > the attached vdr-1.5.9-h264.patch adds H.264 support to VDR's remuxer.
> > The changes to earlier releases are:
> > 
> > - H264::cParser has been enhanced to provide information for
> >   H264::cContext::GetFramesPerSec() and therefore outsourced
> >   into separate files.
> > - cVideoRepacker generates Access Unit Delimiters in case they
> >   are not part of the stream.
> 
> Should this patch make it possible to record H.264 encoded stream? I 
> have applied the patch and can see in the channels menu that Canal+ HD 
> Film uses H.264 codec, but I can not record the channel (nor watch it...).
> 
> -Petri
I did apply this h264 patch and streamdev patch from: 
http://www.vdr-developer.org/mantisbt/view.php?id=382

Now the load of the server is low when tuned to Canal+ HD and I can watch the stream using vlc.
The recording at least outputs something to hard disk ;)

...hanu
  
Petri Helin Aug. 29, 2007, 9:10 p.m. UTC | #4
Reinhard Nissl wrote:
> Hi,
> 
> Petri Helin wrote:
> 
>>> the attached vdr-1.5.9-h264.patch adds H.264 support to VDR's remuxer.
>>> The changes to earlier releases are:
>>>
>>> - H264::cParser has been enhanced to provide information for
>>>   H264::cContext::GetFramesPerSec() and therefore outsourced
>>>   into separate files.
>>> - cVideoRepacker generates Access Unit Delimiters in case they
>>>   are not part of the stream.
>> Should this patch make it possible to record H.264 encoded stream? I 
> 
> It should. It works for the German DVB-S2 HD channels on Astra and it
> worked for LuxeTV HD on Hotbird in the past.
> 
>> have applied the patch and can see in the channels menu that Canal+ HD 
>> Film uses H.264 codec, but I can not record the channel (nor watch it...).
> 
> Is this the channel you've mentioned (I've applied a DVB-S2 patch, so
> the entry may differ from your's a little)?
> 
> CANAL+ FILM
> HD;Harmonic:11470:vC56M2S0Z0:S13.0E:27500:10331+331:332=pol;333=ORY:551:100:15423:318:1400:0
> 
> On my system, VDR says this channel is encrypted. Do you have the
> necessary means to receive this channel?
> 

The channel I mean is the same, I think, but provided by my local cable 
operator. Here is the entry in channels.conf:
Canal+ Film 
HD;Telenor:330000:C0M256:C:6900:10512+512:640=eng;641=eng:0:B00:3306:0:22:0

I have a valid subscription and this particular channel dis work when I 
tested it with the ts-recording and h264-patches available here: 
http://phivdr.dyndns.org/vdr

My subscription is ending in 24 hours, so I'd like to know if I can 
record the channel before making my mind whether to continue the 
subscription ;)

-Petri
  
Reinhard Nissl Aug. 29, 2007, 9:20 p.m. UTC | #5
Hi,

Petri Helin wrote:

> The channel I mean is the same, I think, but provided by my local cable 
> operator. Here is the entry in channels.conf:
> Canal+ Film 
> HD;Telenor:330000:C0M256:C:6900:10512+512:640=eng;641=eng:0:B00:3306:0:22:0
> 
> I have a valid subscription and this particular channel dis work when I 
> tested it with the ts-recording and h264-patches available here: 
> http://phivdr.dyndns.org/vdr

Can you provide me with a few MB of TS stream from that channel?

Something like czap and cat /dev/dvb/adapterX/dvr0 > sample.ts should do
the trick.

> My subscription is ending in 24 hours, so I'd like to know if I can 
> record the channel before making my mind whether to continue the 
> subscription ;)

Then you have to hurry now, I won't have much time tomorrow evening.

Bye.
  
Reinhard Nissl Aug. 29, 2007, 10:11 p.m. UTC | #6
Hi,

Reinhard Nissl wrote:

> Can you provide me with a few MB of TS stream from that channel?
> 
> Something like czap and cat /dev/dvb/adapterX/dvr0 > sample.ts should do
> the trick.

The TS sample you've sent me looks ok, i. e. it can be parsed by
H264::cParser.

Please locate the following location in cVideoRepacker::Repack() in file
remux.c:

  // remember start of the data
  const uchar *payload = data;
  const uchar *NalPayload = payload;

  while (todo > 0) {

and add the following line before the while:

if (h264parser) { static FILE *f = fopen("/video/sample.es.h264", "wb");
fwrite(data, 1, todo, f); fflush(f); }

The line will write the PES packet's content into file
/video/sample.es.h264 when a h264parser exists. Then please send me some
MB of the file.

Bye.
  
Reinhard Nissl Aug. 29, 2007, 11:02 p.m. UTC | #7
Hi,

Reinhard Nissl wrote:

> The line will write the PES packet's content into file
> /video/sample.es.h264 when a h264parser exists. Then please send me some
> MB of the file.

The file you've sent me doesn't contain any useful data. You can have a
look at it yourself:

od -Ax -t x1 -v sample2.es.h264 | less -S

You need to find at least the sequence 00 00 01. Otherwise it's garbage.

I'll go to bed soon, so here's a quick description how to go on:

- add this function to cRepacker
  virtual void LogTS(const uint8_t *Buf) {}
- add this function to cVideoRepacker
  virtual void LogTS(const uint8_t *Buf) { if (h264parser) { static FILE
*f = fopen("/video/sample.ts", "wb"); fwrite(Buf, 1, 188, f); fflush(f); } }
- change this area in ts_to_pes() like that:

void cTS2PES::ts_to_pes(const uint8_t *Buf) // don't need count (=188)
{
  if (!Buf)
     return;
if (repacker) repacker->LogTS(Buf);
  if (Buf[1] & TS_ERROR)

Be careful to just have a single cVideoRepacker instance write into this
file, i. e. either activate transfer mode on this channel or make a
recording on this channel but not both at the same time.

Have a look at this file with

od -Ax -t x1 -v -w188 sample.ts | less -S

and locate the sequence 00 00 01 multiple times. It should then be
possible to record this channel although it doesn't work for now, as
cVideoRepacker didn't find any startcode (00 00 01) in the
sample.es.h264 from above.

Bye.
  
Petri Helin Aug. 30, 2007, 5:38 a.m. UTC | #8
Reinhard Nissl wrote:
> Hi,
> 
> Reinhard Nissl wrote:
> 
>> The line will write the PES packet's content into file
>> /video/sample.es.h264 when a h264parser exists. Then please send me some
>> MB of the file.
> 
> The file you've sent me doesn't contain any useful data. You can have a
> look at it yourself:
> 
> od -Ax -t x1 -v sample2.es.h264 | less -S
> 
> You need to find at least the sequence 00 00 01. Otherwise it's garbage.
> 
> I'll go to bed soon, so here's a quick description how to go on:
> 
> - add this function to cRepacker
>   virtual void LogTS(const uint8_t *Buf) {}
> - add this function to cVideoRepacker
>   virtual void LogTS(const uint8_t *Buf) { if (h264parser) { static FILE
> *f = fopen("/video/sample.ts", "wb"); fwrite(Buf, 1, 188, f); fflush(f); } }
> - change this area in ts_to_pes() like that:
> 
> void cTS2PES::ts_to_pes(const uint8_t *Buf) // don't need count (=188)
> {
>   if (!Buf)
>      return;
> if (repacker) repacker->LogTS(Buf);
>   if (Buf[1] & TS_ERROR)
> 
> Be careful to just have a single cVideoRepacker instance write into this
> file, i. e. either activate transfer mode on this channel or make a
> recording on this channel but not both at the same time.
> 
> Have a look at this file with
> 
> od -Ax -t x1 -v -w188 sample.ts | less -S
> 
> and locate the sequence 00 00 01 multiple times. It should then be
> possible to record this channel although it doesn't work for now, as
> cVideoRepacker didn't find any startcode (00 00 01) in the
> sample.es.h264 from above.
> 
> Bye.

I have made the changes and did some testing, but there are no "00 00 
01" series in the data at all. Some strange patterns I can see, but 
mostly just garbage. I will try again this evening when I can be sure 
that there is a program running.

Fortunately I remembered wrong the end date of my subscription, it is 
valid until the end of this month, so I have 24 hours more to test this...

-Petri
  
Arthur Konovalov Aug. 30, 2007, 9:03 a.m. UTC | #9
> Reinhard Nissl wrote:
> the attached vdr-1.5.9-h264.patch adds H.264 support to VDR's remuxer.

Hi,
I trying to compile vdr-1.5.9 with h264 patches but vdr-xine-0.7.10 plugin give 
me error:

xineDevice.c: In member function 'int PluginXine::cXineDevice::PlayCommon3(const 
uchar*, int, int64_t)':
xineDevice.c:1387: error: cannot call member function 'int 
cRemux::ScanVideoPacket(const uchar*, int, int, uchar&)' without object
xineDevice.c: In function 'bool PluginXine::getPTS(const uchar*, int, int64_t&, 
bool, bool, double&, double&, double&, double&, double*)':
xineDevice.c:2017: error: cannot call member function 'int 
cRemux::ScanVideoPacket(const uchar*, int, int, uchar&)' without object
make[1]: *** [xineDevice.o] Error 1

Is there any solution?
Please help me.

Regards,
AK
  
Petri Helin Aug. 30, 2007, 5:44 p.m. UTC | #10
Reinhard Nissl wrote:
> Hi,
> 
> Reinhard Nissl wrote:
> 
>> The line will write the PES packet's content into file
>> /video/sample.es.h264 when a h264parser exists. Then please send me some
>> MB of the file.
> 
> The file you've sent me doesn't contain any useful data. You can have a
> look at it yourself:
> 
> od -Ax -t x1 -v sample2.es.h264 | less -S
> 
> You need to find at least the sequence 00 00 01. Otherwise it's garbage.
> 
> I'll go to bed soon, so here's a quick description how to go on:
> 
> - add this function to cRepacker
>   virtual void LogTS(const uint8_t *Buf) {}
> - add this function to cVideoRepacker
>   virtual void LogTS(const uint8_t *Buf) { if (h264parser) { static FILE
> *f = fopen("/video/sample.ts", "wb"); fwrite(Buf, 1, 188, f); fflush(f); } }
> - change this area in ts_to_pes() like that:
> 
> void cTS2PES::ts_to_pes(const uint8_t *Buf) // don't need count (=188)
> {
>   if (!Buf)
>      return;
> if (repacker) repacker->LogTS(Buf);
>   if (Buf[1] & TS_ERROR)
> 
> Be careful to just have a single cVideoRepacker instance write into this
> file, i. e. either activate transfer mode on this channel or make a
> recording on this channel but not both at the same time.
> 
> Have a look at this file with
> 
> od -Ax -t x1 -v -w188 sample.ts | less -S
> 
> and locate the sequence 00 00 01 multiple times. It should then be
> possible to record this channel although it doesn't work for now, as
> cVideoRepacker didn't find any startcode (00 00 01) in the
> sample.es.h264 from above.
> 
> Bye.

I have now tested when there is a program running (I am even seeing the 
dvb-subtitles with xineliboutput), but still there are no "00 00 01" 
series in the sample.ts. Anything more I could test with?

-Petri
  
Hannu Tirkkonen Aug. 30, 2007, 6:13 p.m. UTC | #11
On Thu, Aug 30, 2007 at 08:44:27PM +0300, Petri Helin wrote:
> I have now tested when there is a program running (I am even seeing the 
> dvb-subtitles with xineliboutput), but still there are no "00 00 01" 
> series in the sample.ts. Anything more I could test with?

I lost the stream also today. The subtitles were visible, but no sound.
vlc of course did not got anything to show.

After a several (10 - 15) try I did manage to tune to CD channel and got 
sound also using xineliboutput. After getting the sound I did try vlc
and got stream also. 

There is some problems on tuning or encrypting hd channels. Because I do 
have only budget cards without cams, my canal+ card is on my dbox2 and 
I'm using xx plugin to access the card. 

...hanu
  
Petri Helin Aug. 30, 2007, 6:29 p.m. UTC | #12
Hannu Tirkkonen wrote:
> There is some problems on tuning or encrypting hd channels. 

Everything worked without problems when they used mpeg2 on Canal+ HD.

-Petri
  
Reinhard Nissl Aug. 30, 2007, 8:13 p.m. UTC | #13
Hi,

Petri Helin wrote:

> I have now tested when there is a program running (I am even seeing the 
> dvb-subtitles with xineliboutput), but still there are no "00 00 01" 
> series in the sample.ts. Anything more I could test with?

I'm sorry, I can't help you any further. Try to get a correctly
decrypted TS first, then it should work out of the box.

When you have a look at the first sample.ts you've sent me with this command

od -Ax -t x1 -v -w188 sample.ts | less -S

then you can find the sequence 00 00 01 09 which is a H.264 access unit
delimiter. So it once must have worked to get a properly decrypted TS.

Bye.
  
Petri Helin Aug. 30, 2007, 8:24 p.m. UTC | #14
Reinhard Nissl wrote:
> Hi,
> 
> Reinhard Nissl wrote:
> 
> Have a look at this file with
> 
> od -Ax -t x1 -v -w188 sample.ts | less -S
> 
> and locate the sequence 00 00 01 multiple times. It should then be
> possible to record this channel although it doesn't work for now, as
> cVideoRepacker didn't find any startcode (00 00 01) in the
> sample.es.h264 from above.
> 
> Bye.

I tried again by using streamdev-plugin to send TS-stream to a vlc 
client, which I set to dump the TS-stream. In the dumped stream I can 
find the "00 00 01" start codes.

-Petri
  
Petri Helin Aug. 30, 2007, 9:05 p.m. UTC | #15
Reinhard Nissl wrote:
> Hi,
> 
> Petri Helin wrote:
> 
>> I have now tested when there is a program running (I am even seeing the 
>> dvb-subtitles with xineliboutput), but still there are no "00 00 01" 
>> series in the sample.ts. Anything more I could test with?
> 
> I'm sorry, I can't help you any further. Try to get a correctly
> decrypted TS first, then it should work out of the box.
> 
> When you have a look at the first sample.ts you've sent me with this command
> 
> od -Ax -t x1 -v -w188 sample.ts | less -S
> 
> then you can find the sequence 00 00 01 09 which is a H.264 access unit
> delimiter. So it once must have worked to get a properly decrypted TS.
> 
> Bye.


When I tried again with streamdev-plugin sending TS-stream to a vlc 
client and letting it dump the TS-stream, I can find the "00 00 01 09" 
delimiter in the dumped stream. So if it works with the combination 
above, what could be missing from VDR itself that prevents it from doing 
the same?

-Petri
  
Hannu Tirkkonen Aug. 30, 2007, 9:15 p.m. UTC | #16
On Thu, Aug 30, 2007 at 12:05:08AM +0300, Hannu Tirkkonen wrote:
> I did apply this h264 patch and streamdev patch from: 
> http://www.vdr-developer.org/mantisbt/view.php?id=382
> 
> Now the load of the server is low when tuned to Canal+ HD and I can watch the stream using vlc.
> The recording at least outputs something to hard disk ;)

Well... the video part of the recordings seems to be corrupted.
vlc cannot show any video; there's only audio.

projectx says (hundreds of lines on 34MB recording):
!> error in pes_extension of pes-ID 0xBD @ pos: 112153 (1554 / 14 / 15 / true / false)
-> found PES-ID 0xBD (private stream 1) @ 112153
!> error in pes_extension of pes-ID 0xE0 @ pos: 134640 (2048 / 14 / 15 / true / false)
!> error in pes_extension of pes-ID 0xE0 @ pos: 188715 (2048 / 14 / 15 / true / false)
!> error in pes_extension of pes-ID 0xE0 @ pos: 247087 (2048 / 19 / 20 / true / false)
....
-> more than 500 warnings/errors, stop logging..
-> dropping video data, GOP larger than 6MB
-> dropping video data, GOP larger than 6MB

od does find 00 00 01 09 sequences from the file.

The live stream can be watched with vlc, and saving 
the stream with vlc creates a file that can be watched again with mplayer or vlc.

There is 34MB of the recording on http://hotel.hanu.com/~hanu/h264

...hanu
  
Hannu Tirkkonen Aug. 30, 2007, 9:34 p.m. UTC | #17
On Fri, Aug 31, 2007 at 12:05:12AM +0300, Petri Helin wrote:
> 
> When I tried again with streamdev-plugin sending TS-stream to a vlc 
> client and letting it dump the TS-stream, I can find the "00 00 01 09" 
> delimiter in the dumped stream. So if it works with the combination 
> above, what could be missing from VDR itself that prevents it from doing 
> the same?

Maybe there is something to do with the Welho's way of broadcasting
the Canal+ HD dvb-s2 stream again in dvb-c?

I do have a subscription also on Thor 1W, so I'll try to do some
tests using dvb-s2 during the weekend.

(The dish splitter is on another room, so there can be some
waf negotiations during the weekend ;)) 

..hanu
  
Jose Alberto Reguero Aug. 30, 2007, 9:59 p.m. UTC | #18
El Jueves, 30 de Agosto de 2007, Hannu Tirkkonen escribió:
> On Thu, Aug 30, 2007 at 12:05:08AM +0300, Hannu Tirkkonen wrote:
> > I did apply this h264 patch and streamdev patch from:
> > http://www.vdr-developer.org/mantisbt/view.php?id=382
> >
> > Now the load of the server is low when tuned to Canal+ HD and I can watch
> > the stream using vlc. The recording at least outputs something to hard
> > disk ;)
>
> Well... the video part of the recordings seems to be corrupted.
> vlc cannot show any video; there's only audio.
>
> projectx says (hundreds of lines on 34MB recording):
> !> error in pes_extension of pes-ID 0xBD @ pos: 112153 (1554 / 14 / 15 /
> true / false) -> found PES-ID 0xBD (private stream 1) @ 112153
> !> error in pes_extension of pes-ID 0xE0 @ pos: 134640 (2048 / 14 / 15 /
> true / false) !> error in pes_extension of pes-ID 0xE0 @ pos: 188715 (2048
> / 14 / 15 / true / false) !> error in pes_extension of pes-ID 0xE0 @ pos:
> 247087 (2048 / 19 / 20 / true / false) ....

I have this errors also with the ttxtsubs .They are not important in mpeg-2 
streams. Perhaps ttxtsubs corupts the mpeg-4 stream.

Jose Alberto

> -> more than 500 warnings/errors, stop logging..
> -> dropping video data, GOP larger than 6MB
> -> dropping video data, GOP larger than 6MB
>
> od does find 00 00 01 09 sequences from the file.
>
> The live stream can be watched with vlc, and saving
> the stream with vlc creates a file that can be watched again with mplayer
> or vlc.
>
> There is 34MB of the recording on http://hotel.hanu.com/~hanu/h264
>
> ...hanu
>
> _______________________________________________
> vdr mailing list
> vdr@linuxtv.org
> http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr
  
Reinhard Nissl Aug. 30, 2007, 10:05 p.m. UTC | #19
Hi,

Arthur Konovalov wrote:

> I trying to compile vdr-1.5.9 with h264 patches but vdr-xine-0.7.10 plugin give 
> me error:
> 
> xineDevice.c: In member function 'int PluginXine::cXineDevice::PlayCommon3(const 
> uchar*, int, int64_t)':
> xineDevice.c:1387: error: cannot call member function 'int 
> cRemux::ScanVideoPacket(const uchar*, int, int, uchar&)' without object
> xineDevice.c: In function 'bool PluginXine::getPTS(const uchar*, int, int64_t&, 
> bool, bool, double&, double&, double&, double&, double*)':
> xineDevice.c:2017: error: cannot call member function 'int 
> cRemux::ScanVideoPacket(const uchar*, int, int, uchar&)' without object
> make[1]: *** [xineDevice.o] Error 1
> 
> Is there any solution?

Use vdr-xine-0.7.11 please.

Bye.
  
Reinhard Nissl Aug. 30, 2007, 10:09 p.m. UTC | #20
Hi,

Hannu Tirkkonen wrote:

> Well... the video part of the recordings seems to be corrupted.
> vlc cannot show any video; there's only audio.
> 
> projectx says (hundreds of lines on 34MB recording):
> !> error in pes_extension of pes-ID 0xBD @ pos: 112153 (1554 / 14 / 15 / true / false)
> -> found PES-ID 0xBD (private stream 1) @ 112153
> !> error in pes_extension of pes-ID 0xE0 @ pos: 134640 (2048 / 14 / 15 / true / false)
> !> error in pes_extension of pes-ID 0xE0 @ pos: 188715 (2048 / 14 / 15 / true / false)
> !> error in pes_extension of pes-ID 0xE0 @ pos: 247087 (2048 / 19 / 20 / true / false)
> ....
> -> more than 500 warnings/errors, stop logging..
> -> dropping video data, GOP larger than 6MB
> -> dropping video data, GOP larger than 6MB

ProjectX doesn't understand H.264. It assumes MPEG2 and therefore sees
an overfull GOP.

> od does find 00 00 01 09 sequences from the file.
> 
> The live stream can be watched with vlc, and saving 
> the stream with vlc creates a file that can be watched again with mplayer or vlc.
> 
> There is 34MB of the recording on http://hotel.hanu.com/~hanu/h264

Plays perfectly here with vdr-xine-0.7.11 and xine-lib-cvs from my
homepage + vdr-xine's xine-lib.patch. If I play it in slow motion, my PC
is fast enough to decode and display all frames.

Bye.
  
Reinhard Nissl Aug. 30, 2007, 10:18 p.m. UTC | #21
Hi,

Hannu Tirkkonen wrote:

>> When I tried again with streamdev-plugin sending TS-stream to a vlc 
>> client and letting it dump the TS-stream, I can find the "00 00 01 09" 
>> delimiter in the dumped stream. So if it works with the combination 
>> above, what could be missing from VDR itself that prevents it from doing 
>> the same?
> 
> Maybe there is something to do with the Welho's way of broadcasting
> the Canal+ HD dvb-s2 stream again in dvb-c?
> 
> I do have a subscription also on Thor 1W, so I'll try to do some
> tests using dvb-s2 during the weekend.

Please keep in mind, that my patch doesn't add DVB-S2 support.

Bye.
  
Petri Helin Aug. 31, 2007, 9:32 a.m. UTC | #22
On 8/29/07, Reinhard Nissl <rnissl@gmx.de> wrote:
> Hi,
>
> the attached vdr-1.5.9-h264.patch adds H.264 support to VDR's remuxer.
>
> These changes should make VDR ready for the upcoming IFA fair in regard
> to the broadcasts on the temporary channel EinsFestival HD.
>

Referring to the problems I've had with this patch, I'd like to know
if the reason was that the channel I'm trying to watch/record is
encrypted. Have you had chance to test this with an encrypted channel?
Or is that out of the question and the reason is something else?

-Petri
  
Reinhard Nissl Aug. 31, 2007, 6:24 p.m. UTC | #23
Hi,

Petri Helin wrote:

>> the attached vdr-1.5.9-h264.patch adds H.264 support to VDR's remuxer.
>>
>> These changes should make VDR ready for the upcoming IFA fair in regard
>> to the broadcasts on the temporary channel EinsFestival HD.
> 
> Referring to the problems I've had with this patch, I'd like to know
> if the reason was that the channel I'm trying to watch/record is
> encrypted. Have you had chance to test this with an encrypted channel?

No, I didn't have a chance to test this.

> Or is that out of the question and the reason is something else?

One part of my patch adds some functionality to cVideoRepacker and
therefore has no influence on the TS level.

But another part modifies VPID to transport the information that this
channel uses H.264. This is done by adding 10000 to the normal VPID
which is in the range 0..8191. The decimal offset 10000 was chosen over
the hex offset 0x10000 as the real VPID should still be recognizable in
channels.conf without using a calculator.

The drawback is, that the decimal offset isn't simply clipped away by
assigning the patched VPID for example to a variable of type short or
when masking it with 0x1fff. Therefore it is necessary to add some
special clipping code at each location where the patched VPID is entered
into some data structure which is then given to DVB API functions.

So, there is the chance that this clipping is missing at a location
where the VPID is scheduled for decrypting. This could be the reason why
the video TS packets do not get decrypted.

But I don't understand why streamdev still delivers a decrypted video
stream in that case. Can it be that the client asks streamdev to filter
certain TS packets and therefore uses the correct VPID?

Bye.
  
Petri Hintukainen Aug. 31, 2007, 6:34 p.m. UTC | #24
Reinhard Nissl wrote:
> But I don't understand why streamdev still delivers a decrypted video
> stream in that case. Can it be that the client asks streamdev to filter
> certain TS packets and therefore uses the correct VPID?

Yes. In http streaming mode streamdev parses PIDs directly from PMT and
does not use VDR channel data. But the VDR<->VDR streaming mode probably
does not work if PIDs are not "real" ones.


- Petri
  

Patch

--- ./dvbplayer.c	2007-04-28 16:55:22.000000000 +0200
+++ ../vdr-1.5.9/./dvbplayer.c	2007-08-28 22:25:08.000000000 +0200
@@ -182,8 +182,8 @@  bool cNonBlockingFileReader::WaitForData
 
 #define PLAYERBUFSIZE  MEGABYTE(1)
 
-// The number of frames to back up when resuming an interrupted replay session:
-#define RESUMEBACKUP (10 * FRAMESPERSEC)
+// The number of seconds to back up when resuming an interrupted replay session:
+#define RESUMEBACKUP 10
 
 class cDvbPlayer : public cPlayer, cThread {
 private:
@@ -196,6 +196,7 @@  private:
   cFileName *fileName;
   cIndexFile *index;
   cUnbufferedFile *replayFile;
+  int framesPerSec;
   bool eof;
   bool firstPacket;
   ePlayModes playMode;
@@ -225,6 +226,7 @@  public:
   void Goto(int Position, bool Still = false);
   virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
   virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed);
+  int GetFramesPerSec(void) { return framesPerSec; }
   };
 
 #define MAX_VIDEO_SLOWMOTION 63 // max. arg to pass to VIDEO_SLOWMOTION // TODO is this value correct?
@@ -253,6 +255,7 @@  cDvbPlayer::cDvbPlayer(const char *FileN
   replayFile = fileName->Open();
   if (!replayFile)
      return;
+  framesPerSec = replayFile->GetFramesPerSec();
   ringBuffer = new cRingBufferFrame(PLAYERBUFSIZE);
   // Create the index file:
   index = new cIndexFile(FileName, false);
@@ -341,7 +344,7 @@  bool cDvbPlayer::Save(void)
   if (index) {
      int Index = writeIndex;
      if (Index >= 0) {
-        Index -= RESUMEBACKUP;
+        Index -= RESUMEBACKUP * GetFramesPerSec();
         if (Index > 0)
            Index = index->GetNextIFrame(Index, false);
         else
@@ -371,7 +374,7 @@  void cDvbPlayer::Action(void)
 
   readIndex = Resume();
   if (readIndex >= 0)
-     isyslog("resuming replay at index %d (%s)", readIndex, *IndexToHMSF(readIndex, true));
+     isyslog("resuming replay at index %d (%s)", readIndex, *IndexToHMSF(readIndex, true, GetFramesPerSec()));
 
   nonBlockingFileReader = new cNonBlockingFileReader;
   int Length = 0;
@@ -667,7 +670,7 @@  void cDvbPlayer::SkipSeconds(int Seconds
      Empty();
      int Index = writeIndex;
      if (Index >= 0) {
-        Index = max(Index + Seconds * FRAMESPERSEC, 0);
+        Index = max(Index + Seconds * GetFramesPerSec(), 0);
         if (Index > 0)
            Index = index->GetNextIFrame(Index, false, NULL, NULL, NULL, true);
         if (Index >= 0)
@@ -834,3 +838,10 @@  void cDvbPlayerControl::Goto(int Positio
   if (player)
      player->Goto(Position, Still);
 }
+
+int cDvbPlayerControl::GetFramesPerSec()
+{
+  if (player)
+     return player->GetFramesPerSec();
+  return FRAMESPERSEC;
+}
--- ./dvbplayer.h	2002-06-23 12:13:51.000000000 +0200
+++ ../vdr-1.5.9/./dvbplayer.h	2007-08-28 22:25:08.000000000 +0200
@@ -54,6 +54,8 @@  public:
   void Goto(int Index, bool Still = false);
        // Positions to the given index and displays that frame as a still picture
        // if Still is true.
+  int GetFramesPerSec();
+       // Returns the number of frames per second for the current recording.
   };
 
 #endif //__DVBPLAYER_H
--- ./menu.c	2007-08-24 15:15:48.000000000 +0200
+++ ../vdr-1.5.9/./menu.c	2007-08-28 22:25:08.000000000 +0200
@@ -4014,7 +4026,7 @@  bool cReplayControl::ShowProgress(bool I
         lastCurrent = lastTotal = -1;
         }
      if (Total != lastTotal) {
-        displayReplay->SetTotal(IndexToHMSF(Total));
+        displayReplay->SetTotal(IndexToHMSF(Total, false, GetFramesPerSec()));
         if (!Initial)
            displayReplay->Flush();
         }
@@ -4022,7 +4034,7 @@  bool cReplayControl::ShowProgress(bool I
         displayReplay->SetProgress(Current, Total);
         if (!Initial)
            displayReplay->Flush();
-        displayReplay->SetCurrent(IndexToHMSF(Current, displayFrames));
+        displayReplay->SetCurrent(IndexToHMSF(Current, displayFrames, GetFramesPerSec()));
         displayReplay->Flush();
         lastCurrent = Current;
         }
@@ -4055,8 +4067,8 @@  void cReplayControl::TimeSearchProcess(e
 {
 #define STAY_SECONDS_OFF_END 10
   int Seconds = (timeSearchTime >> 24) * 36000 + ((timeSearchTime & 0x00FF0000) >> 16) * 3600 + ((timeSearchTime & 0x0000FF00) >> 8) * 600 + (timeSearchTime & 0x000000FF) * 60;
-  int Current = (lastCurrent / FRAMESPERSEC);
-  int Total = (lastTotal / FRAMESPERSEC);
+  int Current = (lastCurrent / GetFramesPerSec());
+  int Total = (lastTotal / GetFramesPerSec());
   switch (Key) {
     case k0 ... k9:
          if (timeSearchPos < 4) {
@@ -4083,7 +4095,7 @@  void cReplayControl::TimeSearchProcess(e
     case kDown:
     case kOk:
          Seconds = min(Total - STAY_SECONDS_OFF_END, Seconds);
-         Goto(Seconds * FRAMESPERSEC, Key == kDown || Key == kPause || Key == kOk);
+         Goto(Seconds * GetFramesPerSec(), Key == kDown || Key == kPause || Key == kOk);
          timeSearchActive = false;
          break;
     default:
@@ -4204,7 +4216,7 @@  void cReplayControl::EditTest(void)
         if ((m->Index() & 0x01) != 0)
            m = marks.Next(m);
         if (m) {
-           Goto(m->position - SecondsToFrames(3));
+           Goto(m->position - SecondsToFrames(3, GetFramesPerSec()));
            Play();
            }
         }
--- ./recording.c	2007-06-17 15:10:12.000000000 +0200
+++ ../vdr-1.5.9/./recording.c	2007-08-28 22:25:08.000000000 +0200
@@ -1481,11 +1481,11 @@  cUnbufferedFile *cFileName::NextFile(voi
 
 // --- Index stuff -----------------------------------------------------------
 
-cString IndexToHMSF(int Index, bool WithFrame)
+cString IndexToHMSF(int Index, bool WithFrame, int FramesPerSec)
 {
   char buffer[16];
-  int f = (Index % FRAMESPERSEC) + 1;
-  int s = (Index / FRAMESPERSEC);
+  int f = (Index % FramesPerSec) + 1;
+  int s = (Index / FramesPerSec);
   int m = s / 60 % 60;
   int h = s / 3600;
   s %= 60;
@@ -1493,17 +1493,17 @@  cString IndexToHMSF(int Index, bool With
   return buffer;
 }
 
-int HMSFToIndex(const char *HMSF)
+int HMSFToIndex(const char *HMSF, int FramesPerSec)
 {
   int h, m, s, f = 0;
   if (3 <= sscanf(HMSF, "%d:%d:%d.%d", &h, &m, &s, &f))
-     return (h * 3600 + m * 60 + s) * FRAMESPERSEC + f - 1;
+     return (h * 3600 + m * 60 + s) * FramesPerSec + f - 1;
   return 0;
 }
 
-int SecondsToFrames(int Seconds)
+int SecondsToFrames(int Seconds, int FramesPerSec)
 {
-  return Seconds * FRAMESPERSEC;
+  return Seconds * FramesPerSec;
 }
 
 // --- ReadFrame -------------------------------------------------------------
--- ./recording.h	2007-06-17 14:53:05.000000000 +0200
+++ ../vdr-1.5.9/./recording.h	2007-08-28 22:25:08.000000000 +0200
@@ -233,11 +233,11 @@  public:
   cUnbufferedFile *NextFile(void);
   };
 
-cString IndexToHMSF(int Index, bool WithFrame = false);
+cString IndexToHMSF(int Index, bool WithFrame = false, int FramesPerSec = FRAMESPERSEC);
       // Converts the given index to a string, optionally containing the frame number.
-int HMSFToIndex(const char *HMSF);
+int HMSFToIndex(const char *HMSF, int FramesPerSec = FRAMESPERSEC);
       // Converts the given string (format: "hh:mm:ss.ff") to an index.
-int SecondsToFrames(int Seconds); //XXX+ ->player???
+int SecondsToFrames(int Seconds, int FramesPerSec = FRAMESPERSEC); //XXX+ ->player???
       // Returns the number of frames corresponding to the given number of seconds.
 
 int ReadFrame(cUnbufferedFile *f, uchar *b, int Length, int Max);
--- ./svdrp.c	2007-08-25 11:28:26.000000000 +0200
+++ ../vdr-1.5.9/./svdrp.c	2007-08-28 22:25:08.000000000 +0200
@@ -1297,8 +1297,10 @@  void cSVDRP::CmdPLAY(const char *Option)
                  int x = sscanf(option, "%d:%d:%d.%d", &h, &m, &s, &f);
                  if (x == 1)
                     pos = h;
-                 else if (x >= 3)
-                    pos = (h * 3600 + m * 60 + s) * FRAMESPERSEC + f - 1;
+                 else if (x >= 3) {
+                    int FramesPerSec = cUnbufferedFile::GetFramesPerSec(recording->FileName());
+                    pos = (h * 3600 + m * 60 + s) * FramesPerSec + f - 1;
+                    }
                  }
               cResumeFile resume(recording->FileName());
               if (pos <= 0)
--- ./tools.c	2007-08-05 14:18:15.000000000 +0200
+++ ../vdr-1.5.9/./tools.c	2007-08-28 23:27:37.000000000 +0200
@@ -27,6 +27,8 @@  extern "C" {
 #include <utime.h>
 #include "i18n.h"
 #include "thread.h"
+#include "remux.h"
+#include "recording.h"
 
 int SysLogLevel = 3;
 
@@ -1566,6 +1568,112 @@  cUnbufferedFile *cUnbufferedFile::Create
   return File;
 }
 
+int cUnbufferedFile::GetFramesPerSec(const char *FileName)
+{
+  // use this constant as a fallback value
+  int FramesPerSec = FRAMESPERSEC;
+  // open the file an determine frames per second
+  cFileName fn(FileName, false);
+  cUnbufferedFile *f = fn.Open();
+  if (f) {
+     FramesPerSec = f->GetFramesPerSec();
+     fn.Close();
+     }
+  return FramesPerSec;
+}
+
+#define ADD_H264_SUPPORT 1
+
+#ifdef ADD_H264_SUPPORT
+#include "h264parser.h"
+#endif
+
+int cUnbufferedFile::GetFramesPerSec(void)
+{
+  // use this constant as a fallback value
+  int FramesPerSec = FRAMESPERSEC;
+  // rember current file position to restore later
+  off_t OrigPos = curpos;
+  // seek to the beginning and read a chunk of data
+  if (0 == Seek(0, SEEK_SET)) {
+     uchar Data[2048];
+     ssize_t Count = Read(Data, sizeof(Data));
+     if (Count > 0) {
+        // this chunk of data should actually be a PES packet
+        uchar *Limit = Data + Count;
+        int PesPayloadOffset = 0;
+        if (AnalyzePesHeader(Data, Count, PesPayloadOffset) == phMPEG2) {
+           // we need a video stream -- radio recordings use the default
+           if ((Data[3] & 0xF0) == 0xE0) {
+              uchar *p = Data + PesPayloadOffset;
+#ifdef ADD_H264_SUPPORT
+              // check whether this is a H.264 video frame
+              if (cRemux::IsFrameH264(Data, Count)) {
+                 // need to have a H264 parser since picture timing is rather complex
+                 H264::cParser H264parser(false);
+                 // send NAL units to parser until it is able to provide frames per second
+                 while (p < Limit) {
+                       // find next NAL unit
+                       uchar *pNext = (uchar *)memmem(p + 4, Limit - (p + 4), "\x00\x00\x01", 3);
+                       if (!pNext) // just pass the remainder
+                          pNext = Limit; 
+                       H264parser.PutNalUnitData(p, pNext - p);
+                       // process NAL unit and check for frames per second
+                       H264parser.Process();
+                       int FPS = H264parser.Context().GetFramesPerSec();
+                       if (FPS != -1) { // there we are ;-)
+                          FramesPerSec = FPS;
+fprintf(stderr, "FramesPerSec: %d\n", FramesPerSec);
+                          break;
+                          }
+                       // continue with next NAL unit
+                       p = pNext;   
+                       }
+                 }
+              else {
+#endif
+                 // thanks to cVideoRepacker, the payload starts with a sequence header
+                 if (p + 12 <= Limit) {
+                    if (p[0] == 0x00 && p[1] == 0x00 && p[2] == 0x01 && p[3] == 0xB3) {
+                       uint32_t frame_rate_code = p[7] & 0x0F;
+                       uint32_t frame_rate_extension_n = 0;
+                       uint32_t frame_rate_extension_d = 0;
+                       // now we need to have a look at the next startcode, 
+                       // as it might be a sequence extension
+                       p = (uchar *)memmem(p + 12, Limit - (p + 12), "\x00\x00\x01", 3);
+                       if (p && p + 4 < Limit && p[3] == 0xB5) { // extension start code
+                          if (p + 5 < Limit && (p[4] >> 4) == 0x1) { // sequence extension
+                             if (p + 10 < Limit) {
+                                frame_rate_extension_n = (p[9] & 0x60) >> 5;
+                                frame_rate_extension_d = (p[9] & 0x1F);
+                                }
+                             }
+                          }
+                       // calculate frame rate and round it for compatibility
+                       if (0x1 <= frame_rate_code && frame_rate_code <= 0x8) {
+                          static const int n[] = { -1, 24000, 24, 25, 30000, 30, 50, 60000, 60 };
+                          static const int d[] = { -1,  1001,  1,  1,  1001,  1,  1,  1001,  1 };
+                          double frame_rate = n[frame_rate_code] * (frame_rate_extension_n + 1) 
+                                   / (double)(d[frame_rate_code] * (frame_rate_extension_d + 1));
+                          FramesPerSec = (int)frame_rate;
+                          if (frame_rate - FramesPerSec > 0.5)
+                             FramesPerSec++;
+fprintf(stderr, "FramesPerSec: %d\n", FramesPerSec);
+                          }
+                       }
+                    }
+#ifdef ADD_H264_SUPPORT
+                 }
+#endif
+              }
+           }
+        }
+     }
+  // restore original position
+  Seek(OrigPos, SEEK_SET);
+  return FramesPerSec;
+}
+
 // --- cLockFile -------------------------------------------------------------
 
 #define LOCKFILENAME      ".lock-vdr"
--- ./tools.h	2007-08-25 16:16:39.000000000 +0200
+++ ../vdr-1.5.9/./tools.h	2007-08-28 22:25:08.000000000 +0200
@@ -349,6 +349,8 @@  public:
   ssize_t Read(void *Data, size_t Size);
   ssize_t Write(const void *Data, size_t Size);
   static cUnbufferedFile *Create(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE);
+  static int GetFramesPerSec(const char *FileName);
+  int GetFramesPerSec(void);
   };
 
 class cLockFile {