Monday, 6 June 2011

Objective C - NSUserDefaults - add in support for default values

There may be times when coding in Objective C, for iOS, that you wish to retrieve user settings values, but also specify a default value to return if the setting is not found.

This approach is particularly useful when a user may have upgraded your app, so settings that were previously undefined are now attempted to be retrieved.

A few carefully written methods should get you on track. The fiddly bit is the lack of support for a [[NSUserDefault standardUserDefaults] keyExistsWithName:...] function, but this can be worked around using the objectForKey method, which returns nil if a key is not found:


// Default handling

- (BOOL) boolOrDefaultForKey:(NSString *)keyName withDefault:(BOOL)defaultValue

{

if ([self keyExists:keyName])

return [[NSUserDefaults standardUserDefaults] boolForKey:keyName];

else

return defaultValue;

}

- (BOOL) integerOrDefaultForKey:(NSString *)keyName withDefault:(BOOL)defaultValue

{

if ([self keyExists:keyName])

return [[NSUserDefaults standardUserDefaults] integerForKey:keyName];

else

return defaultValue;

}

- (BOOL) keyExists:(NSString *) keyName

{

return ([[NSUserDefaults standardUserDefaults] objectForKey:keyName] != nil);

}

Saturday, 4 June 2011

More tips on using a MediaStreamSource with H264 video

I've recently blogged a little about parsing H264/AAC video and audio streams and passsing the individual samples to Silverlight's native decoder. (using MediaStreamSource class)

Here are some more observations:
  • Silverlight expects frames in Dts (decoding) order, not presentation order.
  • If using HE-AAC audio, you must set the number of channels to 1. Two or more channels are not suported; thanks to anonymous commenter for this information.
  • Access unit delimiters seem to be optional; they are stripped out by the decoder. I send them anyway, but it doesn't seem to make a difference.
  • Your stream will probably contain 'Emulation prevention three byte' codes. I don't think you need to strip these out; it seems to make no difference if you pass them to the Silverlight decoder; my guess is that it searches for, and strips out the codes.

You can see the parsing working successfully in SilverLive, my HTTP Live Streaming client for Silverlight.

How to obtain timestamp information from your H264 stream (inside an Mpeg1 transport stream)

Some more information on parsing an H264 video stream to pass the individual NAL units to Silverlight's in-built decoder:

In my last blog post, I suggested incrementing the timestamp for each NAL picture frame. However, this technique isn't reliable since it relies on knowing the frame rate in advance and this isn't always available within an H264 stream. (H264 has no knowledge of frame rate as standard, although this info can be optionally included in Sequence Parameter Set units)

Therefore, I would suggest a better technique for obtaining timestamp information when decoding H264 video frames: Simply get your timestamps from the PES headers of the transport stream itself.

Apple's documentation relating to HTTP Live Streaming suggests that NAL picture frames (i.e. NAL units types 1-5) should be in 'unique PES packets'. This makes a lot of sense, since it means that the Transport Stream can then be used as a single reliable source of timestamps.

Use a decoding loop as follows when parsing an H264 byte stream: (assuming you already have code in place to demux the transport stream container)

  • PES header encountered.
  • Store the PTS/DTS from the PES header.
  • Parse the PES stream for NAL units.
  • Generate a MediaStreamSample correponding to each NAL unit encountered within the stream, timestamping it with the stored Dts (if available, or use Pts) values.
  • If you encounter more than one NAL picture frame within the PES, it is an invalid stream. (you could try to guess the timestamp)
  • PES header encountered; update your stored timestamp.
  • Continue in this fashion until you reach the end of the stream

Monday, 30 May 2011

The curious case of the P8P67 Pro and resuming from sleep

I recently upgraded my development PC to an i7-2600k based setup, based on an Asus P8P67 Pro motherboard. Throw in a new OCZ Vertex 3 SSD, overclock to 4.3GHz and it's blazingly fast.

However, whenever the system awoke from sleep, there would be no video output - frustrating to say the least. The only way to resume was a hard reset of the entire system.

I eventually tracked this problem down to an obscure setting in the BIOS related to the overclocking - 'Internal PLL Overvoltage'. Not exactly something you would imagine would be related to ACPI or sleep settings.

Disabled this setting fixed the problem for me - thanks to the overclockers forum for the tip-off.

Sunday, 1 May 2011

Silverlight's MediaStreamSource - Some Initial Thoughts

I've recently had cause to begin working with the MediaStreamSource element in Silverlight, in order to create an HTTP Live Streaming client.

Unfortunately, while there is some documentation on the matter, the actual quirks and details of the implementation are very poorly documented, leaving many developers resorting to trial and error to get things working.

My main goal was to demux MPEG-2 transport streams into H264/MP3 A/V streams, and then feed the frames/samples from these back to a MediaElement.

It's been frustrating to say the least, but I'm 90% of the way there now. If I get some more time, I'd really love to blog about the experience to help other developers. Some very initial observations:

  • When you send H264 video from a MediaStreamSource, you should send one NAL unit back to the MediaElement for each GetSampleAsync() request.
  • This includes non-picture NAL units, e.g. SPS / PPS units.
  • When you send your NAL units, ensure there are 3-byte start codes (0x00 0x00 0x01) at the beginning of each one. (This is similar to 'Annex B' format, but not quite the same thing)
  • In ReportOpenMediaCompleted(), when setting up your video stream description, you can ignore the CodecPrivateData attribute string, despite what the documentation says. It's not required. (assuming your stream of NAL units includes SPS and PPS units)
  • In ReportGetSampleCompleted(), set the value of 'Offset' equal to the beginning of the NAL start code, not the actual data. (in most cases this will be zero, assuming you use a fresh stream per NAL unit)
  • Remember to increase the time stamp when sending each NAL unit that represents a frame.

That's all I have time for right now - one final caveat; if you're feeding audio data back too, I had problems using a 48kbps sample rate; the MediaElement asked for one audio sample, then never asked for any more! I eventually found that using a 44.1khz rate produced better results.

Carlos

Friday, 1 April 2011

Why I Will Never Need Amazon Cloud Player

Amazon launched its Cloud Player music service this week, to much fanfare.

But it's not something that I need, nor will I ever need a cloud-based music player. I already have a music library sitting on the Internet, accessible from every computer in the World - it's called my home PC. Not only can I get to my music, I can play my songs, stream my videos and pictures to any browser and any mobile phone, completely free-of-charge.

You can do exactly the same too - I've even written the software and iOS app to get you started; it's called Remote Potato; follow the link for more info.

We all have a piece of the Internet that we already own. Why pay twice?

Sunday, 6 February 2011

GMail - Rich Text Signatures for different accounts

How did I miss this?!

Around 8 months ago, it seems that GMail finally added the ability to set up multiple signatures for all your various email addresses, within one GMail account.

To get started, just visit 'Settings' -> Signatures and take it from there.

Time to finally ditch all those various Browser Extensions...

C