[완료]그놈 애플릿 Debug는 어떻게 ?

atie의 아바타

주말에 취미 생활(?) 컴파일을 했었습니다. 하나는 Nokia의 꽃 브라우저 였고, 또 다른 하나는 istream이라는 그놈 애플릿 이었습니다. 전자는 "web-core를 gtk로 포팅을 하는구나... 테스트 브라우저... 여전히 허접하네." 하는 기술적 내용이야 상당하더라도 사용자의 관점에서는 별 감흥이 없었고, 후자의 istream은 패널에 등록하고 한번 클릭에 라디오 방송을 들을 수 있으니 꽤 유용하구나 하는 생각을 해서 제 패널에도 등록을 해 놓았습니다.

그런데, 언제나 그렇듯이 꼭 노래 제목에서 한글이 깨지는 것은 여전하더군요.(테스트는 뮤클캐스트로...) 그래서, 잠깐 웹 검색을 해서

diff -urN istream-0.10/src/stream.c stream.c 
--- istream-0.10/src/stream.c   2007-04-07 17:39:09.000000000 -0500
+++ stream.c    2007-04-07 17:37:53.000000000 -0500
@@ -30,6 +30,19 @@
 
         g_strstrip(title);  
 
+               if (title != NULL && !g_utf8_validate (title, -1, NULL)) {
+                       const gchar *encoding;
+                       gchar *tmp;
+
+                       //need encoding = g_getenv ("GST_TAG_ENCODING")? Now, cp949
+                       //for testing
+                       encoding = "cp949";
+                       tmp = g_convert_with_fallback (title, -1, "UTF-8", encoding,
+                               "*", NULL, NULL, NULL);
+                       g_free (title);
+                       title = tmp;
+               }
+
         if (applet->title==NULL || strcmp (title, applet->title) != 0) {
           if (debug) printf ("new title (scroll)\n");
 
@@ -129,6 +142,19 @@
       if (gst_tag_list_get_string (list,tag, &title)) {
         g_strstrip(title);
 
+               if (title != NULL && !g_utf8_validate (title, -1, NULL)) {
+                       const gchar *encoding;
+                       gchar *tmp;
+
+                       //need encoding = g_getenv ("GST_TAG_ENCODING")? Now, cp949
+                       //for testing
+                       encoding = "cp949";
+                       tmp = g_convert_with_fallback (title, -1, "UTF-8", encoding,
+                               "*", NULL, NULL, NULL);
+                       g_free (title);
+                       title = tmp;
+               }
+
         if (applet->title==NULL || strcmp (title, applet->title) != 0) {
           if (debug) printf ("new title (no scroll)\n");

위와 같이 제목만이라도 한글이 나올까 싶은 테스트 코드를 만들어 보았습니다. 결과는 안되더군요. 그래서 이 애플릿을 디버깅할 필요가 생겼습니다.

웹 검색을 해서 그놈 개발자의 애플릿 디버깅 관련 글을 보기는 했는데... 어느 분이 저 예제로 명쾌하게 설명해 주실 수 있나요? 덧붙여 한글 제목이 올바르게 나오는 수정도 어느 분이 해주시면 좋겠고... 급한 것 아니니 "코드놀이" 겸 이 곳에 글을 써 놓고 오는 주말까지 답변을 기다려 보겠습니다.

그리고, 그놈에서 encoding 처리는 저 방식으로 하는 것이 맞나요? 궁금하더군요.

애플릿의 STDOUT을 보려면

제가 예전에 했을 때는, 일단 터미널에서 한 번 실행을 시키고 (libexec 밑에 있는 걸 그냥 실행하면 됐던 걸로 기억합니다만 정확한지는 모르겠습니다) 그 다음에 패널에 추가했습니다. 그러면 STDOUT 등이 터미널 쪽에 나오더라구요.

그리고는 최고의 디버깅 툴인 printf로.. (glib은 g_print..)

=3=33

panel-test-applets 를

panel-test-applets 를 이용해보세요.

----
데스크탑 프로그래머를 꿈꾸는 임베디드 삽질러

그리고 태그는

그리고 태그는 gstreamer에서 얻어오는 것 같네요. 먼저 gstreamer에서 제대로 얻어오는 지 확인 해봐야 할 것 같습니다.

환경변수에 다음 값을 설정해서 id3태그를 제대로 읽어오는 지 확인해보세요

$ export GST_DEBUG=id3demux:4

----
데스크탑 프로그래머를 꿈꾸는 임베디드 삽질러

istream 수준에서

istream 수준에서 해결될 문제가 아닌 것 같습니다.
전에 rhythmbox 에서 같은 문제로 삽질을 했었는데,
gstreamer 저 깊숙한 곳에서 이미 코드가 깨져서 올라옵니다.

말하자면, istream 에서 볼 수 있는 코드는 utf8 코딩된 한글도 아니고 euckr 코딩된 한글도 아닙니다. 정체불명 국적불명 이해불가능 코드입니다.

LANG=ko_KR.euckr rhythmbox & g
하듯이
LANG=ko_KR.euckr /usr/libexec/istream &
하시고 패널에 iStream 을 추가하니 잘 뵈네요.
개인적으로... 이게 더 신기했었습니다.
gnome 의 기본정책은... 아마도... "system 의 LANG 이 뭐든간에 최종적으로 utf8 로 변환한 다음 display 에 뿌려주는 것" 으로 짐작됩니다.

euckr(또는 cp949) 코드를 utf8(system)->utf8(gnome) 변환했을 때 망가지는 이유는 gnome 또는 gstreamer 의 자가당착적 버그 같습니다. 열심히 하느라고 한 것 같기는 한데, 오바했다 싶어요. 결국 system locale 이 utf8 일 경우, utf8 이 아닌 코드는 전부 망가질 수 밖에 없을 거라 봅니다.
to_charset 과 from_charset 이 같으면 아예 건드리지 않으려니,
utf8_validate() 를 통과못한 코드를 그대로 display 시도할 경우에 발생하는 각종 문제들을 감당하기 어려워 억지로 utf8 로 꿰어 맞추는 거겠죠.

OTL

gnome 의 기본정책은...

bushi wrote:

gnome 의 기본정책은... 아마도... "system 의 LANG 이 뭐든간에 최종적으로 utf8 로 변환한 다음 display 에 뿌려주는 것" 으로 짐작됩니다.

gtk/gnome 내부에서는 text를 전부 utf-8로 처리하도록 되어있습니다.

bushi wrote:

euckr(또는 cp949) 코드를 utf8(system)->utf8(gnome) 변환했을 때 망가지는 이유는 gnome 또는 gstreamer 의 자가당착적 버그 같습니다. 열심히 하느라고 한 것 같기는 한데, 오바했다 싶어요. 결국 system locale 이 utf8 일 경우, utf8 이 아닌 코드는 전부 망가질 수 밖에 없을 거라 봅니다.

정확히는 gstreamer에 포함된 id3tag 라이브러리가 id3태그에 정의된 인코딩(iso-8859-1, utf-8, utf-16le, utf-16be)으로만 처리하려고 해서 그렇습니다.

윈도에서 사용하는 id3태깅 프로그램들이 문자셋은 iso-8859-1로 설정을 하고 로컬 캐릭터셋으로 저장하는 만행을 저지르죠.

----
데스크탑 프로그래머를 꿈꾸는 임베디드 삽질러

recap을 하면...

뮤클캐스트의 곡 제목이 한글로 보이는 것은, (코드 수정할 필요도 없이 원래의 0.10 버전으로)
killall istream 한 후, 명령행에서 LANG=ko_KR.euckr /usr/libexec/istream & 한 후 화면 상에 뜬 대화창의 reload 버튼을 눌러 주면 그 후의 곡 제목들은 한글이 잘 보입니다. bushi님 이야기대로 입니다.

제가 테스트한 코드에서는 !g_utf8_validate 부분을 빼고, 항상 강제로 cp949 -> utf8을 유도하면 title 값이

title: ºò¸¶¸¶ - Ãູ
tmp: 쨘챵쨍쨋쨍쨋 - 횄횪쨘쨔
 
title: ¹éÁö¿µ - ³ª»Û »ç¶÷
tmp: 쨔챕횁철쩔쨉 - 쨀짧쨩횤 쨩챌쨋첨

이런 식으로 화면 상에 보여지게 됩니다. 터미널 화면 상에 보이는 것은 코드에 printf를 넣고 위와 같은 방법으로 istream을 재시작한 후에는 STDOUT 값을 볼 수 있었습니다. kz님 이야기대로 입니다.

결론은 넘어오는 gstream tag값과 g_convert_with_fallback() 내부를 보아야 할 듯 싶은데... 능력 밖이라 저는 미뤄놓겠습니다.

원 글을 쓰기 전에 kz님도 이전에 비슷한 것을 보았고, 그리고 gana님은 이미 gstream tag 쪽을 많이 본 것으로 알고 있으니 어느날 크리스마스 선물이 도착할 수도 있겠죠. :P 그리고, 대략 제가 사용해 본 플레이어 중에서 LANG=ko_KR.euckr을 주고서라도 스트림에서 가져오는 곡 제목이 제대로 보이는 플레이어는 리듬박스 하나였던 것 같습니다. 이제는 두 개가 된 셈인데, 무엇인가
"gstreamer 저 깊숙한 곳에서 이미 코드가 깨져서 올라옵니다."
이 것을 해결할 방법이 있으면 하는 생각을 갖게 하는군요.

그놈 애플릿 디버그에 관한 글은,
http://www.davyd.id.au/articles/debugging-gnome-applets.shtml
이 것을 찾아놓고 있었습니다.

답변 주신 세 분께 고맙습니다.
----
I paint objects as I think them, not as I see them.

----
I paint objects as I think them, not as I see them.
atie's minipage

그냥 아무생각없이

그냥 아무생각없이 패치 만들어서 버그질라에 올렸습니다.

http://bugzilla.gnome.org/show_bug.cgi?id=428689

id3v1을 파싱할 때는 환경변수로 설정하는게 있는데 id3v2에선 그냥 날로파싱하네요..

고치는 김에 property로도 고칠 수 있도록 했습니다.

----
데스크탑 프로그래머를 꿈꾸는 임베디드 삽질러

포인트 올려 드렸습니다.

:Happy!
----
I paint objects as I think them, not as I see them.

----
I paint objects as I think them, not as I see them.
atie's minipage

gstreamer 버그

gstreamer 버그 담당자가 뻐팅기네요 -ㅅ-

한마디 적어주세요~

----
데스크탑 프로그래머를 꿈꾸는 임베디드 삽질러

feisty 패키지로는...

patch가 적용이 안되서 trunk버전으로 패키지 빌드를 하려면 제가 시간이 좀 필요하겠습니다. -_- 테스트해서 이러이러니 이게 필요하다라고 예와 증명을 따라할 수 있게 하면 담당자도 수긍하겠지요.
----
I paint objects as I think them, not as I see them.

----
I paint objects as I think them, not as I see them.
atie's minipage

개발자의 이해도가 의외로 낮네요.

새로 리포트를 만들었습니다.
http://bugzilla.gnome.org/show_bug.cgi?id=428901
----
I paint objects as I think them, not as I see them.

----
I paint objects as I think them, not as I see them.
atie's minipage

모질라에는 문자셋이

모질라에는 문자셋이 기술되지 않은 기존의 미디어나 프로토콜의 문자셋을 짐작할 수 있는 라이브러리가 있습니다.

이넘을 glib으로 포팅해서 넣은 다음 쟤네덜을 다 고쳐버리고 싶네요.

주말마다 쌩노가다하면 언젠가는 들어갈지도.. (먼산)

일단은 첫걸음으로 kldp위키에 http://wiki.kldp.org/wiki.php/Ganadist/GCharDet 페이지를 만들었습니다.

과연 제대로 만들어져서 glib에 통합될 수 있을까요;;

----
데스크탑 프로그래머를 꿈꾸는 임베디드 삽질러

스트리밍 태그 건은...

아래에 bushi님 쓰신대로 딱 그렇게 고쳐졌습니다.
----
I paint objects as I think them, not as I see them.

----
I paint objects as I think them, not as I see them.
atie's minipage

더듬거리며

더듬거리며 찾아봤습니다.
http://bugzilla.gnome.org/show_bug.cgi?id=428901
고생 많으셨습니다.
GST_ICY_TAG_ENCODING 를 사용하면 되는군요.

OTL

gstreamer-plugins-good

gstreamer-plugins-good 0.10.6 릴리즈부터 적용되는군요.

OTL

OTL

환경변수로 설정하는

환경변수로 설정하는 것은 파일의 태그에나 먹힙니다.
나름대로 유행중인 인터넷 라디오 방송엔 소용없다니까요.

광고는 아니고... 예시로 http://mukul.inlive.co.kr/listen.pls

OTL

두번씩이나 같은

두번씩이나 같은 삽질을 했다는 것이 기분나빠서 gstreamer 말고 다른 곳을 찔러봤습니다.

태그에 대한 간략한 설명
http://jicyshout.sourceforge.net/oreilly-article/java-streaming-mp3-pt2/...

날린 요청

GET / HTTP/1.0
Icy-MetaData:1

받은 ICY 헤더

ICY 200 OK
icy-notice1:<BR>This stream requires <a href="http://www.winamp.com/">Winamp</a><BR>
icy-notice2:SHOUTcast Distributed Network Audio Server/Linux v1.9.7<BR>
icy-name:Republic of Korea Top Radio. MUKULCAST.COM*KPOP
icy-genre:Republic of KoreaPOP
icy-url:http://mukulcast.com
content-type:audio/mpeg
icy-pub:1
icy-metaint:8192
icy-br:128

실제 받아본 ICY metadata (편의상 utf8 로 변환해서 적습니다. 본의아니게 또 광고)

StreamTitle='Cj^레이...멘트中 - 처음';StreamUrl='hTtP://mn.inlive.co.kr/?c=mukul.inlive.co.kr&p=80&ID=MUKUL';

charset encoding 에 대한 정보는 원래부터 어디에도 없었습니다.

gstreamer 는 도대체 무슨 이유때문에 꾸역거리며 억지로, 무조건 utf8 로 변환을 시도하는 건가요 ?

OTL

잠이 싹

잠이 싹 달아났습니다.
gstreamer icydemux 코드는
http://webcvs.freedesktop.org/gstreamer/gst-plugins-good/gst/icydemux/gs...

관심이 집중되는 핵심 부분을 추리면

/* The following two charset mangling functions were copied from gnomevfssrc.
 * Preserve them under the unverified assumption that they do something vaguely
 * worthwhile.
 */
static char *
unicodify (const char *str, int len, ...)
{
  char *ret = NULL, *cset;
  va_list args;
  gsize bytes_read, bytes_written;
 
  if (g_utf8_validate (str, len, NULL))
    return g_strndup (str, len >= 0 ? len : strlen (str));
 
  va_start (args, len);
  while ((cset = va_arg (args, char *)) != NULL)
  {
    if (!strcmp (cset, "locale"))
      ret = g_locale_to_utf8 (str, len, &bytes_read, &bytes_written, NULL);
    else
      ret = g_convert (str, len, "UTF-8", cset,
          &bytes_read, &bytes_written, NULL);
    if (ret)
      break;
  }
  va_end (args);
 
  return ret;
}
 
static char *
gst_icydemux_unicodify (const char *str)
{
  return unicodify (str, -1, "locale", "ISO-8859-1", NULL);
}
 
static void
gst_icydemux_parse_and_send_tags (GstICYDemux * icydemux)
{
  GstTagList *tags = gst_tag_list_new ();
  const guint8 *data;
  int length, i;
  gchar *buffer;
  gchar **strings;
  gboolean found_tag = FALSE;
 
  length = gst_adapter_available (icydemux->meta_adapter);
 
  data = gst_adapter_peek (icydemux->meta_adapter, length);
 
  /* Now, copy this to a buffer where we can NULL-terminate it to make things
   * a bit easier, then do that parsing. */
  buffer = g_malloc (length + 1);
  memcpy (buffer, data, length);
  buffer[length] = 0;
 
  strings = g_strsplit (buffer, "';", 0);
 
  for (i = 0; strings[i]; i++) {
    if (!g_ascii_strncasecmp (strings[i], "StreamTitle=", 12)) {
      char *title = gst_icydemux_unicodify (strings[i] + 13);
 
      if (title && *title) {
        gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_TITLE,
            title, NULL);
        g_free (title);
        found_tag = TRUE;
      }
    } else if (!g_ascii_strncasecmp (strings[i], "StreamUrl=", 10)) {
      char *url = gst_icydemux_unicodify (strings[i] + 11);
 
      if (url) {
        /* 
           gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_URL, 
           url, NULL); 
           found_tag = TRUE;
         */
        g_free (url);
      }
    }
  }
 
  g_strfreev (strings);
  g_free (buffer);
  gst_adapter_clear (icydemux->meta_adapter);
 
  if (found_tag) {
    if (icydemux->srcpad) {
      gst_icydemux_send_tag_event (icydemux, tags);
    } else {
      if (!icydemux->cached_tags) {
        icydemux->cached_tags = gst_tag_list_new ();
      }
 
      gst_tag_list_insert (icydemux->cached_tags, tags,
          GST_TAG_MERGE_REPLACE_ALL);
    }
  }
}

말인즉슨 StreamTitle=... 을 받아서 $LANG->utf8 변환이 실패하면 iso8859_1->utf8 로 끝장을 보고자 했음이겠고.
gst_icydemux_unicodify() 를 적당히 변조하면 GST_ICY_CHARSET 따위의 환경변수를 집어넣는 것이 가능하다는 소리렸다.

(gana 군. "locale" 보다 우선순위가 높도록 그 앞으로 부탁함세.)

ICY 의 StreamTitle 에 대한 charset encoding 문제는 icecast 메일링리스트에서 4년전에 잠깐 반짝하고는 별 변화가 보이지 않고.
icecast 서버쪽 소스를 보니 로그를 남기기 위해 id3 tag 정보를 참조해서 encoding 변환을 하는 부분이 있긴 합니다.

OTL

당연한 것이겠지만,

당연한 것이겠지만, 위의 소스에서 iso8859_1을 cp949로 바꿔서 만든 플러그인 패키지와 함께로는 istream에 LANG 환경 변수를 주는 것 없이 한글 제목이 잘 보이는군요.

링크해주신 shoutcast 스펙의 스트림에서의 charset은 조건부이니 라디오 방송에서 그 정보를 전달하지 않는 것에 하자가 있다고 할 수는 없겠고, 결국은 gstreamer를 쓰는 각각의 플레이어를 수정하지 않으려면 gstreamer에서 단일한 그리고 똑똑한 편법을 하나 넣어야 한다는 이야기인데 gstreamer 기존의 환경 변수 값을 하나 골라 쓸 것인지 gana님의 패치처럼 속성값을 추가하는 방식인지는 선택이 어렵겠습니다. 지금 예는 shoutcast에 맞는 charset 속성이지만 또 다른 스펙에 맞게도 속성을 추가해야 할지도 모른다는 것으로 이해가 되서요.
----
I paint objects as I think them, not as I see them.

----
I paint objects as I think them, not as I see them.
atie's minipage

댓글 보기 옵션

원하시는 댓글 전시 방법을 선택한 다음 "설정 저장"을 누르셔서 적용하십시오.

댓글 쓰기

CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다. 아래 보이는 글자를 입력해 주세요.