Archive for the ‘QuickTime’ Category

QuickTime reference movie에 대하여

QuickTime은 그동안 Reference Movie라는 것을 제공해 왔다.
Reference Movie라는 것은, 예를 들어 Movie file A가 있을때, 그 안에는 실제로 영상이나 소리와 같은 데이터가 있지 않고, 그 파일 외부에 별로도, 영상과 소리 데이터를 가지고 있는 파일(들)을 가르치는 pointer(reference)만 있는 것을 의미한다. 물론 영상 데이터는 내부에 있는데, 소리 데이터만 외부에 있는 경우도 reference movie라고 할 수있다.

그런데, 이 reference movie는 프로그래머 입장에서 볼 때, 그 구성이 다양할 수있다.
이를 알아보려면 movie 파일과 QTMovie 혹은 Movie로 표현되는 audio/visual data를 포함할 수있는, container 구조의 atom, 그리고 실제 audio/visual data (이를 essence라고 한다)에 대한 이해가 필요하다.

movie file은 말 그대로, 동영상 파일이다. 디스크에 특정한 포맷으로 저장이 된다.
QTMovie/Movie는 movie file 속에서 실제로 audio/visual 데이터나 외부 파일에 대한 reference, QuickTime VR, sprite 혹은 (이젠 deprecated되었지만) QuickDraw 3D와 같은 비 시간적 데이터들, 그리고 자막이나 timecode와 같은 다양한 media를 포함하는 최상위 data structure이다.

QuickTime은 파일속에 QTMovie/Movie가 있고, 그 속에 QTTrack/Track으로 대변되는 트랙들, 그리고 각 트랙위에 QTMedia/Media로 대변되는 미디어가, 그리고 각 미디어 속에는 실제 data sample들이 있다.

여기서 File부터 Media까지는 이해가 될텐데, 미디어와 실제 data sample의 차이는 무엇이냐 싶을 것이다.
Video tape과 같은 실제 물리적 장비(?)를 보면, 그 안에 어떻게든 여러개의 트랙 (이를테면 복수개의 영상 트랙/오디오 트랙)들이 있을테고,각 트랙에 비디오나 오디오 데이터가 저장된다.
그러므로 쉽게 생각하면 Track까지는 이해가 쉽게 되고, 그냥 Track위에 audio/video 데이터들을 얹을 수있게 만들면 되지 않겠나 싶은데, 이게 생각보다 한 층의 레이어가 더 필요하다.
예를 들어 한 트랙에 오디오 데이터를 얹는다 하자. 오디오 데이터의 특정한 형식이 필요할 것이다. 그럼 그런 것을 받아들이게 만든 track의 데이터 스트럭쳐가 다른 데이터 형도 쉽게 받아들일 수있을 까? 즉 비디오 데이터를 받아들일까?
아. 물론 받아 들이게 만들 수는 있다. 하지만 점점 어떤 체계가 잘 잡힌 모양은 무너지기 시작할 것이다.

여기에 더 생각해보자. 자막을 넣는다면? 타임 코드를 넣는다면? 혹은 비 시간적 데이터들, 예를 들어 sprite를 넣는다면?
( 93년쯤이었던 것으로 기억한다. Apple의 샘플 QuickTime 영상 중에는 동영상 내에 sprite가 들어가서, 일종의 갤라거 비디오 게임처럼, 움직이는 동화상을 배경으로 비행기였던가 공이었던가가 왔다 갔다 하는, 그리고 그 물체를 키보드론가 조작이 가능했던 것이 있었던 것으로 기억한다)

아.. 굉장히 복잡해진다. 어떻게 데이터 구조와 알고리즘의 일관성을 유지하면서 이런 다양한 미디어를 트랙에 잡아 넣을까?
여전히 잘 이해가 되지 않는 부분이다.
실제로 2000년 쯤이었나? 1999년이었나. 광주 KAIST에서 MPEG-4의 의장이었던 프랑스 사람인가가 와서, 그때 MPEG-4의 표준이 막 정해지고 나서, MPEG-4가 어떤 것을 지향하고 어떻게 바뀔 것인지 등에 대해서 설명을 해주었던 session이라고 할까 conference라고 할까에 갔었다. (KAIST 학생들은 이런게 부럽다. 질 좋은, 그 현장에서의 실제 관련된 사람들이 방문해서 설명해 주니까. 물론 막상 참여해서 내용을 들으면 그 내용이 별거 아닐 수도 있다. 하지만 그런 기회를 갖느냐 안갖느냐 자체가 의미가 상당하다.)
거기서 MPEG-4를 연구하시던 교수님 두어분이 질문을 했는데, 어떻게 MPEG-4가 비 시간적 데이터를 시간적 데이터와 같이 한 파일에서 처리할 수있느냐는 것이었다. 지금은 MPEG-4가 그때에 비해서 많이 퇴색한 것 같다. 사실 최근까지 Simple Profile만 이용을 해 왔고, 최근 들어와서야 advanced codec인 AVC / H.264를 본격적으로 사용하니까. 근데 MPEG-4는 그 이외에도 지향하는 여러가지가 있다.
예를 들어, 변하지 않는 배경은 한번만 인코딩하고, 그 위에서 움직이는 사물들만 감지를 해서, 그들만 encoding하고 decoding한다던가, 비시간적 데이터를 시간적 데이터와 같이 표현을 한다던가. ) MPEG-4로 이루려고 하던 상당수를 이미 QuickTime은 하고 있었다.
자막도 검색이 가능해서, 영화를 보다가 이런 저런 대화가 나오는 부분을 키보드로 검색할 수있었다.
이런 식으로 QuickTime은 굉장히 다양한 앞선 기술을 90년대 초에 이미 지원을 하고 있었지만, 그때는 Apple이 바야흐로 암흑기로 들어가고 고생을 하기 시작하던 때라, 그다지 사람들에게 (일반인)는 appeal하지 못했던 것으로 안다. 이때가 Bill Gates가 Apple에게 AVI 포기할테니 QuickTime 내놔라라고 협박하던 때다.

사족이 길었는데, 자.. 이렇게 다양한 미디어를 표현하려면 그 데이터를 바로 트랙위에 싣는 디자인으로 갈까 아니면 일종의 adaptor 데이터 구조를 만들어서 넣을까? QuckTime은 후자의 것을 선택했다. (물론 내가 QuickTime의 소스코드를 본 것은 아니다. 하지만 구조를 보면 그것을 짐작할 수있다.)
내가 볼때 그 adaptor 역할을 하는 것이 Media data structure이고, QTKit에서는 이것을 QTMedia로 표현한다.
그래서 Track위에 오디오/비디오 데이터가 바로 올라가는게 아니라 Media란 것이 올라간다. 그리고 그 Media 안에 바야흐로 실제의 데이터들이 올라간다. 그리고 그 실제의 데이터들을 QuickTime에서는 data sample이라고 부른다.

<Fig.1> QuickTime structure

이 정도만 알면 일단 QuickTime 구조체의 대략적인 면은 훑은 거라고 할 수있다.
이제 본래의 주제로 돌아와서, Reference Movie를 살펴보자.
앞에서 잠시 말했듯이 Reference Movie라고 하면, 실제의 데이터는 다른 파일에 있고, reference movie 자체는 그 외부 파일에 대한 reference만을 가지고 있다고 했다. 그런데 여기서 잠시 생각을 해보면, 어떤 부분이 reference가 되느냐가 다를 수가 있다.
즉 audio/video 데이터가 고스란히 들어있는, Movie 파일을 위한 부분은 아닌 QTMovie/Movie만을 의미하는 부분이 외부 파일로 있고, Reference Movie file은 그 외부 파일을 pointing할 수가 있다. 그 QTMovie/Movie 만을 의미하는 부분은 CreateMovieStorage()로 만들어질 수있다. ( <Fig.2>에서 볼 수있듯이, movie 파일이 movie data structure를 가지고 외부의 데이터 파일을 참조하는 것은, QuickTime에서는 그냥 movie file이라고 불리지, reference movie file이라고 불리지 않는다. 단지 외부 파일을 reference한다고 reference movie는 아니라는 것이다. 현재까지 내가 했던 프로젝트에서, 내가 현재 있는 회사의 사람들은 두번째의 경우를 reference movie라고 부르는데, “의미상” 그렇다는 것으로 이해해야지, QuickTime에서 정의된 “정의”는 아닌 것이다. 회사에서 일하다보면 이런 것을 조심해야 한다. 기존에 하던 사람들이 설명을 해 줄때, 기술적인 부분을 잘못 기술할 수있고 그것이 헷갈리게 할 수있다. )

<Fig.2> Classification of Movie Files

이 부분에 대해서는 QTKitCreateMovie라는 샘플 프로젝트의 quicktimeMovieFromTempFile 메시지를 보면 어떻게 만들어지고 사용되는지 볼 수있다. 이 QTKitCreateMovie라는 샘플에서는 tmp 디렉토리에 Movie만을 저장하는 임시 파일을 만들어서 Reference Movie가 그것을 referencing하게 되어 있다. 그리고 flattenToFilePath라는 메시지를 보면 저장시에 flatten을 할지 말지를 정해 줄 수가 있다.
flat하게 만드는 것은 movie file을 self-contained movie로 만드는, 즉 reference movie의 반대로 만드는 것이다.
여기서 flatten을 하도록 소스를 바꾸면, 생성되는 QuickTime movie file은 더 이상 그 임시의 파일을 reference하지 않고 그 자체에 모든 데이터를 저장한다.

자. 생각을 해보자. flatten을 하지 않은 상태에서, 정지 사진을 movie에 import하면 어떻게 될까?

 

<Fig.3> A reference movie pointing to an external file with "Movie" structure which refers external files

 

<Fig.4> A reference movie pointing to an external file with "movie" structure and embedded media data

위와 같은 두 가지의 형태가 될 수있다.
그런데 flattening하는 것은 movie를 self-contained movie로 바꾸어 주는 것을 의미하는데, <Fig.3>의 경우엔 실제 미디어를 가지고 있는 파일까지 movie 파일 내부로 가지고 오는 것일까? 아니면, movie 구조를 포함한 파일을 movie file로 짚어 넣는 것일까?실제로 해보면 양쪽 다하는 것을 알 수있다. 그렇다면 각각의 형태는 어떻게 만들어야 할까?

문제는 어떻게 하느냐에 따라 달라진다.

여기에 대해서는 다음 포스트에서 알아보기로 하자. (이 포스트도 너무 길고, 이젠 좀 자야겠다)

QuickTime에서 TimeScale은 정확하게 무엇일까?

이제 Lion이 나온 시점에 QuickTime API에 대해서 쓸 필요가 있겠느냐만, 그래도 여전히 오래된 코드들은 존재하고, 그것을 이해할 필요가 있다. QuickTime은 time-based media에서 non-time-based media까지 커버하고, 단순한 재생용 API가 아니라, 편집이 가능하도록 만들어진 API로 굉장히 잘 만들어졌다.

하지만 그 “잘 만들어졌다”라는 관점은 지원되는 기능에 대한 것이지, 사용하기 쉽게 만들어졌다거나, 정의된 데이터 形이나 기타의 것이 잘만들어졌다는 것은 아니다.

여러가지 중에서 이해하기 곤란한 것이 있는데, Timescale이란 것이 그것이다.
QuickTime의 timecode에 대한 것은 일전에 한번 다루었다. 하지만 충분치 않아서 이번에 완결을 해 볼까 한다.

우선 QuickTime의 시간 표현 법을 보자

12:30:24:1503/3000
12:30:24:12/2997

저 포맷은 다음과 같은 내용이다.
hh:mm:ss:ff/timescale

hh: 두자리의 시간
mm : 분
ss : 초
ff : frame 번호
timescale : QuickTime time scale

여기서 time scale이 문제다. 그리고 저 frame 번호.
어떤 것은 frame 번호가 4자리로, 어떤 것은 2자리로 나와 있다.
과연 두번째 것은 12번째 프레임이란 뜻일까? 혹은 1503은 정말 1503번째 프레임이라는 뜻일까? 저 프레임 번호는 time scale로 본 프레임 번호이다. 그리고 저렇게 timescale 자체가 4자리 일때는 4자리로 봐야 한다. 즉 12처럼 두자리로 나타나질때는 100을 곱해서 1200으로 본다.

왜 QuickTime을 만드는 사람들이 저것을 일관적으로 하지 않았는지는 의문이다. 하지만 여러 미디어 파일을 검사해보고, 실제로 프레임을 하나 하나 다뤄본 결과, 저 frame 번호를 그렇게 해석해야 한다는 것을 알았다.

그렇다면 time scale은 무엇인가? 저것은 해당 퀵타임 파일을 만든 사람이 어떤 번호를 부여하느냐에 따라 의미가 달라지는데, 대부분의 예제를 보면 fps * 100을 한 숫자들이다. 여기서 참 이상한 것은 29.97xxx과 같은 NTSC의 fps인데, 그냥 2997로 표현한다. 그리고 실제 내부에서 계산할때도 2997로 한다.
SMPTE 타임코드와 MPEG을 다뤄보신 분들은 다음과 같이 계산을 할 것이다.

30 * 1000/1001 = 29.97xxx

이렇게 해야 프레임이 밀리지 않지 그냥 29.97로 하드 코딩해 버리면, 프레임이 밀리는 현상이 생긴다.
근데 이것을 QuickTime에서는 그냥 2997로 계산해 버린다.

근데 이전의 포스팅에서도 언급되었지만, 이것이 꼭 fps * 100일 필요는 없다.
이를테면 default 값은 600이다.
혹은 임의로 1000이나 400 등을 해도 된다.
그런데 결론부터 말하자면 fps * 100이 편하다.
왜 그럴까? 사실 그건 직접 생각해 보면 파악할 수있고, 이 포스팅의 요지는 과연 이 time scale이 무엇이냐는 것이다.

Apple의 QuickTime reference를 보면 이게 명확하게 정의가 안되어 있다. 이런 중요한 것은 한 섹션이나 작은 챕터로 만들어도 좋겠는데, 그다지 잘 안되어 있다.
최근에 다음과 같은 내용을 발견했다.

About Movie Time
At the most basic level, the Movie Toolbox allows you to process time based data. As such, the Movie Toolbox must provide a description of the time basis of that data as well as a definition of the context for evaluating that time basis. In QuickTime, a movie’s time basis is referred to as its timebase. Geometrically, you can think of the time base as a vector that defines the direction and velocity of time for a movie. The context for a time base is called its time coordinate system. Essentially, the time coordinate system defines the axis on which the time base vector is plotted. The smallest single unit of time marked on that axis is defined by the time scale as the units per absolute second.

QuickTime에서 시간 좌표계를 설정하는데, 그 좌표계에서는 time base vector가 찍히는 것이라고 되어 있다. 그리고 그 좌표계에서 가장 작은 단위로 좌표 축에 찍히는 단위는 “절대 시간” 당 몇 유닛이냐는 것이다
음.. 잘 이해가 되지 않는다.

다행스럽게도 그 다음 섹션에 더 명확하게 설명이 나와있다.

Time Coordinate Systems movie’s time coordinate system provides the context for evaluating the passage of time in the movie. If you think of the time coordinate system as defining an axis for measuring time, it is only natural that this axis would be marked with a scale that defines a basic unit of measurement. In QuickTime, that measurement system is called a time scale.

A QuickTime time scale defines the number of time units that pass each second in a given time coordinate system. A time coordinate system that has a time scale of 1 measures time in seconds. Similarly, a time coordinate system that has a time scale of 60 measures sixtieths of a second. In general, each time unit in a time coordinate system is equal to (1/time scale) seconds. Some common time scales are listed in Table 1-1.

일단 time scale의 의미는 QuickTime에서 시간 축에서의 측정 단위다라는 것이다. 이 말은 cm가 길이를 재는 단위이다. 뭐 이런 수준의 설명이다. 그보다는 두번째 문장의 첫 줄에서 더 명확하게 정의를 내렸다.
즉 주어진 시간 좌표계에서 1 초당 몇개의 time unit이 지나가느냐라는 것이다. 더 쉽게 말하면 1초를 몇개의 구간으로 나누느냐이다.

time scale의 정의
1초당 몇개의 time unit이 지나가느냐 혹은 1초를 몇개의 구간으로 나누느냐.

예 : 1 초를 1000개의 구간으로 나누면, 두 눈금간의 시간 거리는 1/000 초이다. 이것은 1 msec이다.
이것을 QuickTime의 time scale로 말하면, “time scale이 1000이다”라고 말한다.

위의 둘째 문장에서 나온 예를 생각해 볼까? time scale이 60이라는 것은, 1초를 60개의 구간으로 나눈다는 것이다. 즉 1초에 60개의 time unit이 지나간다. 이때 한 time unit의 시간은 1/60 초이다.
일반화 해서 말하자면, 한개의 time unit은 1/time scale이다.
간단한 산수다.

자 그럼 왜, fps * 100을 time scale로 하는 경우가 많은지 생각해 보자.
아니 100을 곱하건 뭘 곱하건, 기본이 fps으로 한다는데 중요한 의미가 있다.

자 PAL의 25 fps을 생각해 보자.
이것은 1초에 25장의 프레임을 보여준다. 만약 time scale을 25로 한다면, 1초에 25개의 time unit이 지나가니까, 1장당 1 time unit이 되는 것이다. 만약 같은 frame rate에서 time scale을 30으로 해보자, 혹은 45로 해보자. 계산이 슬슬 복잡해지기 시작하고, 나누어도 딱 떨어지지 않는다. 어차피 time based media는 한 프레임, 혹은 한 샘플을 표시하고 다음 것을 표시하는데 얼마나 시간을 지연시키고, 몇개 프레임/샘플 후의 시간은 얼마다라는 것을 아는 것이 중요하기 때문에, 1 프레임/샘플당으로 time unit을 설정하면 편할 것이다.

그럼 여기에 왜 100을 곱할까? non drop frame인 경우야 별 문제가 안되겠지만, 23.976이나 29.976과 같은 나누어서 딱 떨어지지 않는 frame rate이 존재한다. NTSC와 같은 것이 대표적이다.
이것은 24 * 1000/1001 혹은 30 * 1000/1001로 계산을 한다.
이런 frame rate를 가지는 미디어를 다룰때, 좀더 세밀하게 시간을 계산해야할 필요가 있다. 왜냐하면, 딱 떨어지지 않는 숫자기 때문에, 매 2초마다 1장을 drop 시킨다던가 할 필요가 있는고, 편집을 하려해도 이런 세세한 제어가 필요하기 때문에 그냥 fps를 timscale로 쓰지 않고, 그것에 어떤 수를 곱해서 더 세밀하게 만드는 것이다.

여기서 주의해야 할 것이 있다. QuickTime의 atom에 frame rate를 기록해 두고, duration도 계산해서 넣어야 하는데, 이때 a * 1000/1001을 할까? 실제로 보니 그렇게 하지 않고, 예를 들면 23.97로 넣는다.
이것은 그냥 meta 정보 역할을 하는 것같다. 만약 실제로 그 atom을 읽어서 비디오 에디터등을 만든다면, 그런 값을 보면 실제의 계산을 해 줄 필요가 있을 것이다.

그리고 또하나, frame drop을 한다는 것은 실제로 어떤 프레임을 버리는 게 아니다.
frame은 하나도 버리지 않고, 단지 time code marking을 마치 프레임 드롭이 된 것처럼 하는 것이다.

예를 들어, 1초, 2초, 3초, 이러다가 4초가 아니라 5초로 마킹을 한다.
그럼 4초에 해당하는 frame을 버린 것 같은 모습이 된다. 실제 4번째 장은 5초에 대응할 뿐이다.

자 그럼 여기서 한가지만 더.
제일 처음으로 가서 QuickTime에서의 시간 포맷을 보자.

12:30:24:1503/3000

여기서 명심해야 할 것이 있다.

우선 /는 나누기가 아니라, time code와 time scale을 구분해 놓은, 구분자이다.
둘때로 1503은 frame number에 대응을 하지만, 사실 “시간”의 표현이다.
SMPTE time code 포맷은 “시간:분:초:프레임 번호”로 분명히 time code임에도 frame 번호는 몇번째 프레임이냐지, 그 프레임이 시간 축에서 차지하는 시간을 의미하지 않는다. (물론 환산이 가능하지만)
반면에 QuickTime의 timecode는 순수하게 시간의 요소들만으로 구성되어 있다.
그리고 각각의 시간 값을 time value라 한다.
즉 위의 QuickTime 시간 포맷에서

12:30:24:1503는 time value를
3000은 time scale을 의미한다.

정리가 잘 안되었는데, 아무튼 이것이 QuickTiem에서의 시간에 대한 전체적인 설명이다.
QuickTime에서 이 시간을 이해하면, 이해의 30%는 한 것이라고 볼 수있다.

AVFoundation and QTKit or QuickTime

I didn’t notice that AVFoundation was in Snow Leopard, but it was there in iOS.
It seems to me that AVFoundation is going to replace QTKit/QuickTime.

Here are some posts on the issue.

Steve Jobs said that Mac OS X Lion is to bring advancement in iOS to Mac OS X. It may not be only the UI, but frameworks.

ADDED : From iOS ?.? doc: The AV Foundation framework provides Objective-C interface… in your Mac OS X application.
That is why I thought it was in Snow Leopard. However, I searched it again, and it has never been in Mac OS X SDK.

Timecode QuickTime returns vs. Correct timecode for DF video

currentTime method of QTMovie and [[qtMovie attributeForKey:QTMovieCurrentTimeAttribute] QTTimeValue] returns QTTime value equivalent to these.

33 sec 28
34 sec 00 ( jump 1 frame)
34 sec 01
34 sec 02

However, the correct values should be these because frame drop should not happen within a minute boundary.
33 sec 28
33 sec 29 (continue)
34 sec 00
34 sec 01

It seems to me that there is no way to correct this timecode from QuickTime API, because the timecode from QuickTime API is already modified one by QuickTime. Additionally, when the timecode jumps seems to be inconsistent by observing how the timecodes are changed for about 3 minutes. So, there seems to be no way to correct the timecode for Drop Frame video, i.e. DF video.

Fortunately there were timecode tracks in video files I am supposed to handle.
So, by reading the timecode I have these correct results.

33 sec 28th frame

33 sec 29th frame

34 sec 0th frame

Then 2 frames should be dropped at every 1 minute. But the timecodes from QuickTime API are like :

59 sec 29 frame
1 min 00 sec 00 frame
1 min 00 sec 01 frame

The expected timecodes are :

59 sec 28 frame
59 sec 29 frame
1 min 00 sec 02 frame ( jumping two frame, i.e two frames were dropped. )

59 sec 29th frame

1 min 2nd frame

The sample program to print out timecodes can be downloaded here.

MediaHandler and x86_64 target

Snow Leopard is ready for full 64bit applications. However, it doesn’t boot into 64bit mode by default. Apple people seem to give more time for 3rd party developers to migrate their code from 32bit to 64bit.

Is it true? Yeah.. kind of… Truth is that even Apple doesn’t seem to be prepared for full 64bit environment. For example, QuickTime is not fully ready yet.
I have heard about 64bit issues with QuickTime from here and there.
Today I noticed my own.

This part of codes causes compilation error with x86_64 target.

MediaHandler is not recognized when x86_64 target is enabled

Because the MediaHandler is not recognized, it complains something else is wrong. The compiler is confused.
Then, how to solve this problem? Set the target to 32bit.

No compilation error when targeted for 32bit

So, I looked up the header files to figure out how the MediaHandler is compiled into. It was declared in Movies.h which is a part of QuickTime header files. ( QuickTime.h )
If you use QTKit, it is imported like this from QTMovie.h

#import <Cocoa/Cocoa.h>
#if !__LP64__
	#import <QuickTime/QuickTime.h>
#endif

if you use QuickTime framework directly, it is imported by :

#if !__LP64__

#ifndef __MEDIAHANDLERS__
#include <QuickTime/MediaHandlers.h>
#endif

#ifndef __MOVIES__
#include <QuickTime/Movies.h>
#endif

If its following lines more, you can see that MediaHandler is not defined, if __LP64 is defined.

Conclusion is that you should compile your code in 32bit mode to manipulate media types like timecode. ( or virtually anything which is referenced using MediaHandler.

Correct String format for QTTimeFromString()

QTTimeFromString() doesn’t seem to work as it is explained.

If there is a “day” part in the string, it is not properly converted.
( The 2nd to the last example. )

The 2nd to the last example has an additional string at its front. That is why it couldn’t be converted properly.

The document should explain more about the string format.

QTTime testTime;

testTime = QTTimeFromString( @"00:00:03:16.00/2997" );
JALog(@"test time is set to : %@", QTStringFromTime(testTime) );

testTime = QTTimeFromString( @"00:03:00:16.00/2997" );
JALog(@"test time is set to : %@", QTStringFromTime(testTime) );

testTime = QTTimeFromString( @"00:00:03:16.0000/2997" );
JALog(@"test time is set to : %@", QTStringFromTime(testTime) );

testTime = QTTimeFromString( @"00:00:03:16.000000/2997" );
JALog(@"test time is set to : %@", QTStringFromTime(testTime) );

testTime = QTTimeFromString( @"0:00:00:03:16.000000/2997" );
JALog(@"test time is set to : %@ - Doesn't work because of the \"day\" part.", QTStringFromTime(testTime) );

testTime = QTTimeFromString( @"00:00:03:16/2997" );
JALog(@"test time is set to : %@ - Doesn't work because of the \"frame\" is in integer.", QTStringFromTime(testTime) );

Output is :

test time is set to : 0:00:03:16.00/2997
test time is set to : 0:03:00:16.00/2997
test time is set to : 0:00:03:16.00/2997
test time is set to : 0:00:03:16.00/2997
test time is set to : 0:00:00:03.00/2997 – Doesn’t work because of the “day” part.
test time is set to : 0:00:00:00.00/1 – Doesn’t work because of the “frame” is in integer.

It turned out that the document explain things wrongly.

Apple’s document states :

This function returns a QTTime structure whose time is set to the time expressed by the string; the string is assumed to be in the form “days:hours:minutes:seconds:frames/timescale”.

There is a problem in seconds:frames/timescale part.
It should be seconds.frames/timescale.

QTAudioFrequencyLevels and variable length array in a structure

QuickTime API내에서 사용되는 structure 중 AuidoFrequencyLevels라는 것이 있다. 이것은 다음과 같이 생겼다.

struct QTAudioFrequencyLevels {
  UInt32              numChannels;
  UInt32              numFrequencyBands;
                                              /* numChannels * numFrequencyBands entries, with the frequency bands for a single channel stored contiguously.*/
  Float32             level[1];
};

자, 여기서 제일 마지막 요소인 level을 보자. 크기가 1인 행렬로 되어 있다. (아… 행렬이란 말 참 오랜 만에 써본다.) 뭐 하느라고 이렇게 선언을 했을까? Apple의 Technical QA1459 : Easy Frequency Level audio Metering with MoviewAudio API를 보면 다음과 같이 쓰는 것을 볼 수가 있다.

QTAudioFrequencyLevels *freqResults = NULL;

...

// call this once per movie to establish metering
err = SetMovieAudioFrequencyMeteringNumBands(myMovie,
                                             kQTAudioMeter_StereoMix,
                                             &numberOfBandLevels);
if (err) goto bail;

freqResults = malloc(offsetof(QTAudioFrequencyLevels,
                              level[numberOfBandLevels * numberOfChannels]));
if (freqResults == NULL) {
    err = memFullErr;
    goto bail:
}

freqResults->numChannels = numberOfChannels;
freqResults->numFrequencyBands = numberOfBandLevels;

즉, dynamic length를 가지는 행렬로써 쓰고 있는 것이다.
음….
이거 말이지…
보통 이렇게 쓰지 않던가?

struct QTAudioFrequencyLevels {
  UInt32              numChannels;
  UInt32              numFrequencyBands;
  Float32             level[];

예전부터 이렇게 쓴 것으로 알고 있는데..
근데 GCC 문서를 보니, variable length를 지원하기 위해서 ISO C99에서는 바로 위의 예처럼 length자체가 없는 형식을 쓰는게 표준이고 ISO C90에서는 1이라고 길이를 명시해야 한단다.
근데 GCC에서는 자체 extension으로 0-length array를 지원한다고.
예전에 어디선가 인터뷰를 봤을때, 0-length array를 물어 봤었는데…
나원참 항상 standard 문서를 확인해보는 것도 아니고..
그리고 나는 가능하면 이런 extension은 쓰지 않는다. 왜냐하면 호환성에 문제가 생길 수있기 때문이다. 이를테면 예전에 삼성에 다닐때 ARM 프로세서를 사용하는 embedded system에서 프로그래밍을 했었는데, pSOSystem이 제공하는 컴파일러가 아주 오래된 사양을 지원하는 C/C++ 컴파일러였다. 물론 C++은 추천되는 대상이 아니었다. embedded system은 항상 C를 선호해왔으니까. 요새야 메모리 빵빵하니 C++을 적극 추천하지만… 근데 그때까지만해도 항상 새로운 표준을 열심히 공부하던 나로써는 당황스러웠다. PC에서 잘 되던 문법이 안되는 것이다. 회사에 제대로 된 pSOSystem 매뉴얼도 없고… 알고보니 오랜 표준만을 지원하고 있었던 것이다. 그 이후로는 가능하면 이곳 저곳에서 다 쓸 수있는 문법만을 쓴다. portability가 중요하기 때문에.

아무튼 Apple의 구현또한 옛날 컴파일러에서도 돌아가게 끔 되어 있는 것이다. 이런 사려깊은 것들 같으니라구.

%d bloggers like this: