Archive

Archive for December, 2015

Resizing App Preview videos using EasyWMV

iMovie is a simple and intuitive app for creating AppPreview videos, but, what’s really annoying is that it only creates appPreview videos compatible with 4 inch iPhone displays – Like the iPhone 5s ? – really old.

You really need to have videos for the iPhone 6s, and 6 Plus. But before you buy QuickTime Pro, here’s a free way.

EasyWMV’s demo version is limited to 1 minute of video, but that’s fine for App Previews, which are only 30 seconds anyway. Now, you need to fiddle with the settings.

For the iPhone 6 Plus (5.5 inch), I selected Custom size – 1080×1920.

Deselect “Preserve aspect ratio”

Drop the bit rate down below 1200kbps.

 

Screen Shot 2015-12-19 at 17.31.03

Now for the techy stuff, how I diagnosed this – I uploaded a video with the bit rate too high, and got a vague warning from iTunes Connect. I then looked in inspector for more details and saw this:

{
“statusCode” : 400,
“errorCodes” : [ “MOV_H264_LEVEL_TOO_HIGH”, “MOV_VIDEOCODEC_NOT_ACCEPTABLE_FOR_VIDEOTYPE” ],
“suggestionCode” : “MOV_RESAVE_LOWER_LEVEL”,
“nonLocalizedMessage” : “H264 Level is too high. Please refer to Apple’s documentation for appropriate levels.”,
“localizedMessage” : “The H264 Level is too high. Please refer to Apple’s documentation for appropriate formats.”
}

Which according to apple, this is the maximum specs:

H.264 ProRes 422 HQ only Notes
Target Bit Rate 10-12 Mbps VBR ~220 Mbps

And 12Mbps translates to 12000 Kbps

Then you get this a success in the trace once it works:

{
“responses” : [ {
“url” : “http://a364.phobos.apple.com/us/r30/VideoSource60/v4/0f/8d/42/0f8d42b0-c7a1-3bbc-0fd9-47e6ce27cd4b/pr_source.mp4?downloadKey=1450740609_4e0cd82c5efe91f96becf577bbc3cdc4”,
“token” : “VideoSource60/v4/0f/8d/42/0f8d42b0-c7a1-3bbc-0fd9-47e6ce27cd4b/pr_source.mp4”,
“groupToken” : {
“groupToken” : “VideoSource60/v4/0f/8d/42/0f8d42b0-c7a1-3bbc-0fd9-47e6ce27cd4b”,
“pool” : “VideoSource60”,
“syntaxVersion” : “HASH_MOUNT_UUID_GROUP”
},
“blobString” : “{\”token\”:\”VideoSource60/v4/0f/8d/42/0f8d42b0-c7a1-3bbc-0fd9-47e6ce27cd4b/pr_source.mp4\”,\”type\”:\”MZPurpleSoftwarePromoVideoFileType.SOURCE\”,\”originalFileName\”:\”App Preview webcam-1.mp4\”}”,
“descriptionDoc” : “<?xml version=\”1.0\” encoding=\”UTF-8\” standalone=\”no\”?><!–Generated by the FoghornLeghorn Quicktime MediaDescriptionGenerator, version 1.24–><!–File URL: \”\”–><movie xmlns:ma=\”http://beans.media.leghorn.jingle.apple.com\” codecs=\”avc1.6742C0, mp4a.40.2\” type=\”mpeg4\”><describer><ma:name>FoghornLeghorn MPEG-4 Parser</ma:name><ma:version>1.24</ma:version></describer><clock poster_time=\”0\” preview_duration=\”0\” preview_time=\”0\” time_scale=\”1000\” total_duration=\”22016\”/><tracks><video enabled=\”true\” index=\”0\” type=\”vide\”><track_id>1</track_id><language numeric=\”21956\”>und</language><alternate_group>0</alternate_group><matrix identity=\”true\”/><data_size units=\”bytes\”>2745711</data_size><duration milliseconds=\”21967\” track_duration=\”21967\” units=\”milliseconds\”>21967</duration><edit_list count=\”1\” empties=\”0\” normal_rate=\”true\”><edit_list_entry media_rate=\”1.0\” media_time=\”2\” track_duration=\”21967\”/></edit_list><sample_description_count>1</sample_description_count><duration_statistics mean_duration=\”1.0\” time_scale=\”30\” total_duration=\”659\” uniform=\”true\”/><user_data_atoms/><data_rate units=\”Kb/s\”>976.50415</data_rate><data_rate_statistics units=\”Kb/s\”><peak first_media_DTS=\”99\” last_media_DTS=\”99\”>2719</peak></data_rate_statistics><graphics_mode>copy</graphics_mode><codec name=\”H.264\” type=\”avc1.6742C0\”>avc1</codec><encoded_dimensions><width>1080</width><height>1920</height></encoded_dimensions><display_dimensions><width>1080</width><height>1920</height></display_dimensions><track_dimensions><width>1080</width><height>1920</height></track_dimensions><frame_rate_mode>CFR</frame_rate_mode><frame_rate>30.0</frame_rate><field_dominance>progressive</field_dominance><sample_description><avcC><profile>Baseline</profile><compatability>192</compatability><level>4.0</level><nal_units><picture_parameter_sets><pic_parameter_set entropy_coding_mode_flag=\”0\” pic_parameter_set_id=\”0\” seq_parameter_set_id=\”0\”/></picture_parameter_sets></nal_units><raw_avcc>0142C028FFE1001A6742C028D9004403C797C044000003000400000300F03C60C92001000468CB8CB2</raw_avcc></avcC></sample_description><maximum_sample_size>81858</maximum_sample_size></video><sound enabled=\”true\” index=\”1\” type=\”soun\”><track_id>2</track_id><language numeric=\”5575\”>eng</language><alternate_group>0</alternate_group><matrix identity=\”true\”/><data_size units=\”bytes\”>680375</data_size><duration milliseconds=\”22016\” track_duration=\”22016\” units=\”milliseconds\”>22016</duration><sample_description_count>1</sample_description_count><user_data_atoms/><data_rate units=\”Kb/s\”>241.43484</data_rate><codec name=\”aac \” type=\”mp4a.40.2\”>aac </codec><channel_layout name=\”Stereo (L R)\”><channel name=\”Left\”>L</channel><channel name=\”Right\”>R</channel></channel_layout><sample_rate units=\”kilohertz\”>48.0</sample_rate><bit_depth>16</bit_depth></sound></tracks><matrix identity=\”true\”/><itunes_metadata_atoms><itunes_metadata format=\”UTF-8\” type=\”©too\”>Lavf52.88.0</itunes_metadata></itunes_metadata_atoms><notifications><ma:notification code=\”mediaValidation.data\” level=\”INFO\”><ma:parameters><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.trackType\”>vide</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.dataFormat\”>avc1</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.vendor\”>????</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.temporalQuality\”>0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.spatialQuality\”>0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.width\”>1080</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.height\”>1920</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.hRes\”>72.0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.vRes\”>72.0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.frameCount\”>1</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.compressorName\”/><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.depth\”>24</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.version\”>1</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.profile\”>66</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.compatability\”>192</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.level\”>4.0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.profileIdc\”>66</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.constraintSets\”>c0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.levelIdc\”>40</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.seqParameterSetId\”>0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.log2MaxFrameNum\”>4</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.picOrderCntType\”>2</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.log2MaxPicOrderCountLsb\”>0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.deltaPictureAlwaysZero\”>false</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.offsetForNonrefPic\”>0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.offsetForTopToBottomField\”>0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.numRefFramesInPicorderCntCycle\”>0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.numRefFrames\”>3</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.gapsInFrameNumValueAllowedFlag\”>false</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.picWidthInMbs\”>68</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.picHeightInMapUnits\”>120</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.frameMbsOnly\”>true</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.mbAdaptiveFrameField\”>false</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.direct8x8Inference\”>true</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.frameCrop.left\”>0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.frameCrop.right\”>4</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.frameCrop.top\”>0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.frameCrop.bottom\”>0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.vui.aspectRatio\”>1:1</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.vui.videoSignalType.videoFormat\”>5</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.vui.videoSignalType.videoFullRange\”>false</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.vui.timeInfo.numUnitsInTick\”>1</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.vui.timeInfo.timeScale\”>60</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.vui.timeInfo.fixedFrameRate\”>false</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.vui.bitStreamRestriction.motionVectorsOverPicBoundaries\”>true</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.vui.bitStreamRestriction.maxBytesPerPicDenom\”>0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.vui.bitStreamRestriction.maxBitsPerMbDenom\”>0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.vui.bitStreamRestriction.log2MaxMvLengthHorizontal\”>11</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.vui.bitStreamRestriction.log2MaxMvLengthVertical\”>11</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.vui.bitStreamRestriction.maxNumReorderFrames\”>0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.sps.0.vui.bitStreamRestriction.maxDecFrameBuffering\”>3</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.pps.0.ppsId\”>0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.pps.0.spsId\”>0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.pps.0.entropyCodingMode\”>false</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.pps.0.sliceGroupMapType\”>0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.pps.0.bottomFieldPictureOrderInFramePresent\”>false</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.pps.0.numRefIdx10DefaultActive\”>3</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.pps.0.explicitWeightedPrediction\”>false</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.pps.0.weightedBiPredIdc\”>0</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.pps.0.chromaQpIndexOffset\”>1</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.pps.0.deblockingFilterControlPresent\”>true</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.pps.0.constrainedIntraPrediction\”>false</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.pps.0.redundantPicCountElementPresent\”>false</ma:entry><ma:entry key=\”moov.trak.1.mdia.minf.stbl.stsd.0.avcC.0.pps.0.transform8x8Mode\”>true</ma:entry><ma:entry key=\”moov.trak.2.mdia.minf.stbl.stsd.0.trackType\”>soun</ma:entry><ma:entry key=\”moov.trak.2.mdia.minf.stbl.stsd.0.dataFormat\”>mp4a</ma:entry><ma:entry key=\”moov.trak.2.mdia.minf.stbl.stsd.0.numChannels\”>2</ma:entry><ma:entry key=\”moov.trak.2.mdia.minf.stbl.stsd.0.compressionId\”>0</ma:entry><ma:entry key=\”moov.trak.2.mdia.minf.stbl.stsd.0.sampleRate\”>48000.0</ma:entry><ma:entry key=\”message\”>data</ma:entry></ma:parameters></ma:notification></notifications></movie>”
}
]
}

Categories: Uncategorized

Get #ISO3166 Country code from #IP address in C#

cell-tower

Although an IP address can’t always pinpoint where a user is to the correct city, it’s pretty reliable way of getting the user’s country, and you can tailor the content for that user, i.e. show prices in GBP for UK users, and USD for USD users.

There are plenty of ways of doing this, and many services that provide this service, but this worked well for me in an ASP.NET MVC website

WebClient wc = new WebClient();
var strJson = wc.DownloadString(“http://ipinfo.io/&#8221; + Request.ServerVariables[“REMOTE_ADDR”]);
var ip = Newtonsoft.Json.Linq.JObject.Parse(strJson);
var country = ip[“country”].ToString();

Categories: Uncategorized

WhitehatTwitterFollowers.com : a new way to boost your twitter presence

splash

WhitehatTwitterFollowers.com  is a website that gets you new twitter followers based on your chosen hashtags ; and it’s WhiteHat, which means that there’s nothing untoward about the service.

That means that it’s not a service that get’s you an instant following of 10,000 zombie twitter accounts that all seem to have random twitter handles, and come from Eblonia*, oh, and they all get cancelled by twitter after it discovers that they’ve been created by a bot.

What it does, is uses the Twitter API to automatically favourite hundreds of tweets based on your selected hashtags, and those “favourites”, get you noticed by the authors of the tweets, and we’ve seen ratios typical of 3 new followers per 100 favourites.

So, it’s not an instant win, but a slow burn. But that’s what Whitehat is all about. If you prefer the 10,000 zombie accounts, look elsewhere.

 

*No, Eblonia is not a real place, it’s actually a nod to Dilbert 🙂

Categories: Uncategorized

Google Image Search No Longer Available

About 2 days ago, Google Image Search API was terminated, and attempts to call the API gives an error “No Longer Available”. There is a work around, using the Google Custom Search API, and here’s some code to do it using JQuery.

(You’ll need to get your own key, since it’s limited to 100 queries per day)

function GoogleImageSearch(searchTerm, callback)
{
var params = {};
params.q = searchTerm; // search text
params.num = 1; // integer value range between 1 to 10 including
params.start = 1; // integer value range between 1 to 101, it is like the offset
params.imgSize = “large”; // for image size
params.searchType = “image”; // compulsory
params.fileType = “jpg”; // you can leave these if extension does not matters you
params.key = “xxxxxxx”; // API_KEY got from https://console.developers.google.com/
params.cx = “xxxxxx”; // cx value is the custom search engine value got from https://cse.google.com/cse(if not created then create it).
$.get(“https://www.googleapis.com/customsearch/v1&#8221;,params,function(img){
console.log(img);
callback(img.items[0].link);
}).fail(function(y){
console.log(y);
});
}

Categories: Uncategorized