2009/11/20

Objective-Cの日付文字列をNSDateに変換

DBから出てきた日付は文字列なので、NSDateFormatterクラスのdateFormatterメソッドを使ってNSDate形式に変換します。

  1. //日付の変換  
  2. NSString *datestr = [setDataDict valueForKey:@"set_datetime"];  
  3. NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];  
  4. [dateFormatter setTimeStyle:NSDateFormatterFullStyle];  
  5. [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];  
  6. [NSDate *datetime = [dateFormatter dateFromString:datestr];  
  7. [dateFormatter release];  
ここを参考に
http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns
日本語はこっちね
http://e6sc8e.jugem.cc/?eid=413

2009/11/17

iPhone Navigation Bar + Tab Bar + hidesBottomBarWhenPushed

タブとナビゲーションビューを使っているとき、ナビゲーションで進んだ先ではタブバーを隠したいときに使えるポロパティにhidesBottomBarWhenPushedがある。文字通り別のビューがプッシュされたら下にあるバーを隠す設定をするためのプロパティ。アクセサを使ってこんな感じで設定する。
  1. [SomeViewController setHidesBottomBarWhenPushed:YES];  
  2. [self.navigationController pushViewController:SomeViewController animated:YES];  

はまりどころ。hidesBottomBarWhenPushedは呼び出す側のコントローラで設定しておかないと行けない。上の例でいうと。SomeViewControllerのdidViewLoadで設定することができるが、これだとちょっとよくない。
didViewLoadで設定するとSomViewControllerがPushされた場合、ボトムバーが消えない。SomeViewController以降のpushされたビューで初めてボトムバーが消える。(SomeViewControllerを再描写して初めて消えているっぽい)。多分didViewLoadでは1手遅いんだと思う。didViewLoadより前でhidesBottomBarWhenPushedを設定しないといけない。つまりSomeViewControllerが呼ばれた時点でバーを隠す場合は、上のサンプルコードのように呼び出し側で設定する。

2009/11/09

iPhone タップ/タッチのイベントを取得する

タッチ/タップのイベントを取得できるのはUIResponderをスーパークラスに持つクラス。UIResponderを親に持つクラスはレスポンだと呼ばれる。レスポンダはタッチ/タップのイベントを取得することができる。
UIViewはUIResponderを継承している。UIControlはUIViewのサブクラス。つまりInterface Builderで構築されるUIはすべてレスポンダ。イベントは一番手前(? ユーザー直面しているビュー)のレスポンダにまず渡される。イベントを渡されたビューが処理しない場合、次のレスポンダに渡されていき、レスポンダの階層をさかのぼっていく。適時イベントが処理される部分が現れると、イベントは処理され破棄されて、イベントが終了する。
ということらしい。
レスポンダに記述する、イベントを処理するメソッドはこんな感じ。UIEventとしてイベントが渡されている。

  1. - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event  
  2. {  
  3.  NSUInteger  numTaps = [[touches anyObject] tapCount];  
  4.  NSUInteger numTouches = [touches count];  
  5.  NSLog(@"タップの回数 : %d",numTaps);  
  6.  NSLog(@"タッチの数: %d",numTouches);  
  7. }  

Interface Builderで作ったUIでは、イベントはそのビュー(UIButtonとか)でキャッチされて、IBActionとして指定したViewControllerのメソッドに処理がバイパスされていると考えるということかな

2009/11/06

iPhone NSTimer NSTimerを止める。

NSTimerを止めるとき、単に[timer release]だけではだめで、コンソールに下記のようなエラーがでる
  1. malloc: *** error for object 0x3fe29f0: double free  
  2. *** set a breakpoint in malloc_error_break to debug  

メインループがこの NSTimer を参照しているのが原因のようです。単純にタイマーを止めるには[timer invalidate]を使うようです。またNSTimerのインスタンスを作っている場合はこれを解放する必要があるので別途[timer release]としたほうが良さそうですが、これをやるとエラーが発生してプログラムが落ちます。

デベロッパドキュメントによると
NSTimer:invalidate:はメインループのNSRunLoopオブジェクトからTimerを解放するメソッドです。
このメソッドがNSRunLoopからタイマーを取り除く唯一の方法と書かれています。NSRunLoopから解放されて、さらにreleaseされると書かれています。下の例の用にNSTimerを変数として保持してない場合は、invalidateするだけでreleaseまで行われていると考えて良さそうです。releaseを実行すると落ちます。
  1. - (void)viewDidLoad {  
  2.  [super viewDidLoad];  
  3.  count = 0;  
  4.  someTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateCount:) userInfo:nil repeats:YES];  
  5. }  
  6.   
  7. - (void)updateCount:(NSTimer *)timer  
  8. {  
  9.  count++;  
  10.  NSString *str = [[NSString alloc] initWithFormat:@"Count %d",count];  
  11.  countLabel.text = str;  
  12.  [str release];  
  13.  if (count > 5) {  
  14.   [timer invalidate];  
  15.  }  
  16. }  

NSTimerを呼び出すあたりが曖昧になっていると、結構はまる。NSTimerオブジェクトを以下のように呼び出した場合
  1. [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateCount:) userInfo:nil repeats:YES];  
デベロッパドキュメントによると
scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:はクラスメソッドで、その説明は
Returns a new NSTimer object, scheduled the current NSRunLoop object in the default mode
デフォルトモードが何かは無視して、このメソッドは既存のNSRunLoopにスケジュールされているNSTimerを返すということらしい。つまり生成したNSTimerオブジェクトの管理はNSRunLoopで行われていて、自分のコントローラ内で勝手に消すと怒られるということのよう。
viewDidLoadのような一回だけ呼ばれるメソッドでNSTimerを宣言するときはいいのですが、[self startTimer]とかして、何回でもそのメソッドが叩けるとその数だけNSTimerオブジェクトが生成されてしまう。NSTimerをいつどこで作るかはちゃんと考えてからやった方が良さそう。



ちなみにNSTimerのfireメソッドでスケジュールに無いタイミングでメソッドを実行できるらしい。

2009/11/05

iPhone JSON Framework使用時に実機でのコンパイルエラーの対処

iPhoneでJSON Frameworkを使って開発しているとき。シュミレータではエラーが出なかったのが、実機でのデバッグではコンパイルエラーになる場合の対処法。
Xcode3.1.4 + iPhone SDK 3.1.2 + iPhone 3G(OS 3.1.2[7D11]) + JSON Framework (2.2.2)で遭遇しました。
エラーメッセージ
  1. Codesign error: 〜“object file format invalid or unsuitable”  
Codesignのエラーということ、ググるとこれはJSON Frameworkが悪さしているということが分かった。

コンパイルエラーの対処方法
プロジェクト > プロジェクト設置の編集 > ビルド > コード署名リソース・ルールパス を編集
デフォルトでは空欄なので以下を追加
  1. $(SDKROOT)/ResourceRules.plist  

これでコンパイルは通るようになります。しかし実機での実行時に[NSObject JSONValue]メソッドが呼び出せないエラーが起こり例外エラーになってしまいます。この対処法がわからない。

JSON Frameworkの導入はここを参考に
http://www.syuhari.jp/blog/archives/1146


コンパイルエラーの対処法はここを参考にしました。
http://iphone.galloway.me.uk/2009/04/json-framework-codesign-object-file-format-invalid-or-unsuitable/

解決
JSON Frameworkを使うときに[NSSring JSONValue]が呼べない問題は
  1. //ここでJSONValueを使うのはだめ,実機で落ちる  
  2. //NSDictionary* jsonItem = [jsonStr JSONValue];  
  3.   
  4. //こっちを使う エラーはセットしておく方が大人の対応。  
  5. NSError *error;  
  6. SBJSON *json = [[SBJSON new] autorelease];  
  7. NSDictionary *jsonItem = [json objectWithString:jsonStr error:&error];  
  8. if (!jsonItem) {  
  9.  NSLog(@"%@", error);  
  10. }  

JSON Framework - Google Codeのフォーラムで議論されてました。
http://code.google.com/p/json-framework/issues/detail?id=22

2009/11/02

Objective-Cでの数値→文字列とその逆.

Objective-CでのInt型→NSString型とその逆の渡し方。
特に難しいことはなく、intValueメソッド、またはstringValueメソッドを使えばキャストした値を返してくれる。

  1. //NSSTring型をInt型に  
  2. int intTime = [ @"20" intValue ];  
  3.   
  4. //Int型を文字列に  
  5. NSString* strTime;  
  6. strTime = [ NSString stringWithFormat : @"%d", 20 ];  

2009/10/27

XcodeのSCMでSubversionを使う。

ここが詳しいです。
http://ricecaker.com/mac/139/

[SCM]のメニューから
1.[SCM リポジトリの構成]でリポジトリを登録する。
2.プロジェクトの[このプロジェクトのSCMを構成]から、登録したリポジトリを選ぶ。
3.[プロジェクトの設定を編集]から一般タブを選ぶSCMリポジトリを設定する
4.[SCM]のメニューを開くと項目が増えているはず。これでリポジトリの設定は終わり
5.あとは[リポジトリ]を開いて、状況をチェックする。

リポジトリウィンドウ
読み込むでsvn add
チェックアウトでsvn co
書き出しでsvn export
だと思う。

2009/09/30

identicon.pyの準備

identicon.pyを使いたい。
of + openCVの中におきたい気持ちがあったけど、時間がなかったのでとりあえず
外部プログラムとしてidenticon.pyを使ったpythonスクリプトで画像を吐きだしている。
ちなみにPicasaへのアップロードもpythonで組んでいるのでofで統合はしばらく先になりそう。
PILをインストールしていることが、前提なのでportでPILを入れる。

identicon.pyはここを参照
http://yappo.ne.jp/share/wiki/lang/python/misc
http://bulkya.blogdb.jp/share/browser/lang/python/misc/identicon.py

使い方はこんな感じ
  1. from identicon import render_icon  
  2. icon = render_icon(0xDEADBEAF96)  
あとはicon.save('%08x.png' % code, 'PNG')とかでファイル書き出し完了

[セットアップ]Mac PortでPILのインストール

まずマシンのPyhonのバージョンチェック

/Library/Python/

にバージョンごとにディレクトリがあるのでチェック
OSX 10.5.8では2.3と2.5が入っている。デフォルトでは2.5が呼ばれる
確認はとりあえず -hでみる
  1. python -h  
  2. usage: /System/Library/Frameworks/Python.framework/Versions/2.5/Resources/Python.app/Contents/MacOS/Python [option] ... [-c cmd | -m mod | file | -] [arg] ...  
2.5で大丈夫。
portでPILを探す。
port install PILは間違い。

とりあえず探す。
  1. port search pil  
py-pil
py25-pil
py26-pil
があるみたいのので、当然同じバージョン2.5を入れる。
  1. sudo port install py25-pil  

既にOpenCVなどをインストール済みなので、一発ですぐインストール終了。
ここでいきなり
  1. python  
  2.   
  3. >>>import PIL  
としてもPILがないとおこられます。
portで入れたPILがきちんと呼ばれるようにシンボリックリンクを張る。
  1. ln -s /opt/local/var/macports/software/py25-pil/1.1.6_0/opt/local/lib/python2.5/site-packages/PIL /Library/Python/2.5/site-packages/PIL  

これでもう一度pythonを対話モードで起動してimportを行って確認する。
  1. python  
  2.   
  3. >>>import PIL  
  4. >> import PIL.Image  
  5. >>> import PIL.ImageFilter  
  6. >>> dir(PIL)  
  7. ['Image''ImageFilter''ImageMode''ImagePalette''__builtins__''__doc__''__file__''__name__''__path__''_imaging']  

ちゃんと呼べてるようです。

ここら辺を参考にしました。
MacにPython Imaging Library (PIL)をインストールする
Mac OS X 10.5にPILを入れる(MacPorts)

毎回ありがとうはてなさん

PIL1no

2009/09/16

phpのバックグラウンドで外部処理を実行する

ここを参考にhttp://www.stackasterisk.jp/tech/php/php02_02.jsp

  1. system("/home/user/sh/convert.php $arg1 $arg2 > /dev/null &");  


「> /dev/null &」をバックグランドで処理を実行することになる。

通常処理はこっち。
  1. system("/home/user/sh/convert.php $arg1 $arg2  &");  

これだとconvert.phpの処理に1分かかったら、レスポンスも1分待たないといけない。

2009/09/04

Soft Bankの動画の仕様

ソフトバンクの動画仕様はここを参照する。
動画機能貧弱すぎます。機種ごとの折り合いが取れる仕様がこれみたい
http://creation.mb.softbank.jp/others/movie_about.html

2009/09/03

mp4box古い携帯電話向けの分割処理

古い携帯電話へ動画の再生を対応させる時は動画のサイズがよく問題になります。
各社、各端末ごとに再生できる動画サイズは微妙に違っていたりします。
大体の目安として176x144の縦横で200KB以下というものがあります。
縦横のサイズはffmpegなどで変換時に設定すれば終わりですが、
任意のサイズ辺りで分割する処理にはmp4boxが良いようです。

mp4boxでサイズでファイルを分割するには下記実行します。
  1. mp4box -split-size 190 input.3gp  


完全に均等に190KBにはならないので注意が必要です。
ファイル内のランダムアクセスポイント(sync samples)の配置により、出力ファイルは指定サイズより小さいことがある。

http://agehatype0.blog50.fc2.com/blog-entry-195.html
だそうです。しかし指定サイズを超えることは無いのでこれで十分です。


http://agehatype0.blog50.fc2.com/blog-entry-195.html

phpで大きいファイルのダンプ

phpでファイルサイズの大きいもの、動画や音声ファイルなどをfopen,fread.echoで出力するときに30MB前後で出力が終わってしまうことがあります。
恐らくphpiniのmemory_limitの32MBに引っかかっているのだと思いますが、エラーが出ないのでなんともいえません。

下記のようにflush(),ob_flush()で出力することで回避できます。
flush()していないと、phpのコードが全て実行されてからブラウザの描画が始まるので、
どこかでメモリの制限が行われていると出力されないのだと思う。

  1. header('Content-Length: '.filesize($filename));  
  2. header('Content-Type: '. $contentype);  
  3. //キャッシュを有効に  
  4. header('Pragma: Private');  
  5. header('Cache-Control: Private');  
  6. header('Expires: '.gmdate('D, d M Y H:i:s',time() + 1800) . ' GM  
  7.   
  8. $handle = fopen($filename,'r');  
  9.   
  10. if ($handle) {  
  11.     while (!feof($handle)) {  
  12.         echo  fread($handle, 4096);  
  13.         flush();  
  14.         ob_flush();  
  15.     }     
  16.     fclose($handle);  
  17. }     
  18. die();  

Flash Playerからも接続も確認できました。

2009/09/02

携帯電話の動画再生ページ

携帯電話で動画を再生するには、まず動画を3gp(docomo,softbank)もしくは3gp2(au)の形式に変換しておく必要がある。変換はffmpegなどを使って行います。
次にサイトに埋め込む際にも注意が必要です。キャリアごとに埋め込みの方法が違います。
auは下記のようにobjectとして埋め込みます
  1. <object copyright="no" data="http://ファイルの場所/ファイル名.3g2" type="video/3gpp2">standby="動画ダウンロード (オブジェクトダウンロードを起動する為のリンク部分文字)">  
  2.   
  3. <param name="disposition" value="devmpzz" valuetype="data">  
  4.   
  5. <param name="size" value="119065" valuetype="data">  
  6.   
  7. <param name="title" value="タイトル名" valuetype="data">  
  8.   
  9. </object>  

auの参考ページ

DocomoとSoft Bankはともに3gp形式ですが、埋め込みタグが違います。
Docomo
Docomoの動画はiモーションと呼ばれす。iモーションはobjectタグを使用することで再生の制御などを行うことができます。
詳しくはドコモのサイトへ
http://www.nttdocomo.co.jp/service/imode/make/content/imotion/mp4/about/index.html
  1. 【例1】再生制限がない場合  
  2.   
  3. <a href="”http://www.xxx.co.jp/i-motion.3gp”">iモーション</a>  
  4.   
  5.   
  6.   
  7. 【例2】3回まで再生可能とする場合  
  8.   
  9. <object data="fomacm.3gp" declare="" id="fomacm.declaration" type="video/3gpp">  
  10.   
  11. <param name="count" value="3" valuetype="data">  
  12.   
  13. </object>  
  14.   
  15. <a href="#fomacm.declaration">FOMAコマーシャル</a>  
  16.   
  17.   
  18.   
  19. <a href="#video.declaration">再生する</a>  


Soft Bankは普通にaタグで動画ファイルを設定するだけ?
Soft Bankのサイトにはコンテンツ作成についての情報が無いので不明です。

http://www.marguerite.jp/Nihongo/WWW/Mobile/Video.html


http://cgi15.plala.or.jp/~uniphi/pyuki/wiki.cgi?%B7%C8%C2%D3%B5%A1%BC%EF%28%C6%B0%B2%E8%29%2FSoftbank


http://mpweb.sytes.net/complete/pc/mobile-movie.php

2009/08/31

サーバーサイドでの動画変換

動画の変換はffmpegとmencoderで行う。
mp4の連結はMP4Boxで行っている。
変換に関してはffmpegの方がいろいろ細かいことができるが、mencoderの方が綺麗らしい。
Max/MSPとSC見たいな感じということかな。
ON2のflvを生成するにはmencoderを使う必要があるみたい。

MP4Boxは結合する動画のサイズが異なるとエラーになる。


3gp、3g2(3GPP、3GPP2)はベースはMPEG4でオーディオが微妙に違うだけ。

ファイルフォーマット 3GPP 3GPP2
通信方式 GSM CDMA2000
ビデオ MPEG4/H.263
オーディオ AAC/AMR AAC/AMR/QCELP
テキスト 3Gテキスト
ベースファイルフォーマット MP4
拡張子 *.3gp *.3g2

2009/08/27

ffmpegで変換時の動画サイズ



ffmpegで変換時に半端なサイズを指定すると、変換に失敗する。
3gpとかで"-s 176x99"とかでは落ちる。
"-s 176x100"など2で割れる数字にしないとだめ

2009/08/25

モザイクをつくるよ

モザイクを作るよ

2009/07/09

Mac PortsでOpenCVとffpegインストール

まっさらな状態のiMac(24inch 2.66Ghz Core 2 Duo)にMac Ports からOpenCVとffmpegを入れようとしてハマった。

とりあえずMac Ports をインストールしてすぐPortにあるOpenCV 1.0をさくっと入れようとしたが、python25周りでエラーがでて失敗。

ffmpegはlibsdl周りでエラーが。いろいろググった結果結果答えは見つからなかったが、ふとXcodeが怪しいそうと気づいて最新バージョンにアップデートしたらあっさり通った。


前にも一度Xcodeのgccでつまずいたことがあったから、とりあえずインストールCDのXcodeはもう信用しないようにするべき。