336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

    여기서는 디지털 방송 방식중 위성방송 관점에서 설명을 하도록 하겠다. 위성방송을 수신하기 위해서는 서비스(=채널)을 검색하는 단계와 검색된 서비스에서
원하는 데이터(프로그램)를 필터링하여 수신하는 단계가 필요하다. 첫번째 단계는 위성에서 송신하고 있는 서비스가 어떤 것들이 있으면 어떤 주파수로 송신되고 
있는지에 대한 정보를 확인, 저장하는 단계로 일반적으로 수신기에서는 이 과정을 최초 한번만 수행하면 그 이후부터는 두번째 단계만을 수행하여 방송을 수신할
수 있다. 물론 방송국이나 위성에서의 변경사항이 있으면 그 정보를 새로 수신하여 반영하여야 한다.

그림 1은 하나의 위성에서 송신하고 있는 정보들의 구조를 보여주고 있다. 여기서는 3개의 transponder (TP)가 존재하고 있다. TP는 쉽게 생각하면 KBS, MBC,
SBS와 같은 방송국 단위라고 생각할 수 있다. 우리나라 지상파 방송국의 경우 각 방송국마다 한 개의 서비스만을 제공하고 있지만 그림 1의 TP2에서는 세 개의 
서비스를 제공하고 있는 것을 알 수 있다. 수신기에서는 위성이 송신하고 있는 정보의 구조를 파악하기 위해 채널 검색을 수행하는 것이다.



그림 1. 위성 데이터의 구조

    
    서비스 정보를 확인하기 위해서는 위성에서 데이터를 송신할 때 사용하는 주파수 정보를 알고 있어야 한다. 좀 더 구체적으로는 frequency, symbol rate, 
polarisation (horizontal, vertical) 등의 정보가 있어야 데이터를 수신할 수 있다. 수신기에서는 기본적으로 이런 값들을 저장하고 있지만 없는 경우에는 원하는 
방송을 송신하는 위성의 정보를 인터넷 (www.lyngset.com)을 통해 확인한 후 manual로 설정하면 데이터 수신이 가능하다.

    서비스 정보를 수신하기 위해서는 우선 원하는 주파수로 튜너를 락킹해야 한다. 락킹 과정에서 frequency, symbol rate, polarisation 등의 정보가 사용된다.
서비스가 락킹되면 데이터가 수신기로 들어오기 시작한다. 수신기에서는 맨 처음 PID=0x0000인 PAT를 찾게 된다. PAT를 parsing하여야 실제 서비스 정보를
가지고 있는 PMT의 PID를 얻을 수 있기 때문이다. 이 과정에서 서비스 번호가 0인 PID를 확인하여 NIT의 PID도 확인이 가능하다. NIT에는 또 다른 network
정보들이 포함되어 있기 때문에 서비스 검색시에 parsing되어야 한다. PMT에는 각 서비스에 필요한 비디오, 오디오, 그리고 데이터 정보들이 어떤 PID를 통해
전달되는지 알 수 있는 정보가 들어있다.

간단하게 정리해보면 우선 서비스 검색을 위해서는 다음과 같은 pseudo code가 수행 될 것이다.

FOR counter = 0 to Num_of_TP
      FOR counter = 0 to Num_of_SERVICE
            FOR counter = 0 to Num_of_ELEMENT
  
                  Construct_Service_DB()
 
            ENDFOR
      ENDFOR
ENDFOR

where Num_of_TP is sum of NIT pasing & 수신기에 저장된 TP list,
          Num_of_SERVICE is number of PMT,
          Num_of_ELEMENT is number of elements like audio, video, data.


이렇게 채널 검색 과정이 끝나고 실제 특정 서비스 (=채널)의 이벤트 (=프로그램) 데이터를 수신하기 위해서는 다음과 같은 파싱 순서가 진행되어진다.

    PAT로부터 각 서비스 PMT의 PID 확인
       => 각 서비스의 PMT로부터 video, audio, data packet의 PID 확인
             => Video, Audio, Data PID를 수신하여 decoder로 전송


블로그 이미지

뚱땡이 우주인

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

디지털 방송이 만들어지는 과정 
디지털 방송의 실제 데이터인 TS가 만들어지는 과정에 대해 알아보면...
영상 데이터가 디지털 방송의 실제 데이터인 TS로 변화하기 위해 거치는 인코더와 생성(generator), 그리고 MUX에 대해 알아볼 것이다. 이 때 데이터가 어떤 식으로 변형되는지 변화 과정 또한 알아볼 것이고, 마지막으로 각각의 인코더와 MUX를 거치기 전과 거친 후의 변화되는 모양새를 살펴보는 시간을

디지털 방송 TS의 생성 원리 
우선 PES(Packetized Elementary Stream) 패킷이 무엇이고, TS가 무엇인가에 대해 알아보자. TS는 ‘Transport Stream’의 약자이다. 즉, 디지털 방송을 전송하는 실제 데이터들의 연속적인 모임을 말하는 것이다. 방송사에서는 TS를 전송하고, 수신측(DTV, 셋톱박스)에서는 이 TS를 받아서 디코딩해 화면에 영상을 표시하고, 음성을 들려주고, 여러가지 부가 서비스를 위한 정보를 골라내 사용한다. 이때 사용되는 영상은 MPEG-2(ISO/IEC 13818-1)이고, 음성은 AC3(돌비 디지털 사운드)를 사용한다. 

이 TS는 몇 가지 특징이 가지고 있다. 첫 번째가 TS는 일련의 TS 패킷이란 것으로 구성되는데, TS 패킷들은 각각의 길이가 188바이트로 일정하다는 것이고, 두 번째가 TS의 데이터 구조는 복수 프로그램을 운반하기 위한 목적으로 ITU-T(구 CITT)에 의한 표준인 ATM 방식과 유사하다는 것이다. 

이러한 TS가 생성되는 과정을 간략하게 알아보도록 하자. <그림 1>은 실제 영상과 음성이 방송파(TS)로 변하는 과정을 나타낸다. 실제 영상을 받아서 MPEG-2로 변환(ENCODING)하고, 음성은 AC3로 변환한다. 이것을 각각의 비디오 ES, 오디오 ES라고 한다. 

그림1 | TS 생성과정 (Sarnoff 인용)


이 ES를 가변적 크기로 잘라낸 후 헤더를 붙여 PES 패킷으로 변환한다. 이 PES 패킷의 크기는 고정되지 않고 가변적이다. 이 PES 패킷을 고정된 크기 188바이트로 잘라내고 헤더를 붙여(헤더 포함 188바이트) TS 패킷으로 변환한다. 만들어진 TS를 주파수에 실어 전송한다고 간단하면서도 어렵게 설명할 수 있다. 그럼 좀더 세부적으로 살펴보도록 하자. 

싱글-프로그램 인코더가 PES 패킷이 생성되는 부분 
디지털 방송은 MPEG-2를 사용한다. MPEG-2는 비디오와 오디오가 따로 구성된다. 그렇기 때문에 <그림 1>의 싱글 프로그램 인코더(single-program encoder) 부분을 보면 비디오와 오디오가 각각 인코딩된다. 그럼 우선 비디오 하나만 가지고 살펴보도록 하자. 

<그림 1>을 보면 ‘Video → [MPEG-2 Encoder] → MPEG-2 Bitstream → [Transport Mux] → SP transport Stream’으로 표현된다. 여기서 비디오 데이터가 MPEG-2 인코더를 거쳐서 생성되는 MPEG-2 비트스트림이 ES를 의미하고, 이 ES가 Transport Mux를 거쳐서 생성되는 것이 PES 패킷을 의미한다. 

SP(Single Program) 트랜스포트 스트림과 MP(Multi Program) 트랜스포트 스트림으로 나눠지는 이유는 디지털 방송이 멀티채널의 구현이 가능하기 때문이다. 멀티채널이란 하나의 방송 프로그램 영역에 여러 개의 프로그램을 같이 포함시켜 서로 다른 프로그램을 송출하는 것을 의미한다. 간단한 예를 들자면 8번 채널에서 8-1, 8-2, 8-3, 8-4와 같이 8번 채널이 4개로 분할되어 4개의 서로 다른 프로그램의 방영이 가능한 것을 말한다. 우리나라에서의 디지털 지상파 방송 규격은 HD(고화질 디지털 방송)이기 때문에 다채널이 제공되지 않는다. 다채널을 사용하기 위해서는 SD(일반화질 디지털 방송)급의 방송을 사용한다. 외국이나 위성 방송에서는 SD를 사용한다.

 


[ TS와 PS ] 
MPEG-2를 이용해 TS와 PS를 생성할 수 있다. TS는 잡음이 많은 환경에 사용되고, PS(Program Stream)는 잡음이 거의 없을 거라 예상되는 환경에 사용된다. 즉, TS는 데이터 손실이 예상되는 방송용 데이터로, PS는 데이터 손실이 거의 없을 거라 예상되는 DVD 같은 저장 매체에 주로 사용된다. PS는 MPEG-1과 같이 하나의 프로그램 구성이 가능하고, TS는 복수의 프로그램 구성(다채널)이 가능하다. TS는 복수의 프로그램을 하나의 비트 열로 구성할 수 있기 때문에 TV 방송 등에 대응할 수 있고 자유도가 많은 편성이나 스크램블 기능 등에도 대비할 수 있다.


싱글-프로그램 인코더 부분을 좀더 상세하게 표현한 <그림 2>를 살펴보자. Video Data가 Video Encoder를 거쳐서 Video ES가 만들어지고, 생성된 Video ES가 Packetizer를 거쳐서 Video PES 패킷으로 변환된다. 그럼 PES 패킷이란 무엇인가? 그것은 ‘The data structure used to carry elementary stream data. It consists of a PES packet header followed by PES packet payload and is described’라고 13818-1에 표현되어 있다. 정확한 이해를 위해 원문을 적었다.

 

정리하자면 비디오 인코더를 이용해 ES가 생성된다. 이 ES는 비디오의 처음부터 끝까지의 일련의 데이터이다. 이것을 그대로 전송할 경우, 잡음에 의한 데이터 손실이 있을 수 있고, 혹은 데이터의 분실이 생길 수도 있다. 그렇기 때문에 원활한 전송을 위해 ES를 나누고, 나눈 각각에 헤더를 포함시켜서 연결 정보 및 데이터의 손상 여부에 대한 정보 등을 추가시켜 수신측에서 데이터를 원활히 수신하도록 만드는 것이다. 이것이 바로 PES 패킷인 것이다. 만약에 중간에 PES 패킷 한 개를 유실했더라도 유실된 정보를 알 수 있기에 디코딩에 실패하지 않고 복구할 수 있다. 


그림2 | PES 패킷 1 (13818-1 인용)

 


그림3 | PES 패킷 2


그래서 패킷타이저(packetizer)를 거침으로써 ES에 헤더가 포함되고 일정하지 않은 크기로 잘라낸 패킷을 만드는 것이다. PES 패킷의 헤더에는 이것들의 순서의 정보도 가지고 있고, 다른 정보들이 왔을 때 무시하는 아이덴티파이어(identifier) 정보도 포함하는 것이다. 변화의 과정이 <그림 3>처럼 표현되는 것이다. 

◆ <그림 1>의 PSI과 PSIP 제너레이터 부분이 PSI, PSIP가 생성되는 부분이다 
싱글-프로그램 인코더 부분은 MPEG-2를 위한 부분이고, PSI와 PSIP 제너레이터 부분은 MPEG-2의 디코딩 정보와 부가 정보가 만들어지는 부분이다. PSIP에 관한 세부 내용은 다음 호에서 설명하도록 한다. 
◆ <그림 1>의 트랜스포트 MUX 부분이 TS가 생성되는 부분이다

    싱글-프로그램 인코더 부분의 수행으로 우리는 PES 스트림(PES 패킷들의 연속된 모임을 PES 스트림이라고 한다)을 얻었다. 이 PES 스트림을 이용해 TS 혹은 PS가 생성된다. PES 스트림이 TS Mux를 거치면 TS가 생성되고, PS Mux를 거치면 PS가 생성되게 되는 것이다.

그림4 | TS 생성


PES 패킷의 TS 생성 과정을 살펴보면 PES 패킷만을 이용해 TS를 생성하는 것이 아니라, PSI와 PSIP 제너레이터를 이용해 생성된 PSI, PSIP 섹션도 함께 TS Mux에 삽입해야 한다. 그러면 완전한 TS가 생성되는 것이다. 싱글-프로그램 인코더에서 생성된 PES 스트림과 PSI와 PSIP 제너레이터에서 생성된 PSIP, PSI 섹션을 가지고 TS Mux(MP Transport Mux)가 TS(188바이트)를 만드는 것이다. 이것이 주파수를 타고 날아오는 실제 데이터이고, 실제 수신측은 이것을 받아 디코딩해 화면과 영상을 보여주는 것이다. 

여기까지 실제 비디오 데이터가 TS로 변화되는 과정에 대한 원리를 살펴보았다. 다음으로 데이터 구조에 대해 살펴보도록 하자.

 

단위 모양새가 궁금하다 
ES가 TS로 변하는 과정에서의 데이터 구조의 변화에 대해 자세히 살펴보도록 하자. <그림 5>를 참조한다. 

 

그림5 | ES -> PES -> TS


<그림 5>의 ①번은 ES를 나타낸다. 이것이 오디오인지 비디오인지는 중요하지 않다. 그 이유는 같은 방식이기 때문이다. 우선 ES(오디오 또는 비디오)가 있다고 가정한다. ②번이 패키타이저를 통해 ES를 일정하지 않은 크기(일정한 형식에 맞추어)로 잘라낸 후 헤더를 추가해 PES 패킷이 생성된 모습을 표현한 것이다. PES 패킷 옆에 있는 것이 PSIP 제너레이터로 생성된 PSIP 섹션이다. 

③번이 TS Mux를 통해 PES 스트림과 PSIP 섹션을 TS로 변환한 모습을 표현한 것이다. 이것 역시 헤더가 추가되며, PES 스트림을 이용해 TS를 만드는 사이사이에 PSIP, PSI 섹션도 같이 추가되어 하나의 TS가 완성되는 것이다. 실제 TS가 만들어지기 위해서는 한 개의 원본에(ES) 두 개의 헤더가 각기 추가됨을 알 수 있다. 그렇기 때문에 역으로 TS에서 원본을 추출하기 위해서는 두 개의 껍데기를 벗겨내야 하는 것이다. 

TS를 자세히 살펴보니 데이터 영역에 스터핑(stuffing)이란 것이 새롭게 추가된 것을 알 수 있다. <그림 5>와 <그림 6>에 포함된 스터핑이란 것은 무엇인가? 실제적인 데이터 크기를 고려해 스터핑이 무엇이고, 왜 생겼는지에 대해 알아보자. 


그림6 | 스터핑 샘플


스터핑이란 TS가 188바이트라는 고정된 크기를 갖는 특성 때문에 생긴 것으로 빈 공간에 채워지는 의미 없는 데이터를 의미한다. 예를 들면 PES 패킷의 크기가 300바이트라고 가정하자. 이것을 TS로 변환하려면 최소 2개의 TS를 사용해야 한다. 참고로 TS 헤더의 크기는 4바이트이다. 즉 데이터로 사용할 수 있는 크기는 ‘188 - 4 = 184바이트’이다(어댑션_필드(adaptation_field)가 아닌 데이터_바이트(data_byte)가 올 때만 적용된다). 

그렇기 때문에 ‘300/184 = 1과 116’의 나머지의 값이 2개의 TS에 나누어 저장되고 ‘184 - 116 = 68바이트’ 값을 스터핑이라 하는 것이다. 이 스터핑의 값은 모든 비트는 아무런 의미 없는 ‘1’로 채워지게 된다. 그렇기 때문에 수신측에서 디코딩할 때에 이 값은 모두 버리게 되는 것이다. <그림 6>을 참고하도록 한다.


출처 : http://blog.naver.com/PostView.nhn?blogId=parks888&logNo=130036940362&redirect=Dlog&widgetTypeCall=true


'ⓘⓣ > DTV' 카테고리의 다른 글

HTTP Live Streaming  (0) 2012.04.16
디지털 방송 - PES / Section에 대해  (0) 2012.04.16
디지털 방송이 보여지기까지의 과정  (0) 2012.04.16
블로그 이미지

뚱땡이 우주인

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
각주1



간단한 임베디드 리눅스 드라이버 만들기

 

q 정의

¦ 장치 파일

       장치를 접근할  있게 하는 파일

       장치에 입출력 하는 것은 장치에 read/write하는것과 동일

¦ 장치번호

       주번호(major number) 부번호(minor number)

       /proc/devices 사용중인 장치번호가 있음

       test 용으로 사용할  있는 major number

      60~63, 120~127, 240~254

¦ 장치 유형(device type)

       문자(character device)

       블록(block device)

       네트워크(network device)

 

q 디바이스 드라이버 읽기 쓰기 구조

q 디바이스 내부 구조

¦ 구성요소

       Initialization/termination interface

      init(), init_module(), exit_module()

       File system interface

      Well-defined interface : file_operations

      Character device : open, release, read, write, ioctl

      Block device : open, release, request, ioctl

      Network device : open, close, transmit, receive, ioctl

       Hardware interface

      inb(), inw(), inl(), insb(), insw(), insl()

      outb(), outw(), outl(), outsb(), outsw(), outsl()

      readb(), readw(), readl()

      writeb(), writew(), writel()

 

q 디바이스 만들기

¦ 순서

        장치를 위한  번호를 할당( 번호를 정하자)

       디바이스 드라이버를 만들기

       Application 프로그램 만들기

       Make 파일 만들기

       장치 파일을 생성함

      mknod /dev/mydrv [b|c] major_number minor_number

       디바이스 드라이버를 컴파일(2가지 방법)

      커널에 직접 포함하여 컴파일

      모듈로서 컴파일하고나중에 모듈 형태로 삽입함

¦  장치를 위한  번호 할당

        예제에서는  번호를 240,  번호를  0으로 정함

¦ 디바이스 드라이버 만들기

       Source code

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <asm/uaccess.h>

#include <asm/io.h>

 

#define DEVICE_NAME "mydrv" //       device name

#define MYDRV_MAJOR 240              //           major number

volatile unsigned int *R_piol;

 

int mydrv_open(struct inode *inode, struct file *flip)

{

             int num = MINOR(inode->i_rdev);

             printk("my drv open : minor number is %d\n",num);

             return 0;

}

ssize_t mydrv_read(struct file *flip, char *buf,size_t count, loff_t *_pos)

{

             unsigned char status;

             printk("my_drvread: buf is %d, countis %d \n",*buf,count);

             return count;

}

 

ssize_t mydrv_write(struct file *flip, char *buf,size_t count, loff_t *_pos)

{

             printk("my_drv_write: buf is %d, countis %d \n",*buf,count);

             *buf=1;

 

             return count;

}

int mydrv_release(struct file *flip, char *buf,size_t count, loff_t *_pos)

{

             printk("my_drv_release: bufis %08X, countis %08X \n",buf,count);

             return count;

}

int mydrv_ioctl(struct inode *inode, struct file *flip, int ioctl_param)

{

             printk("mydrv_ioctl(): ioctl_param %d \n",ioctl_param);

             return 0;

}

 

struct file_operations mydrv_fops ={

             //llseek    :mydrv_llseek,

             read        :mydrv_read,

             write       :mydrv_write,

             ioctl        :mydrv_ioctl,

             open       :mydrv_open,

             release    :mydrv_release

};

 

static int hello_init(void)

{

             int result;

 

             printk("init moudle \n");

 

             result = register_chrdev(MYDRV_MAJOR,DEVICE_NAME,&mydrv_fops);

             if(result<0){

                           printk("mydrv: device driver can't be registered\n");

                           return result;

             }

             return 0;

}

 

static void hello_exit(void)

{

             printk("exit module\n");

}

void hello_cleanup(void)

{

             printk("cleanup module \n");

             unregister_chrdev(MYDRV_MAJOR,DEVICE_NAME);

}

 

module_init(hello_init); //커널을모듈에적재할때호출도리함수지정

module_exit(hello_exit); //커널을모듈에서제거할때호출될함수지정

MODULE_LICENSE("Dual BSD/GPL"); // 커널2.6의라이센스등록

 

¦ Application program 만들기

       Source code

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <stdio.h>

#include <math.h>

 

int main(void)

{

             int fd,ret,select=1;

             int count,temp=0,DIP[8]={0};

             unsigned char buf=0;

             unsigned long flag = 0x01;

             fd = open("/dev/mydrv",O_RDWR);

             if(fd < 0)

             {

                           printf("fd file open fail\n");

                           return -1;

             }

             write(fd,&buf,1);

             read(fd,&buf,1);

             ioctl(fd,1,2);

             close(fd);

}

¦ Makefile 만들기

       Source

obj-m     :=mydrv.o

 

KDIR       :=/home/a/slc100/test_kernel/sl2c100_kernel_2.6.29_20100622

PWD       :=$(shell pwd)

 

default:

             $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

             cp mydrv.ko /nfsroot/RootFS-S5PC100/mydrv.ko

             arm-s3c6410-linux-gnueabi-gcc -o test_app test_app.c

             cp test_app /nfsroot/RootFS-S5PC100/test_app

clean:

             rm -rf *.ko

             rm -rf *.mod.*

             rm -rf *.cmd

             rm -rf *.o

             rm -rf /nfsroot/RootFS-S5PC100/mydrv.ko

rm -rf /nfsroot/RootFS-S5PC100/test_app

 

¦ 장치파일 생성(타켓 보드에서  )

       Mknod /dev/mydrv c 240 0( /dev폴더에 ( 240/ 0 )번호 mydrv 라는 장치파일을 생성)

¦ 모듈 적재

       lnsmod mydrv.ko

       lsmod : 적재된 모듈 출력 / rmmod : 정재된 모듈 삭제

¦ 어플리케션 실행

       ./test_app

¦ 실행화면



Open ->write(buf 0 1 write)->read(buf  1 확인)->ioctl(호출만하였음)->release




블로그 이미지

뚱땡이 우주인

,