문제가 된다면 삭제하겠습니다-_-

전에 WireShark를 이용해서 알송패킷을 캡쳐했을 때 보면 특정주소의 WebService를 요청해서 가져오게 되어있었습니다. http://mudchobo.tomeii.com/tt/434

실제 전송하는 데이터는 MD5값인데, 이게 어떻게 생성되는지 몰라서 구글에서 검색을 하니 어떤 블로그에서 시도한 흔적을 발견했습니다. 거기에 있는 댓글에서 발견했습니다^^
http://dialup.egloos.com/152001

"MP3 파일의 경우 strChecksum 값은 ID3태그등을 제외한 순수 MP3 음악 데이터를 앞에서부터 163840 바이트 읽어서 MD5로 돌린 값입니다. " 라고 친절하게 답변이....-_-

그래서 이렇게 하니까 잘 되더라구요. 아래는 샘플 코드입니다.
필요한 라이브러리는 MD5생성해주는 corelib가 필요합니다.
http://code.google.com/p/as3corelib/
[code]<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
    applicationComplete="applicationCompleteHandler()">
    <mx:Script>
        <![CDATA[
            import mx.rpc.events.FaultEvent;
            import mx.rpc.events.ResultEvent;
            import flash.text.engine.ContentElement;
            import mx.messaging.messages.HTTPRequestMessage;
            import mx.rpc.http.HTTPService;
            import com.adobe.crypto.MD5;
            private function applicationCompleteHandler():void
            {
                var fs:FileStream = new FileStream();
                fs.open(new File("C:/Users/mudchobo/Downloads/임재범 - 사랑이라서.mp3"), FileMode.READ);
                var fileSize:int = fs.bytesAvailable;
               
                for (var i:int = 0; i < 500000; i++)
                {
                    if (fs.bytesAvailable >= 3 && fs.readUTFBytes(3) == "ID3")
                    {
                        var sizeByte:ByteArray = new ByteArray();
                       
                        // ID3v2길이구하기
                        fs.position += 3;
                        fs.readBytes(sizeByte, 0, 4);
                        var id3Size:int = sizeByte[0] << 21 | sizeByte[1] << 14 | sizeByte[2] << 7 | sizeByte[3];
                        fs.position = id3Size + 10;
                        break;
                    }
                }
               
                // ID3태그 없는 경우
                if (i == 500000)
                {
                    fs.position = 0;
                }
               
                // 공백있는 ID3태그에 대한 처리
                for (i = 0; i < 50000; i++)
                {
                    if (fs.readUnsignedByte() == 255)
                    {
                        var a:int = fs.readUnsignedByte();
                        if ((a >> 5) == 7)
                        {
                            fs.position += -2;
                            break;
                        }
                    }
                }
               
                // 163840만큼 읽어서 md5생성
                var data:ByteArray = new ByteArray();
                fs.readBytes(data, 0, 163840);
                var md5:String = MD5.hashBytes(data);
               
                // 웹서비스 요청
                var httpService:HTTPService = new HTTPService();
                httpService.method = HTTPRequestMessage.POST_METHOD;
                httpService.contentType = "application/soap+xml";
                httpService.url = "http://lyrics.alsong.co.kr/alsongwebservice/service1.asmx";
                httpService.request = new XML('<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="ALSongWebServer/Service1Soap" xmlns:ns1="ALSongWebServer" xmlns:ns3="ALSongWebServer/Service1Soap12"><SOAP-ENV:Body><ns1:GetLyric5><ns1:stQuery><ns1:strChecksum>' + md5 + '</ns1:strChecksum><ns1:strVersion>2.0 beta2</ns1:strVersion><ns1:strMACAddress>ffffffffffff</ns1:strMACAddress><ns1:strIPAddress>255.255.255.0</ns1:strIPAddress></ns1:stQuery></ns1:GetLyric5></SOAP-ENV:Body></SOAP-ENV:Envelope>');
                httpService.addEventListener(ResultEvent.RESULT, resultHandler);
                httpService.addEventListener(FaultEvent.FAULT, faultHandler);
                httpService.send();
            }
           
            private function resultHandler(event:ResultEvent):void
            {
                trace("싱크가사 = " + event.result.Envelope.Body.GetLyric5Response.GetLyric5Result.strLyric);
            }
           
            private function faultHandler(event:FaultEvent):void
            {
                trace(event.toString());
            }
           
        ]]>
    </mx:Script>
</mx:WindowedApplication>
[/code]
여기서 알송가사에서 제공하는 웹서비스는 WebService인데, HTTPService로 요청한 이유는 wsdl문서가 어디있는지 못찾겠음 ㄷㄷ 그래서 그냥 httpservice로 xml통채로 넘겨버리니-_- 되더라구요 ^^
xml넘길 때 strCheckSum값만 md5구한걸로 넘기면 돼요^^

[code]싱크가사 = [00:00.00]하루 하루 그대만 보여서<br>[00:23.28]매일매일 눈을 가리고 살아<br>[00:31.34]그대 곁을 나조차도 모르게 머물며<br>[00:38.91]메마른 내 가슴이 그댈 잊어버리지 못한 이유는<br>[00:00.00]<br>[00:00.00]<br>[00:49.93]사랑이라서 사랑이라서<br>[00:56.06]두번다시 못볼 사랑이라서<br>[00:00.00]<br>[01:03.32]하늘이 하는 일 돌릴 수 없는 일<br>[01:11.39]이렇게 사는게 힘들면 그녈 보내줄텐데<br>[01:19.51]죽어서 보라고 그래서 보라고<br>[01:26.42]그때라도 사랑한 마음이 남아있게된다면<br>[01:34.53]그때쯤에<br>[00:00.00]<br>[01:42.93]어딜가도 그대만 보여서<br>[01:49.88]매일매일 나를 지우고 살아<br>[01:57.28]한순간도 바람처럼 떠날줄 모르고<br>[02:04.71]죽어도 내가슴이 그댈 떠나보내지 못한 이유는<br>[00:00.00]<br>[02:15.49]사랑이라서 사랑이라서<br>[02:23.68]가슴가득 맺힌 사랑이라서<br>[00:00.00]<br>[02:29.68]하늘이 하는 일 돌릴 수 없는 일<br>[02:37.81]이렇게 사는게 힘들면 그녈 보내줄텐데<br>[02:45.79]죽어서 보라고 그래서 보라고<br>[02:52.51]그때라도 사랑한 마음이 남아있게 된다면<br>[03:00.90]그때쯤에<br>[00:00.00]<br>[03:04.66]간절히 바랬어 너에게 가는일<br>[00:00.00]<br>[03:33.19]하늘이 하는 일 돌릴 수 없는 일<br>[03:41.80]이렇게 사는게 힘들면 그녈 보내줄텐데<br>[03:49.23]죽어서 보라고 그래서 보라고<br>[03:56.56]그때라도 사랑한 마음이 남아있게된다면<br>[04:04.29]그때쯤에<br>[/code]

PS. HTTPService에서 xml전송해서 하는 거 어떻게 하는지 몰랐는데, 그냥 httpservice에 있는 request객체에 xml을 생성해서 넣어주면 된다는....-_-

 
Posted by 머드초보

댓글을 달아 주세요

  1. BlogIcon 쿠나 2010.01.17 16:27  댓글주소  수정/삭제  댓글쓰기

    우와~ 감사합니다 :)
    POST 헤더를 어떻게 만들어서 보내야하는지 전전긍긍했는데 도움 많이 되었어요~

    • 머드초보 2010.01.19 11:57  댓글주소  수정/삭제

      아....도움이 되셨다니 다행이네요^^
      근데 이글은 알송가사서버에 비정상접속에 대한 글에서....얻으셨다니!-_-

  2. plz 2010.05.31 00:46  댓글주소  수정/삭제  댓글쓰기

    죄송한데 이걸 C++로 바꿔주시면 안될까요

  3. 궁금이 2010.07.24 05:09  댓글주소  수정/삭제  댓글쓰기

    for (i = 0; i < 50000; i++)
    {
    if (fs.readUnsignedByte() == 255)
    {
    var a:int = fs.readUnsignedByte();
    if ((a >> 5) == 7) //굳이 5와 7로 값을 정한이유가 왜죠?
    {
    fs.position += -2; //포지션이 두칸뒤로가면 계속 돌지않나요?
    break;
    }
    }
    }

    • 머드초보 2010.07.25 19:04  댓글주소  수정/삭제

      헐....저도 기억이....나질 않네요-_-
      몬가 ID3값에 공백이 있어서 몬가 처리해놓은 것 같은데....-_-

  4. tri**** 2010.11.03 09:32  댓글주소  수정/삭제  댓글쓰기

    정말 배울게 많은 곳이에요~

    Flex 공부하면서 많이 보고갑니다.

  5. Dect 2012.01.08 16:37  댓글주소  수정/삭제  댓글쓰기

    꼭 ID3를 보내야하나요?
    그냥 HTTP만 보내도 될듯한데..

  6. Dect 2012.01.11 20:23  댓글주소  수정/삭제  댓글쓰기

    죄송합니다. 한가지만 더 여쭙겠습니다..;

    SetFilePointer fh, ExistSize, 0, FILE_BEGIN
    ReadFile fh, Buff(0), 163840, 0, ByVal 0

    ExistSize 로 헤더의 크기를 구한다음
    그 헤더의 끝. 그러니까 순수 음악데이터를 가져온후
    163840 까지 읽어 들였습니다. 그러고 ByteHash 를 돌려
    값을 구했는데요.. 자꾸 딴 값이 나옵니다.ㅠㅠ

    JavaScript는 아니지만 원리를 도저히 모르겠습니다.. ( MD5에서 3일째.. )

    MD5가 다른건가요? 아니면
    저 가져오는 소스가 잘못된건가요?

  7. BlogIcon 토리;s 2012.02.18 06:35  댓글주소  수정/삭제  댓글쓰기

    전 빌더를 안써서 ..httpService 가없다는 비극이!

  8. BlogIcon 토리&#039;s 2012.05.21 20:23  댓글주소  수정/삭제  댓글쓰기

    SOAP 요청부가 바뀐듯한데...전..분석해도 모르겟네요ㅜ

  9. BlogIcon 토리&#039;s 2012.05.22 01:21  댓글주소  수정/삭제  댓글쓰기

    아. 그리고 wsdl 은
    http://lyrics.alsong.co.kr/alsongwebservice/service1.asmx?wsdl
    요깁니당.

  10. BlogIcon 혁이s 2013.02.28 14:31  댓글주소  수정/삭제  댓글쓰기

    혹시 웹에서도 가수+노래제목 으로 가사데이터를 가져올수 잇나요?

 
Flex ANT관련 자료는 지돌스타님이 자세히 써주셨기때문에 참고해주세요.
http://blog.jidolstar.com/505

mxmlc로 컴파일을 해본적이 없어서 작성하는데에 욕봤습니다.
우선 ANT에서 제공하는 태그들이 있는데요. 그걸 이용해서 하려고 하는데 잘 안돼서-_- 그냥 exec로 작성했습니다 ㅠㅠ

그냥 rsl을 사용하지 않은 프로젝트는 ant로 매우 쉽게 할 수 있는데, RSL을 사용하면 조금 복잡해집니다.

RSL로 사용할 Flex Library Project를 하나 만듭니다. 그리고 클래스나 MXML을 추가하게 되면 bin디렉토리에 *.swc파일이 생깁니다. 이걸이용해서 메인프로젝트에서 컴파일을 해야합니다. 또한 *.swc파일을 이용해서 optimizer된 *.swf를 만들어야합니다.
[code]<target name="optimizer">
    <unzip src="${SWC파일}" dest="${SWC파일을 풀어놓을 디렉토리}" />
    <exec executable="${optimizer.exe파일 경로}">
        <arg line="-input '${SWC파일 풀어놓은 디렉토리}/library.swf'" />
        <arg line="-output '{아웃풋할 파일명.swf}'" />
    </exec>
</target>[/code]
몰랐는데, SWC파일 풀면 library.swf가 나오는데, 그걸 optimizer.exe한 것이 Flex Builder에서 나오는 swf파일이랑 같은것이더라구요(알고보니 나만 몰랐던거....다 알고있었음!-_-)
이렇게 하면 swf파일이 만들어집니다.
그럼 메인프로젝트 컴파일 하려면 이런식으로 하면 됩니다.
[code]<target name="compile">
    <exec executable="${mxmlc.exe파일 경로}">
        <arg line="-verify-digests=false" />
        <arg line="-runtime-shared-library-path '${rsl swc파일경로}' '${rsl경로위치url}'" />
        <arg line="-o '${아웃풋 경로}'" />
        <arg line="'${소스mxml메인파일}'" />
    </exec>
</target>[/code]
compile하기전에 optimizer target을 depends해야함^^
아마 verify-digests는 properties에서 설정할 때 체크하는 그것일꺼에요. 음..저는 이런식으로 하니까 되더라구요-_- -runtime-shared-library-path에서 swc파일 경로랑 rsl경로위치url(나중에 파일을 올릴 때 해당 위치에 있어야할 url입니다)로 지정하니 되더군요. 이것때문에 고생을 좀 해서-_-
메인프로젝트에 SWC파일을 LIB로 사용한다면 이런식으로 해야하구요^^
[code]<arg line="-library-path+='${basedir}/libs/Mate_08_8_1.swc'" />[/code]
ftp올리는 것도 지돌스타님 블로그에 잘 정리 되어있음!
http://blog.jidolstar.com/506
이러면 원클릭 배포가 가능해짐-_- 귀차니즘을 위한 ANT임!-_-
 
Posted by 머드초보

댓글을 달아 주세요

  1. BlogIcon 지돌스타 2009.06.22 22:33  댓글주소  수정/삭제  댓글쓰기

    좋은 글이네요~ 트랙백도 걸어주시면 감사 ^^

    • 머드초보 2009.06.23 12:09  댓글주소  수정/삭제

      아...별거 없는데 ㅠㅠ 감사합니다 ^^
      사실 command line컴파일을 그냥 ant로 쓴거라-_-
      방문해주셔서 항상 감사해요~ ^^

  2. BlogIcon 검쉰 2009.06.24 17:19  댓글주소  수정/삭제  댓글쓰기

    저도 귀찮아서 ANT 써야겠다능 ㅎㅎ

 
음... air.swf를 이용하면 설치된 애플리케이션을 실행할 수 있으며, Adobe AIR가 설치가 되어있지 않으면 설치도 할 수 있는 기능이 있는 SWF입니다.
http://airdownload.adobe.com/air/browserapi/air.swf

음....문제점이 한쪽에서 air.swf를 로딩하고 나서 getApplicationVersion(애플리케이션이 설치되었는지 확인하는 함수)을 하고 있습니다. 그런데 다른 한쪽에서 air.swf를 로딩해서 getStatus(air가 설치되어있는지 상태값 받기)를 하면 air가 설치 되어있음에도 불구하고 available(AIR설치는 안되어있으나 설치가 가능함)을 받는 경우가 발생합니다.

그래서 더 찾아보니 우야꼬님의 글을 보다가 알았는데요. air.swf 없이도 AIR애플리케이션을 설치하고 실행할 수 있다고 한다는 글을 보았습니다. 그래서 이 현상이 버그인지 확인해보려고 직접 구현하려고 했지만........-_-
생각보다 조낸 어렵네요-_- 우야꼬님께서 ProductManager클래스를 이용해야 한다는 힌트만 주셔서 ㅠ
ProductManger는 뭐하는 놈인지 검색해도 잘 안나와요-_- 어디서 뜯어봐야하는지ㅠ 근데 이놈을 이용해서 AIR애플리케이션을 리스타트하는 프로그램을 만들 수도 있더라구요.
http://www.hufkens.net/2009/03/how-to-restart-an-air-application-from-code/
productmanager가 air프로그램 실행하고 그러는 것 같긴 한데, launch라는 함수가 있는데 이것에 대한 커맨드라인 명령어 같은 게 설명이 잘 안나왔네요 ㅠ

암튼, air.swf를 로딩해서 getApplicationVersion을 무한 반복하는 애플리케이션을 만들고, 그걸 2개를 띄워볼께요-_-
AirService.as
[code]package
{
    import flash.display.Loader;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.net.URLRequest;
    import flash.system.ApplicationDomain;
    import flash.system.LoaderContext;
   
    public class AirService extends EventDispatcher
    {
        private var _loader:Loader;
        public var _service:Object;
       
        public function AirService()
        {
            _loader = new Loader();
            var context:LoaderContext = new LoaderContext();
            context.applicationDomain = ApplicationDomain.currentDomain;
            _loader.contentLoaderInfo.addEventListener(Event.INIT, initHandler);
            var swf:String = "http://airdownload.adobe.com/air/browserapi/air.swf";
            var request:URLRequest = new URLRequest(swf);
            _loader.load(request, context);
        }
       
        private function initHandler(event:Event):void
        {
            _service = _loader.content;
            dispatchEvent(new Event(Event.COMPLETE));
        }
       
        public function getStatus():String {
            return _service.getStatus();
        }
       
        public function getApplicationVersion(applicationId:String, publisherId:String, callback:Function):void
        {
            _service.getApplicationVersion(applicationId, publisherId, callback);
        }
       
        public function installApplication(url:String, runtimeVersion:String, parameters:Array = null):void
         {
            _service.installApplication(url, runtimeVersion, parameters);        
         }
        
         public function launchApplication(applicationId:String, publisherId:String, parameters:Array = null):void
         {
             _service.launchApplication(applicationId, publisherId, parameters);
         }
    }
}[/code]
Main.mxml
[code]<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="vertical" verticalAlign="middle"
    applicationComplete="applicationCompleteHandler()" width="100%" height="100%">
   
    <mx:Script>
        <![CDATA[
            import adobe.utils.ProductManager;
           
            private var airService:AirService;
           
            private function applicationCompleteHandler():void
            {
                airService = new AirService();
                airService.addEventListener(Event.COMPLETE, completeHandler);
            }
           
            private function completeHandler(event:Event):void
            {
                trace(airService.getStatus());
                ta.text += airService.getStatus() + "\n";
                if (airService.getStatus() == "installed")
                {
                    airService.getApplicationVersion("AirApplication",
                        "2D0F512A27635B8D26E3FE2622F4AAEDDA9D3CFC.1",
                        applicationVersion);
                }
            }
           
            private function applicationVersion(version:String):void
            {
                trace("version=" + version + ", status = " + airService.getStatus());
                ta.text += "version=" + version + ", status = " + airService.getStatus() + "\n";
                ta.verticalScrollPosition = ta.maxVerticalScrollPosition;
                airService.getApplicationVersion("AirApplication",
                    "2D0F512A27635B8D26E3FE2622F4AAEDDA9D3CFC.1",
                    applicationVersion);
            }
           
        ]]>
    </mx:Script>
    <mx:TextArea id="ta" height="100%" width="50%"/>
</mx:Application>[/code]
두개를 띄워보면
사용자 삽입 이미지
한놈은 available을 받습니다-_- 왜그러지-_-
대체 getApplicationVersion에서 어떤 일을 하는지 궁금해지기 시작했습니다.

그래서 대처 방법으로는....-_- getApplicationVersion을 동시에 하지 않으면 돼요-_- 사용자가 클릭할 때 하면 되는데, 이렇게 되면 launchApplication을 할 때에 또 클릭해줘야 해요. launchApplication은 사용자 액션에 의해서만 되더라구요.

PS. 혹시......이 글을 보게 되시는 분들중에서.....AIR애플리케이션을 launch하는 사이트를 목격 하시면 댓글 달아주세요ㅠ

 
Posted by 머드초보

댓글을 달아 주세요

  1. 장문영 2009.06.04 15:57  댓글주소  수정/삭제  댓글쓰기

    http://msp.skbroadband.com 공인인증서 로그인 누르세요
    현재도 개발중이며 계속 버전업 중입니다.
    저도 이 현상을 겪었었습니다.우야꼬님 방명록에 물어봤던 흔적이 아직도 있을거에요...답변은 못들었지만-_-;

    추가로 air.swf 로딩을 하지않고 웹에서 Air를 launch 시키는 방법을 알게 되시면 포스팅 좀 해주세요 ㅎㅎ

    • 머드초보 2009.06.05 09:34  댓글주소  수정/삭제

      air.swf를 두군데서 로딩하나봐요
      저희도 두군데서 로딩을 해야해서 문제가 발생했는데,
      그냥 한개 로딩완료 후 다음swf에서 로딩하는 방식으로
      변경했었습니다^^
      공인인증서를 air로 하다니 대단하네요 ^^

  2. BlogIcon 우야꼬 2009.12.30 10:49  댓글주소  수정/삭제  댓글쓰기

    아이고 요즘 정신이 없어서 제대로된 포스팅을 못하고 있는데
    조만간 ProductManager에 대해서 제가 아는대로 한번 올려볼께요. ㅠ.ㅠ
    글 올리고나서 트랙백 쏘겠슴돠~ ㅎㅎ

    • 머드초보 2009.12.31 12:46  댓글주소  수정/삭제

      앗~ 우야꼬님 반갑습니다^^
      감사해요~
      아직도 저희사이트에서 AIR재설치 문제가 발생해서-_-
      저도 좀 알아보니까 getApplicationversion할 때 air.swf에서 로컬커넥션으로 어디다가 쏘는 것 같더라구요.
      음 그 과정에서 좀 문제가 생기는 것 같은데...
      암튼, 해보시면 알려주세요 ㅠㅠ

  3. 무로 2010.05.25 17:59  댓글주소  수정/삭제  댓글쓰기

    안녕하세요 요즘 AIR 2.0에서 air.swf를 이용해서 PC의 AIR Application을 실행하는
    프로그램을 개발하는 중에 AIR 2.0 Runtime이 설치되어 있음에도 불구하고 getStatus 함수에서
    계속 "available" 문자열만 리턴하는 문제가 있어 여기까지 찾아오게 되었습니다~

    위에 포스팅하신 내용과는 조금 다른것 같지만 현상은 거의 동일해서
    제가 발견한 오류를 기록하고 가겠습니다 ^^;

    제가 발견한 오류는 AIR 2.0 Runtime을 PC에 바로 설치하였을 때 발생하였습니다.
    무슨 말씀이냐면 AIR 1.5 Runtime을 설치하고 AIR 2.0(정확히는 rc1) Runtime으로 업데이트하면
    getStatus 함수에서 "installed"라는 문자열을 리턴했지만 테스트를 하기 위해서 다른 PC에
    AIR 2.0 Runtime을 바로 설치했을 때는 계속해서 "available" 문자열만 리턴하였습니다.

    AIR 1.5 Runtime을 설치했을 때는 "C:\Documents and Settings\username\Application Data\Macromedia\Flash Player\www.macromedia.com\bin\airappinstaller" 디렉토리에 파일이 생성되던데 여기 있는 파일이 없을 경우 문제가 되더군요....
    AIR 2.0 Runtime을 바로 설치하였을 경우에는 디렉토리와 파일이 생성되지 않았으며 다른 PC에 있는 파일을 복사하면 "installed"가 리턴되었습니다.
    정식 릴리즈가 나오면 해결될지 모르겠습니다...

    오늘 급하게 확인한 것이라 정확한지는 모르겠지만
    같은 원인으로 고생하시는 분이 계실까봐 몇 자 적고 갑니다.

    PS. 블로그에서 많은 도움 받고 갑니다. 감사해요~ ^^

    • 머드초보 2010.06.03 18:07  댓글주소  수정/삭제

      저희사이트는 요즘도 발생해서 ㅠㅠ
      아직도 왜그런지 모르겠어요 ㅠㅠ

  4. 아무개 2011.11.18 10:03  댓글주소  수정/삭제  댓글쓰기

    airSWF.getApplicationVersion(appID, pubID, versionDetectCallback);
    function versionDetectCallback(version:String):void {
    trace(version);
    }

    이렇게 쓰는듯.

 
ActionScript3가 제공하는 Sound클래스에서 구하는 재생시간은 구하는데 너무 오래걸립니다.
Sound객체를 생성에 Complete이벤트가 발생한 다음에야 재생시간을 구할 수 있습니다.
재생목록에 추가를 해서 그냥 간단히 재생시간을 보여줘야하는데, 100곡을 재생목록에 추가를 해버리면 AIR애플리케이션이 미친듯이 메모리를 잡아먹는 것을 볼 수 있습니다-_-;

그래서 찾아보니, mp3 Header정보를 이용해서 재생시간을 구할 수 있습니다.

재생시간 = 파일크기 * 8 / 비트레이트 로 구할 수 있습니다.
그러면 비트레이트만 구하면 되는데, 이건 MP3Header에서 찾을 수 있습니다.

MP3 BITRATE는 http://www.datavoyage.com/mpgscript/mpeghdr.htm에 의하면 MPEG버전, LAYER, Bitrate Index로 구할 수 있습니다. MP3는 각각 Frame별로 Header가 존재하는데, 거기서 위에 정보를 구할 수 있는 것 같습니다.

ID3v2태그가 있는 경우는 ID3v2태그 다음에 MP3Header가 나옵니다. 그렇다면 ID3v2태그의 길이를 구해서 그 다음부터 MP3Header를 찾아야 합니다. ID3v2태그는 길이가 가변적입니다.그래서 총길이를 알아야하는데, 총길이는 ID3v2태그 맨 앞에 나오는 10byte Header부분에서 구할 수 있습니다.

이 Header부분의 6byte~10byte까지가 ID3v2의 총 길이인데요. 여기의 값이 00 00 1F 76(00011111 01110110)이라면 각각 MSB를 제거하여 붙인 값이 총 길이가 된다더군요. 00111111110110 -> 4086byte.

우선 C#으로 구현해놓은 소스가 있습니다. 그것을 Actionscript3로 변환했습니다(구현하려니 힘들어서 ㅠ)
C#소스 -> http://www.devhood.com/tutorials/tutorial_details.aspx?tutorial_id=79

제가 변환한 AS3용 MP3Header클래스입니다. 제가 가지고 있는 MP3 대부분 테스트해봤는데 잘 되더라구요.
MP3Header.as

MP3Header클래스


사용법은 이렇게 쓰시면 됩니다.
[code]
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
    creationComplete="init()">
    <mx:Script>
        <![CDATA[
            import util.MP3Header;
            private function init():void
            {
                var mp3Header:MP3Header = new MP3Header();
                mp3Header.readMP3Information("D:/눈물이 글썽 - 서진영.MP3");
                trace("BITRATE = " + mp3Header.intBitRate);
                trace("Frequency = " + mp3Header.intFrequency);
                trace("Mode = " + mp3Header.strMode);
                trace("LengthFormatted = " + mp3Header.strLengthFormatted);
                trace("Length = " + mp3Header.intLength);
            }
        ]]>
    </mx:Script>   
</mx:WindowedApplication>
[/code]
[code]
BITRATE = 64
Frequency = 44100
Mode = Stereo
LengthFormatted = 04:00
Length = 240
[/code]

 
Posted by 머드초보

댓글을 달아 주세요

  1. 2008.11.20 13:27  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

    • 머드초보 2008.11.21 16:29  댓글주소  수정/삭제

      와우 감사합니다 ^^
      이거 블로그코리아의 리뷰룸같은건가요? ^^

  2. 지나가다가 2008.11.21 18:12  댓글주소  수정/삭제  댓글쓰기

    ID3 태그가 있는 경우는 괜찮겠지만, 그 외에 저 위의 계산식으로는 CBR에 대해서만 정확히 나오게 됩니다.
    VBR에 대해서는 정확한 시간이 안나오죠..

    • 머드초보 2008.11.21 23:28  댓글주소  수정/삭제

      아네 ^^ 맞습니다. 제가 VBR은 시간을 어떻게 구하는지몰라서 ㅠ
      저기 C#구현체는 VBR인 경우도 추출할 수 있게 구현이 되어있습니다.
      그래서 제가 포팅한 as3용도 VBR MP3의 재생시간을 잘 구해옵니다^^

  3. 2008.12.11 15:43  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

    • 머드초보 2008.12.12 02:23  댓글주소  수정/삭제

      안녕하세요~
      혹시....프로젝트 이름이 MP3Header가 아니신지?
      아니라면MP3Header.as에 있는 package이름이 해당 폴더에 정확히 있는지가 중요합니다.
      지금 파일에는 rtplayer.util이라고 되어있는데, 만약 이 클래스파일이 src 바로 아래 있다면 rtplayer.util을 지워야합니다.
      음...안되시면 다시 또 연락주세요 ^^

  4. air어려워 2009.02.17 09:21  댓글주소  수정/삭제  댓글쓰기

    본문과 관계없지만
    에어를 윈도우창이 아닌 웹브라우저나~~ flex등에서 호출해서 사용할 수 있는 건가요?
    플렉스로 로컬파일 경로가져오는 부분을 찾다가 에어를 사용해서 해결했다기에 검색하다 보니 여기까지 오게 되었네요~~~

    • 머드초보 2009.02.18 20:40  댓글주소  수정/삭제

      안녕하세요!
      에어는 데스크톱에서 돌아가는 애플리케이션입니다. Flex에서 호출하고 그런 것이 아닙니다. Flex를 이용해서 에어애플리케이션을 만들 수 있죠.
      로컬파일 접근은 Flex에서 할 수 없습니다. Flex에서 특정파일을 선택하면 가능하지만, 임의로 타 컴퓨터에 있는 파일을 접근할 순 없습니다^^

 
다...다른 방법을 검색해서 구했습니다-_-;
하지만, 이건 한글은 이제 잘 읽는 것 같은데......한자를 못 읽습니다-_-; 원래 안되는건가....-_-;

우선 ID3Parser 링크입니다. 매우 빠른 속도로 ID3데이터를 가져옵니다.
http://blog.ashier.com/2007/11/08/id3-parser/

여기서 한글을 읽을 수 있게 수정하는 부분이......
보면 ID3데이터를 추출해오는 부분이 있습니다.
거기서 한글로 추출할 수 있게 변경합니다.

[code]
private function parseFrames():void {
    var id:String = "";
    var size:uint = 0;
    if(fs.position <length) {
        try {
            id = fs.readUTFBytes(frameIdSize);
            size = fs.readUnsignedInt();
            if (version>= 3) {
                fs.readByte();
                fs.readByte();
            }
            if(id.match(regEx)) {
                var obj:Object = new Object();
                obj.encoding = fs.readByte();
                obj.text = fs.readUTFBytes(size - 1);
                frames[id] = obj;
            }
            parseFrames();
        }catch(e:Error) {}
    }
}
[/code]
이 부분이 있는데요. 한글을 읽어오는 readUTFBytes 부분을 바꿔줍니다.
[code]
//obj.text = fs.readUTFBytes(size - 1);
if (obj.encoding == "1")
{
    obj.text = StringUtil.trim(fs.readMultiByte(size - 1, "unicode"));
}
else
{
    obj.text = StringUtil.trim(fs.readMultiByte(size - 1, "EUC-KR"));
}
[/code]
보니까 obj.encoding이 1인 값은 unicode로 인코딩 된 것 같아요. obj.encoding이 0인 값은 EUC-KR로...
이렇게 하니까 잘 되네요....가끔 공백을 추출해오고 그래서 trim처리했습니다.

아래글은 ID3v1방식 추출 방법 및 ID3v2의 다른 추출 방식 입니다^^ 참고하세요~
http://mudchobo.tomeii.com/tt/356
 
Posted by 머드초보

댓글을 달아 주세요

  1. BlogIcon 토리's 2012.02.20 06:53 신고  댓글주소  수정/삭제  댓글쓰기

    이거 링크가 깨졋?네여 ㅜㅜ