はてなフォトライフへの画像アップロードがHTTPSのみになっていたので対応

はてなブログへの自動投稿がいつからかエラーとなるようになっていた。

気づいてはいたものの、「画像投稿数か容量上限かな」と思い放置していたが、調べて見ると画像は月ごとの容量に制限はあるもののトータルは無制限とのこと。

そこで原因を探って対処する。

 

アップロードするアプリのログ:
画像のアップロードに失敗しました
status_code: 500
message: Bad requestAtom feed body is required.
a.jpg :エラー ( 1 / 2 )
画像のアップロードに失敗しました
status_code: 500
message: Bad requestAtom feed body is required.
b.jpg :エラー ( 2 / 2 )
送信対象の画像がありません.
完了しました

 

はてなサービスへの認証の手順は以下の通り。

http://developer.hatena.ne.jp/ja/documents/auth/apis/wsse

AtomフィードのBodyがない・・・?

パケットキャプチャしレスポンスを覗いてみると、

HTTP/1.1 302 Moved Temporarily
Server: awselb/2.0
Date: Sun, 17 Nov 2019 18:31:30 GMT
Content-Type: text/html
Content-Length: 126
Connection: keep-alive
Location: https://f.hatena.ne.jp:443/atom/post/

<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
<center><h1>302 Found</h1></center>
</body>
</html>

HTTPSでアクセスしろということかな・・・?

画像送信テスト用のテストコードの、POST先のURLをHTTPSにて再実行→成功

 アプリのコードを変更してテスト→成功

たったこれだけのことだったのか・・・しかしなぜアナウンスもなく?いまさら・・・

普段使い用にpyinstallerでEXE化して実行:

_tkinter.TclError: couldn't open "settings.png": no such file or directory

リソース同梱でビルドできてない模様・・・

調べて見ると使用していたアプリはCUI仕様のものだったようなので、(リソース同梱の方法はいろいろあるようだけど)とりあえずCUI仕様でEXEビルドを行う。

(※後ほど確認したところ、GUI版はリソースをファイルで同梱してリリースしていた!)

 

CUI版の動作を確認したところ、うまく動いてない

→main時の処理に誤りがあったので修正

ーーー

if __name__ == '__main__':

root = HatenaposterUI()
root.mainloop()

ーーー

 

問題なく動作した。

これで今後は自動的に記事がアップされるはず。しばらく様子見。

 

IPパケットサイズ制限を越えてUDPを送受信する

ためにCで簡単な処理のsendto, recvfrom, sendラッパー関数を作成。
まだまだパフォーマンス確認のためのテスト実装なので、再送やエラー処理はなし。
ここで凝ってしまうとTCPになってしまうのであえてシンプルに。
実用上有益というよりは、たったこれだけで越えられるんだよ!というメモ。

#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
#include <pthread.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "userlog.h"
#include "mudp.h"

#define IP_MAX_SIZE 65000
#define MAX_BMP_SIZE 1920*1080*3

int mudp_sendto(SOCKET sock, char *buf, int len, int flags,
                struct sockaddr *to, int tolen)
{
  char *mudpBuf;
  char packetNum;
  int mudpLen;

  packetNum = ((len % IP_MAX_SIZE) == 0 ) ? (len / IP_MAX_SIZE) : (len / IP_MAX_SIZE)+1;
  mudpBuf = (char*)malloc(IP_MAX_SIZE+1);

  for(int i=0;i<packetNum;i++){
    *mudpBuf = i;
    if (len<(i+1)*IP_MAX_SIZE) {
      memcpy(mudpBuf+1, buf+(IP_MAX_SIZE*i), len % IP_MAX_SIZE);
      mudpLen = (len % IP_MAX_SIZE)+1;
    } else {
      memcpy(mudpBuf+1, buf+(IP_MAX_SIZE*i), IP_MAX_SIZE);
      mudpLen = IP_MAX_SIZE + 1;
    }
    int ret = sendto(sock, mudpBuf, mudpLen, flags, to, tolen);
    if(ret==SOCKET_ERROR) {
      LOG_ERROR("mUDP send socket error:%d seqno:%d.\n", WSAGetLastError(), i);
    }
  }
  free(mudpBuf);

  return 0;
}

int mudp_recvfrom(SOCKET sock, char *buf, int len, int flags,
                  struct sockaddr *to, int *tolen)
{
  char *tmpBuf;
  tmpBuf = (char*)malloc(IP_MAX_SIZE+1);
  int retSize=0;

  for(int i=0;;i++) {
    int ret = recvfrom(sock, (char *)tmpBuf, IP_MAX_SIZE+1, 0, to, tolen);
    if ( ret == SOCKET_ERROR ) {
      LOG_ERROR("mUDP recv socket error %d seqno:%d.\n", WSAGetLastError(), i);
      return SOCKET_ERROR;
    } else if (*tmpBuf != i) {
      return DROPPED;
    } else {
      memcpy(buf+(IP_MAX_SIZE*i), tmpBuf+1, ret-1);
      retSize += ret-1;
      if (ret < IP_MAX_SIZE) break;
    }
  }

  return retSize;
}

int mudp_recv(SOCKET sock, char *buf, int len, int flags) {
  int retSize = mudp_recvfrom(sock, buf, len, flags, NULL, NULL);
  return retSize;
}

パフォーマンス改善とコードの静的チェック

どうにも画面転送ソフトのパフォーマンスがあがらないので動的/静的解析。

 

・cppcheck

便利。

コードを静的解析して、素人的ミスを指摘してくれる。

ver 1.79ならXPでも動作○(最新版はXPでは動作しないらしい)

cppcheck - Browse /cppcheck/1.79 at SourceForge.net

※注:古いやつです。

 

Very Sleepy

gprofのようなプロファイラ

Windows gccの場合は次のようなコンパイラオプションを与える必要があるらしい。

-g:デバッグ情報の付加

-O0:最適化の抑止

-fno-omit-frame-pointer:一部最適化を回避しデバッガ向けコードを生成するオプション

EBPレジスタを汎用的に使用せず、デバッガで使用する指定?)

-gdwarf-2:デバッガ向け出力をdwarf2にする

関数名がアドレス表記?なのはまだコンパイルオプションが不足しているのかもしれない。

 

CodeXL - GPUOpen

とりあえず最新版はXPでは動かなかった・・・。

 

Win32-mingwでのスレッドのスタックについて

VP8,VP9を使うためのライブラリlibvpxhttps://www.webmproject.org/code/での動画の変換がうまくいったのでスレッド化してみたところ、なぜかSIGSEGVで落ちるようになってしまったので調査。

■前提:
MinGWPosixスレッドを選択してインストール済み

■テストコード

#include <stdio.h>
#include <pthread.h>
#include <windows.h>
#include <inttypes.h>

void *pthreadTest(void *p) {
  printf("POSIX thread started.\n");
  //allocate 10MB for stack and heap
  uint32_t tenMegaBytes = 1024*1024*10;
  unsigned char allocStack[tenMegaBytes];
  unsigned char *allocPointer = (unsigned char*)malloc(tenMegaBytes);
  for(long i=0;i<tenMegaBytes;i++){
    allocStack[i] = 0;
    *(allocPointer+i) = 0;
  }
  printf("POSIX thread finished.\n");
  return 0;
}

DWORD WINAPI win32ThreadTest() {
  printf("Win32 thread started.\n");
  //allocate 10MB for stack and heap
  uint32_t tenMegaBytes = 1024*1024*10;
  unsigned char allocStack[tenMegaBytes];
  unsigned char *allocPointer = (unsigned char*)malloc(tenMegaBytes);
  for(long i=0;i<tenMegaBytes;i++){
    allocStack[i] = 0;
    *(allocPointer+i) = 0;
  }
  printf("Win32 thread finished.\n");
  return 0;
}

int main(void) {

  //POSIX pthread
  pthread_t pthread;
  pthread_attr_t attr;
  pthread_attr_init(&attr);
  pthread_attr_setstacksize(&attr, 1024*1024*10+1);
  pthread_create(&pthread, &attr, &pthreadTest, NULL);
  pthread_join(pthread, NULL); // pthreadで作られたスレッドが終わるまで待つ

  // win32 thread
  HANDLE handle = CreateThread(0,1024*1024*10+1,win32ThreadTest,(LPVOID)NULL,0,0);
  WaitForSingleObject(handle, INFINITE);
  CloseHandle(handle);

  return 0;
}

win32、posixのスレッドに、それぞれスタックサイズを10MB割り振ってゼロクリアのテスト。正常終了。
スタックを10MBに変更しない場合には、デフォルトの1MBが適用され、OutOfMemory等で落ちるわけでもなく、スタック確保実行時にSIGSEGVで落ちていた。
ここではpthreadもwin32 threadも仕様通りの挙動を示しているのが、libvpxではpthread〇、win32thread×となり、すべてpthreadに変更してみることに・・・。

libyuv

Bitmap(RGB)→VP8の変換にYUVを経由しなければいけないようで、まずはYUVへの変換をテスト。
libyuv/libyuv - Git at Google
各種RGB系、YUV系画像の相互変換、回転等が可能らしい。
とりあえずライブラリをビルドして、4x4のBitmapを変換してみる。

libyuv:

make -f linux.mk CC=gcc CXX=g++
#include <stdio.h>
#include <stdlib.h>

void bgr2yuv(){

  // 青 緑
  // 白 赤 の4x4 bitmap RGB24(BGRの順)
  unsigned char rgb[] = {
  	0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00,
  	0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00,
  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00};

  int width = 4, height = 4;
  unsigned char *yuv;
  yuv = (char*)malloc(width*height+width*height/4*2);
  int uOffset = width*height, vOffset = width*height + (width*height)/4;
  FILE *yuvFile;

  RGB24ToI420( rgb, width*3, yuv, width,
  	yuv+uOffset, width/2, yuv+vOffset, width/2,
  	width, height);

  for (int j=0;j<height;j++) {
	for (int i=0; i<width;++i) {
		printf("%3d %3d(%d) %3d(%d)| ", yuv[j*width+i],
			yuv[uOffset+width/2*(int)(j/2)+(int)(i/2)],width/2*(int)(j/2)+(int)(i/2),
			yuv[vOffset+width/2*(int)(j/2)+(int)(i/2)],width/2*(int)(j/2)+(int)(i/2));
	}
	printf("\n");
  }

  	if ((yuvFile = fopen("test.yuv", "wb")) == NULL)
        printf("Error opening test.yuv\n");
    if (fwrite(yuv, width*height+width*height/4*2, 1, yuvFile) < 1)
    	printf("Error writing test.yuv");
    fclose(yuvFile);

  //result
/*
 41 240(0) 110(0)|  41 240(0) 110(0)| 144  54(1)  34(1)| 144  54(1)  34(1)|
 41 240(0) 110(0)|  41 240(0) 110(0)| 144  54(1)  34(1)| 144  54(1)  34(1)|
235 128(2) 128(2)| 235 128(2) 128(2)|  82 100(3) 212(3)|  82 100(3) 212(3)|
235 128(2) 128(2)| 235 128(2) 128(2)|  82 100(3) 212(3)|  16 100(3) 212(3)|
 青=(41  240  110)、緑=(144   54   34)、白=(235  128  128)、赤=(82  100  212)
*/

}

int main() {
	bgr2yuv();
	return 0;
}
gcc libyuvtest.c libyuv.a
a.exe
 41 240(0) 110(0)|  41 240(0) 110(0)| 144  54(1)  34(1)| 144  54(1)  34(1)|
 41 240(0) 110(0)|  41 240(0) 110(0)| 144  54(1)  34(1)| 144  54(1)  34(1)|
235 128(2) 128(2)| 235 128(2) 128(2)|  82 100(3) 212(3)|  82 100(3) 212(3)|
235 128(2) 128(2)| 235 128(2) 128(2)|  82 100(3) 212(3)|  16 100(3) 212(3)|

VP9お試しビルド(その2)

いろいろ試した結果、結局cygwin環境でconfigureして生成したMakefileを、MinGW-W64のgcc, g++を用いてビルドしました。

MakefileのCC,CXX環境変数MinGWのものにあとから書き換えて強制変更)

インクルードファイルのパスの扱いに何か違いがあるらしく、ビルドの途中でヘッダファイル見つからないエラーが頻発しましたが、スタティックライブラリのところまでは何とかたどり着きました・・・。

その上でsimple_encoder.cをコンパイルしたところ成功、なんとか組み込めそうです。

$ gcc -o simple_encoder simple_encoder.c ../tools_common.c ../y4minput.c ../video_writer.c ../ivfenc.c ../../libvpx.a -I..