1 | /* |
---|
2 | * media_messages.cpp |
---|
3 | * |
---|
4 | * Created on: Aug 18, 2009 |
---|
5 | * Author: nenko |
---|
6 | */ |
---|
7 | |
---|
8 | #include "media_decoder.h" |
---|
9 | |
---|
10 | MediaBridge BRIDGE; |
---|
11 | Decoder DECODER; |
---|
12 | |
---|
13 | static int sophie_media_open(URLContext *h, const char *filename, int flags); |
---|
14 | static int sophie_media_read(URLContext *h, unsigned char *buf, int size); |
---|
15 | static int sophie_media_write(URLContext *h, unsigned char *buf, int size); |
---|
16 | static int64_t sophie_media_seek(URLContext *h, int64_t pos, int whence); |
---|
17 | static int sophie_media_close(URLContext *h); |
---|
18 | |
---|
19 | // smp = SophieMediaProtocol is misleding |
---|
20 | // (SMP - Simple Management Protocol, Smart Messaging Protocol) |
---|
21 | // changing to sophie |
---|
22 | URLProtocol SOPHIE_PROTOCOL = { "sophie", sophie_media_open, sophie_media_read, sophie_media_write, sophie_media_seek, sophie_media_close, }; |
---|
23 | |
---|
24 | struct Sophie2MediaContext { |
---|
25 | int pos; |
---|
26 | }; |
---|
27 | |
---|
28 | //Sophie2 Media Protocol |
---|
29 | static int sophie_media_open(URLContext *h, const char *filename, int flags) { |
---|
30 | Sophie2MediaContext *s = (Sophie2MediaContext*) av_malloc(sizeof(Sophie2MediaContext)); |
---|
31 | s->pos = 0; |
---|
32 | // if (!s) { |
---|
33 | // return AVERROR(ENOMEM); |
---|
34 | // } |
---|
35 | h->priv_data = s; |
---|
36 | |
---|
37 | return 0; |
---|
38 | } |
---|
39 | |
---|
40 | static int sophie_media_read(URLContext *h, unsigned char *buf, int size) { |
---|
41 | Sophie2MediaContext *s = (Sophie2MediaContext *) h->priv_data; |
---|
42 | |
---|
43 | int fileSize = DECODER.fileSize; |
---|
44 | |
---|
45 | if (s->pos + size > fileSize) { |
---|
46 | size = fileSize - s->pos; |
---|
47 | } |
---|
48 | Response res = MediaResponse::createRequestBytes(s->pos, size); |
---|
49 | BRIDGE.sendResponse(res); |
---|
50 | Command *cmd = BRIDGE.readCommand(); |
---|
51 | if (cmd->getId() == STOP_COMMAND_ID) { |
---|
52 | BRIDGE.sendResponse(BRIDGE.doStop()); |
---|
53 | exit(0); |
---|
54 | } |
---|
55 | assert(cmd->getId() == SEND_BYTES_COMMAND); |
---|
56 | SendBytesCommand *bytesCmd = (SendBytesCommand *) cmd; |
---|
57 | assert(s->pos == bytesCmd->filePos); |
---|
58 | assert(size == (int)bytesCmd->fileData.size()); |
---|
59 | int len = min(int(bytesCmd->fileData.size()), size); |
---|
60 | |
---|
61 | memcpy(buf, (char *) &bytesCmd->fileData[0], len); |
---|
62 | |
---|
63 | s->pos += len; |
---|
64 | |
---|
65 | delete bytesCmd; |
---|
66 | |
---|
67 | return len; |
---|
68 | } |
---|
69 | |
---|
70 | static int sophie_media_write(URLContext *h, unsigned char *buf, int size) { |
---|
71 | //No writting... for now |
---|
72 | return -1; |
---|
73 | } |
---|
74 | |
---|
75 | static int64_t sophie_media_seek(URLContext *h, int64_t pos, int whence) { |
---|
76 | Sophie2MediaContext *s = (Sophie2MediaContext *) h->priv_data; |
---|
77 | |
---|
78 | switch(whence) { |
---|
79 | case SEEK_SET: |
---|
80 | s->pos = pos; |
---|
81 | break; |
---|
82 | case SEEK_CUR: |
---|
83 | s->pos += pos; |
---|
84 | break; |
---|
85 | case SEEK_END: |
---|
86 | s->pos = DECODER.fileSize + pos; |
---|
87 | break; |
---|
88 | case AVSEEK_SIZE: |
---|
89 | return DECODER.fileSize; |
---|
90 | default: |
---|
91 | assert(false); |
---|
92 | } |
---|
93 | |
---|
94 | return s->pos; |
---|
95 | } |
---|
96 | |
---|
97 | static int sophie_media_close(URLContext *h) { |
---|
98 | Sophie2MediaContext *s = (Sophie2MediaContext*) h->priv_data; |
---|
99 | av_free(s); |
---|
100 | |
---|
101 | return 0; |
---|
102 | |
---|
103 | } |
---|
104 | |
---|
105 | Response OpenCommand::execute() { |
---|
106 | fprintf(stderr, "executing open command (used to be-media_decoder.open())...\n"); |
---|
107 | assert(!DECODER.isOpen); |
---|
108 | |
---|
109 | DECODER.fileSize = this->fileSize; |
---|
110 | DECODER.isOpen = false; |
---|
111 | |
---|
112 | //const char * filename = "/home/stefan/media_redesign_workspace/june_chorus.wav";//"smp:///a"; |
---|
113 | string filename = "sophie:///a"; |
---|
114 | |
---|
115 | av_register_all(); |
---|
116 | av_register_protocol(&SOPHIE_PROTOCOL); |
---|
117 | |
---|
118 | fprintf(stderr, "opening input file...\n"); |
---|
119 | if (av_open_input_file(&DECODER.pFormatContext, filename.c_str(), NULL, 0, NULL) != 0) { |
---|
120 | fprintf(stderr, "ERROR opening input file...\n"); |
---|
121 | throw runtime_error("Decoder::open - Cannot open input file!"); |
---|
122 | } |
---|
123 | |
---|
124 | fprintf(stderr, "finding Streams of input file...\n"); |
---|
125 | if (av_find_stream_info(DECODER.pFormatContext) < 0) { |
---|
126 | throw runtime_error("Decoder::open - Cannot find stream info!"); |
---|
127 | } |
---|
128 | |
---|
129 | DECODER.videoStream = -1; |
---|
130 | DECODER.audioStream = -1; |
---|
131 | for (int i = 0; i < int(DECODER.pFormatContext->nb_streams); i++) { |
---|
132 | if (DECODER.pFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) { |
---|
133 | DECODER.videoStream = i; |
---|
134 | } |
---|
135 | if (DECODER.pFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO && DECODER.audioStream < 0) { |
---|
136 | DECODER.audioStream = i; |
---|
137 | } |
---|
138 | if (DECODER.videoStream != -1 && DECODER.audioStream != -1) { |
---|
139 | break; |
---|
140 | } |
---|
141 | } |
---|
142 | |
---|
143 | if (DECODER.videoStream != -1) { |
---|
144 | fprintf(stderr, "Video stream found!\n"); |
---|
145 | DECODER.initVideo(); |
---|
146 | } |
---|
147 | |
---|
148 | if (DECODER.audioStream != -1) { |
---|
149 | fprintf(stderr, "Audio stream found!\n"); |
---|
150 | DECODER.initAudio(); |
---|
151 | } |
---|
152 | DECODER.isOpen = true; |
---|
153 | DECODER.shifted = true; |
---|
154 | DECODER.lastVideoMillis = -1; |
---|
155 | DECODER.lastVideoDur = -1; |
---|
156 | |
---|
157 | //insufficient info |
---|
158 | fprintf(stderr, "\n"); |
---|
159 | dump_format(DECODER.pFormatContext, 0, filename.c_str(), 0); |
---|
160 | return Response::createOk(); |
---|
161 | } |
---|
162 | |
---|
163 | Response GetFrameCommand::execute() { |
---|
164 | vector<byte> data; |
---|
165 | int width = DECODER.pVideoCodecCtx->width; |
---|
166 | int height = DECODER.pVideoCodecCtx->height; |
---|
167 | DECODER.getFrame(data, timeMillis); |
---|
168 | return MediaResponse::createFrame(data, width, height); |
---|
169 | } |
---|
170 | |
---|
171 | Response GetAudioCommand::execute() { |
---|
172 | vector<byte> chunk = DECODER.getAudio(timeMillis); |
---|
173 | return MediaResponse::createAudio(chunk, timeMillis); |
---|
174 | } |
---|
175 | |
---|
176 | Response GetInfoCommand::execute() { |
---|
177 | int width = 0; |
---|
178 | int height = 0; |
---|
179 | AVRational frameRate; |
---|
180 | bool hasAudio = false; |
---|
181 | if(DECODER.videoStream >= 0) { |
---|
182 | width = DECODER.pVideoCodecCtx->width; |
---|
183 | height = DECODER.pVideoCodecCtx->height; |
---|
184 | frameRate = DECODER.pFormatContext->streams[DECODER.videoStream]->r_frame_rate; |
---|
185 | } |
---|
186 | if(DECODER.audioStream >= 0) { |
---|
187 | hasAudio = true; |
---|
188 | } |
---|
189 | int duration = DECODER.pFormatContext->duration * 1000 / AV_TIME_BASE; |
---|
190 | |
---|
191 | return MediaResponse::createVideoInfo(width, height, duration, frameRate, hasAudio); |
---|
192 | |
---|
193 | } |
---|
194 | |
---|
195 | int main() { |
---|
196 | cerr << "Starting media_decoder" << endl; |
---|
197 | BRIDGE.mainLoop(); |
---|
198 | return 0; |
---|
199 | } |
---|