Revision 1e8dedd8

View differences:

include/chunkiser.h
1
/** @file chunkiser.h
2
 *
3
 * @brief Split an audio/video stream in chunks.
4
 *
5
 * The chunkisation functions (chunkiser) allow to split an A/V stream in
6
 * chunks, and to output the chunks payload...
7
 *
8
 */
9
 
10
#ifndef CHUNKISER_H
11
#define CHUNKISER_H
12

  
13
/**
14
 * Opaque data type representing the context for a chunkiser
15
 */
16
struct input_stream;
17

  
18
/**
19
 * Opaque data type representing the context for a de-chunkiser
20
 */
21
struct output_stream;
22

  
23
/**
24
 * @brief Initialise a chunkiser.
25
 * 
26
 * Open an A/V stream, and prepare it for reading chunks, returning the
27
 * chunkiser's context.
28
 * 
29
 * @param fname name of the file containing the A/V stream.
30
 * @param period desired input cycle size.
31
 * @param config configuration string.
32
 * @return the pointer to the chunkiser context on success, NULL on error
33
 */
34
struct input_stream *input_stream_open(const char *fname, int *period, const char *config);
35

  
36
/**
37
 * @brief Cleanup a chunkiser.
38
 * 
39
 * Close an A/V stream, and cleanup all the data structures related to the
40
 * chunkiser.
41
 * 
42
 * @param c chunkiser's context.
43
 */
44
void input_stream_close(struct input_stream *c);
45

  
46
/**
47
 * @brief Read a chunk.
48
 * 
49
 * Read some data from the A/V stream, and generate a new chunk
50
 * 
51
 * @param c chunkiser's context.
52
 * @param id the stream id.
53
 * @param size pointer to an integer where the chunk size is returned.
54
 * @param ts pointer to a long long integer where the chunk release time
55
 *        is returned.
56
 * @return the chunk payload on success, NULL on error
57
 */
58
uint8_t *chunkise(struct input_stream *c, int id, int *size, uint64_t *ts);
59

  
60
/**
61
 * @brief Initialise a dechunkiser.
62
 * 
63
 * Open an A/V stream for output , and prepare it for writing chunks,
64
 * returning the dechunkiser's context.
65
 * 
66
 * @param config configuration string.
67
 * @return the pointer to the dechunkiser context on success, NULL on error
68
 */
69
struct output_stream *out_stream_init(const char *config);
70

  
71
/**
72
 * @brief Write a chunk.
73
 * 
74
 * Write some data (from a chunk's payload) to the A/V stream.
75
 * 
76
 * @param out dechunkiser's context.
77
 * @param id the chunk id.
78
 * @param data pointer to the chunk's payload.
79
 * @param size chunk size.
80
 */
81
void chunk_write(struct output_stream *out, int id, const uint8_t *data, int size);
82
#endif	/* CHUNKISER_H */
src/Chunkiser/Makefile
1
ifndef BASE
2
BASE = ../..
3
else
4
vpath %.c $(BASE)/src/$(notdir $(CURDIR))
5
endif
6
CFGDIR ?= ..
7

  
8
ifdef FFDIR
9
OBJS += input-stream-avf.o output-stream-avf.o
10
endif
11

  
12
all: libchunkiser.a
13

  
14
include $(BASE)/src/utils.mak
15
CPPFLAGS += -I$(FFDIR)
src/Chunkiser/input-stream-avf.c
1
/*
2
 *  Copyright (c) 2009 Luca Abeni
3
 *
4
 *  This is free software; see gpl-3.0.txt
5
 */
6

  
7
#include <libavformat/avformat.h>
8
#include <stdbool.h>
9

  
10
#include "chunkiser.h"
11
//#include "dbg.h"
12
#include "payload.h"
13
#include "config.h"
14

  
15
#define STATIC_BUFF_SIZE 1000 * 1024
16
static int header_refresh_period;
17

  
18
struct input_stream {
19
  AVFormatContext *s;
20
  bool loop;	//loop on input file infinitely
21
  int audio_stream;
22
  int video_stream;
23
  int64_t last_ts;
24
  int64_t base_ts;
25
  int frames_since_global_headers;
26
};
27

  
28
static uint8_t codec_type(enum CodecID cid)
29
{
30
  switch (cid) {
31
    case CODEC_ID_MPEG1VIDEO:
32
    case CODEC_ID_MPEG2VIDEO:
33
      return 1;
34
    case CODEC_ID_H261:
35
      return 2;
36
    case CODEC_ID_H263P:
37
    case CODEC_ID_H263:
38
      return 3;
39
    case CODEC_ID_MJPEG:
40
      return 4;
41
    case CODEC_ID_MPEG4:
42
      header_refresh_period = 50;
43
      return 5;
44
    case CODEC_ID_FLV1:
45
      return 6;
46
    case CODEC_ID_SVQ3:
47
      return 7;
48
    case CODEC_ID_DVVIDEO:
49
      return 8;
50
    case CODEC_ID_H264:
51
      header_refresh_period = 50;
52
      return 9;
53
    case CODEC_ID_THEORA:
54
    case CODEC_ID_VP3:
55
      return 10;
56
    case CODEC_ID_SNOW:
57
      return 11;
58
    case CODEC_ID_VP6:
59
      return 12;
60
    case CODEC_ID_DIRAC:
61
      return 13;
62
    default:
63
      fprintf(stderr, "Unknown codec ID %d\n", cid);
64
      return 0;
65
  }
66
}
67

  
68
static void video_header_fill(uint8_t *data, AVStream *st)
69
{
70
  int num, den;
71

  
72
  num = st->avg_frame_rate.num;
73
  den = st->avg_frame_rate.den;
74
//fprintf(stderr, "Rate: %d/%d\n", num, den);
75
  if (num == 0) {
76
    num = st->r_frame_rate.num;
77
    den = st->r_frame_rate.den;
78
  }
79
  if (num > (1 << 16)) {
80
    num /= 1000;
81
    den /= 1000;
82
  }
83
  payload_header_write(data, codec_type(st->codec->codec_id), st->codec->width, st->codec->height, num, den);
84
}
85

  
86
static void frame_header_fill(uint8_t *data, int size, AVPacket *pkt, AVStream *st, int64_t base_ts)
87
{
88
  AVRational fps;
89
  int32_t pts, dts;
90

  
91
  fps = st->avg_frame_rate;
92
  if (fps.num == 0) {
93
    fps = st->r_frame_rate;
94
  }
95
  if (pkt->pts != AV_NOPTS_VALUE) {
96
    pts = av_rescale_q(pkt->pts, st->time_base, (AVRational){fps.den, fps.num}),
97
    pts += av_rescale_q(base_ts, AV_TIME_BASE_Q, (AVRational){fps.den, fps.num});
98
  } else {
99
    pts = -1;
100
  }
101
  //dprintf("pkt->pts=%ld PTS=%d",pkt->pts, pts);
102
  if (pkt->dts != AV_NOPTS_VALUE) {
103
    dts = av_rescale_q(pkt->dts, st->time_base, (AVRational){fps.den, fps.num});
104
    dts += av_rescale_q(base_ts, AV_TIME_BASE_Q, (AVRational){fps.den, fps.num});
105
  } else {
106
    fprintf(stderr, "No DTS???\n");
107
    dts = 0;
108
  }
109
  //dprintf(" DTS=%d\n",dts);
110
  frame_header_write(data, size, pts, dts);
111
}
112

  
113
struct input_stream *input_stream_open(const char *fname, int *period, const char *config)
114
{
115
  struct input_stream *desc;
116
  int i, res;
117

  
118
  avcodec_register_all();
119
  av_register_all();
120

  
121
  desc = malloc(sizeof(struct input_stream));
122
  if (desc == NULL) {
123
    return NULL;
124
  }
125
  res = av_open_input_file(&desc->s, fname, NULL, 0, NULL);
126
  if (res < 0) {
127
    fprintf(stderr, "Error opening %s: %d\n", fname, res);
128

  
129
    return NULL;
130
  }
131

  
132
  desc->s->flags |= AVFMT_FLAG_GENPTS;
133
  res = av_find_stream_info(desc->s);
134
  if (res < 0) {
135
    fprintf(stderr, "Cannot find codec parameters for %s\n", fname);
136

  
137
    return NULL;
138
  }
139
  desc->video_stream = -1;
140
  desc->audio_stream = -1;
141
  desc->last_ts = 0;
142
  desc->base_ts = 0;
143
  desc->frames_since_global_headers = 0;
144
  desc->loop = 0;	// FIXME: Check config!
145
  for (i = 0; i < desc->s->nb_streams; i++) {
146
    if (desc->video_stream == -1 && desc->s->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
147
      desc->video_stream = i;
148
      fprintf(stderr, "Video Frame Rate = %d/%d --- Period: %lld\n",
149
              desc->s->streams[i]->r_frame_rate.num,
150
              desc->s->streams[i]->r_frame_rate.den,
151
              av_rescale(1000000, desc->s->streams[i]->r_frame_rate.den, desc->s->streams[i]->r_frame_rate.num));
152
      *period = av_rescale(1000000, desc->s->streams[i]->r_frame_rate.den, desc->s->streams[i]->r_frame_rate.num);
153
    }
154
    if (desc->audio_stream == -1 && desc->s->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) {
155
      desc->audio_stream = i;
156
    }
157
  }
158

  
159
  dump_format(desc->s, 0, fname, 0);
160

  
161
  return desc;
162
}
163

  
164
void input_stream_close(struct input_stream *s)
165
{
166
    av_close_input_file(s->s);
167
    free(s);
168
}
169

  
170
int input_stream_rewind(struct input_stream *s)
171
{
172
    int ret;
173

  
174
    ret = av_seek_frame(s->s,-1,0,0);
175
    s->base_ts = s->last_ts;
176

  
177
    return ret;
178
}
179

  
180

  
181
uint8_t *chunkise(struct input_stream *s, int id, int *size, uint64_t *ts)
182
{
183
    AVPacket pkt;
184
    int res;
185
    uint8_t *data;
186
    int header_out, header_size;
187

  
188
    res = av_read_frame(s->s, &pkt);
189
    if (res < 0) {
190
      if (s->loop) {
191
        if (input_stream_rewind(s) >= 0) {
192
          *size = 0;
193
          *ts = s->last_ts;
194

  
195
          return NULL;
196
        }
197
      }
198
      fprintf(stderr, "AVPacket read failed: %d!!!\n", res);
199
      *size = -1;
200

  
201
      return NULL;
202
    }
203
    if (pkt.stream_index != s->video_stream) {
204
      *size = 0;
205
      *ts = s->last_ts;
206
      av_free_packet(&pkt);
207

  
208
      return NULL;
209
    }
210

  
211
    if (s->s->streams[pkt.stream_index]->codec->codec_type == CODEC_TYPE_VIDEO) {
212
      header_size = VIDEO_PAYLOAD_HEADER_SIZE;
213
    }
214
    if (header_refresh_period) {
215
      header_out = (pkt.flags & PKT_FLAG_KEY) != 0;
216
      if (header_out == 0) {
217
        s->frames_since_global_headers++;
218
        if (s->frames_since_global_headers == header_refresh_period) {
219
          s->frames_since_global_headers = 0;
220
          header_out = 1;
221
        }
222
      }
223
    } else {
224
      header_out = 0;
225
    }
226
    *size = pkt.size + s->s->streams[pkt.stream_index]->codec->extradata_size * header_out + header_size + FRAME_HEADER_SIZE;
227
    data = malloc(*size);
228
    if (data == NULL) {
229
      *size = -1;
230
      av_free_packet(&pkt);
231

  
232
      return NULL;
233
    }
234
    if (s->s->streams[pkt.stream_index]->codec->codec_type == CODEC_TYPE_VIDEO) {
235
      video_header_fill(data, s->s->streams[pkt.stream_index]);
236
    }
237
    data[VIDEO_PAYLOAD_HEADER_SIZE - 1] = 1;
238
    frame_header_fill(data + VIDEO_PAYLOAD_HEADER_SIZE, *size - header_size - FRAME_HEADER_SIZE, &pkt, s->s->streams[pkt.stream_index], s->base_ts);
239

  
240
    if (header_out && s->s->streams[pkt.stream_index]->codec->extradata_size) {
241
      memcpy(data + header_size + FRAME_HEADER_SIZE, s->s->streams[pkt.stream_index]->codec->extradata, s->s->streams[pkt.stream_index]->codec->extradata_size);
242
      memcpy(data + header_size + FRAME_HEADER_SIZE + s->s->streams[pkt.stream_index]->codec->extradata_size, pkt.data, pkt.size);
243
    } else {
244
      memcpy(data + header_size + FRAME_HEADER_SIZE, pkt.data, pkt.size);
245
    }
246
    *ts = av_rescale_q(pkt.dts, s->s->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
247
    //dprintf("pkt.dts=%ld TS1=%lu" , pkt.dts, *ts);
248
    *ts += s->base_ts;
249
    //dprintf(" TS2=%lu\n",*ts);
250
    s->last_ts = *ts;
251
    av_free_packet(&pkt);
252

  
253
    return data;
254
}
255

  
256
#if 0
257
int chunk_read_avs1(void *s_h, struct chunk *c)
258
{
259
    AVFormatContext *s = s_h;
260
    static AVPacket pkt;
261
    static int inited;
262
    AVStream *st;
263
    int res;
264
    int cnt;
265
    static uint8_t static_buff[STATIC_BUFF_SIZE];
266
    uint8_t *p, *pcurr;
267
    static uint8_t *p1;
268
    static struct chunk c2;
269
    int f1;
270
    static int f2;
271

  
272
    if (p1) {
273
        c2.id = c->id;
274
        *c = c2;
275
        p1 = NULL;
276

  
277
        return f2;
278
    }
279

  
280
    p = static_buff;
281
    p1 = static_buff + STATIC_BUFF_SIZE / 2;
282
    if (inited == 0) {
283
        inited = 1;
284
        res = av_read_frame(s, &pkt);
285
        if (res < 0) {
286
            fprintf(stderr, "First read failed: %d!!!\n", res);
287

  
288
            return 0;
289
        }
290
        if ((pkt.flags & PKT_FLAG_KEY) == 0) {
291
            fprintf(stderr, "First frame is not key frame!!!\n");
292

  
293
            return 0;
294
        }
295
    }
296
    cnt = 0; f1 = 0; f2 = 0;
297
    c->stride_size = 2;
298
    c2.stride_size = 2;
299
    pcurr = p1;
300
    if (pkt.size > 0) {
301
        memcpy(p, pkt.data, pkt.size);
302
        c->frame[0] = p;
303
        c->frame_len[0] = pkt.size;
304
        f1++;
305
        p += pkt.size;
306
    }
307
    while (1) {
308
        res = av_read_frame(s, &pkt);
309
        if (res >= 0) {
310
            st = s->streams[pkt.stream_index];
311
            if (pkt.flags & PKT_FLAG_KEY) {
312
                cnt++;
313
                if (cnt == 2) {
314
                    return f1;
315
                }
316
            }
317
            memcpy(pcurr, pkt.data, pkt.size);
318
            if (pcurr == p) {
319
                c->frame[f1] = pcurr;
320
                c->frame_len[f1] = pkt.size;
321
                p += pkt.size;
322
                pcurr = p1;
323
                f1++;
324
            } else {
325
                c2.frame[f2] = pcurr;
326
                c2.frame_len[f2] = pkt.size;
327
                p1 += pkt.size;
328
                pcurr = p;
329
                f2++;
330
            }
331
        } else {
332
            pkt.size = 0;
333

  
334
            return f1;
335
        }
336
    }
337

  
338
    return 0;
339
}
340
#endif
src/Chunkiser/output-stream-avf.c
1
/*
2
 *  Copyright (c) 2010 Luca Abeni
3
 *
4
 *  This is free software; see gpl-3.0.txt
5
 */
6

  
7
#include <libavformat/avformat.h>
8
#include <stdio.h>
9
#include <string.h>
10

  
11
#include "chunkiser.h"
12
//#include "dbg.h"
13
#include "payload.h"
14

  
15
struct output_stream {
16
  const char *output_format;
17
  const char *output_file;
18
  int64_t prev_pts, prev_dts;
19
  AVFormatContext *outctx;
20
};
21

  
22
static struct output_stream out;
23

  
24
static enum CodecID libav_codec_id(uint8_t mytype)
25
{
26
  switch (mytype) {
27
    case 1:
28
      return CODEC_ID_MPEG2VIDEO;
29
    case 2:
30
      return CODEC_ID_H261;
31
    case 3:
32
      return CODEC_ID_H263P;
33
    case 4:
34
      return CODEC_ID_MJPEG;
35
    case 5:
36
      return CODEC_ID_MPEG4;
37
    case 6:
38
      return CODEC_ID_FLV1;
39
    case 7:
40
      return CODEC_ID_SVQ3;
41
    case 8:
42
      return CODEC_ID_DVVIDEO;
43
    case 9:
44
      return CODEC_ID_H264;
45
    case 10:
46
      return CODEC_ID_THEORA;
47
    case 11:
48
      return CODEC_ID_SNOW;
49
    case 12:
50
      return CODEC_ID_VP6;
51
    case 13:
52
      return CODEC_ID_DIRAC;
53
    default:
54
      fprintf(stderr, "Unknown codec %d\n", mytype);
55
      return 0;
56
  }
57
}
58

  
59
static AVFormatContext *format_init(struct output_stream *o, const uint8_t *data)
60
{
61
  AVFormatContext *of;
62
  AVCodecContext *c;
63
  AVOutputFormat *outfmt;
64
  int width, height, frame_rate_n, frame_rate_d;
65
  uint8_t codec;
66

  
67
  av_register_all();
68

  
69
  payload_header_parse(data, &codec, &width, &height, &frame_rate_n, &frame_rate_d);
70
  //dprintf("Frame size: %dx%d -- Frame rate: %d / %d\n", width, height, frame_rate_n, frame_rate_d);
71
  outfmt = av_guess_format(o->output_format, o->output_file, NULL);
72
  of = avformat_alloc_context();
73
  if (of == NULL) {
74
    return NULL;
75
  }
76
  of->oformat = outfmt;
77
  av_new_stream(of, 0);
78
  c = of->streams[0]->codec;
79
  c->codec_id = libav_codec_id(codec);
80
  c->codec_type = CODEC_TYPE_VIDEO;
81
  c->width = width;
82
  c->height= height;
83
  c->time_base.den = frame_rate_n;
84
  c->time_base.num = frame_rate_d;
85
  of->streams[0]->avg_frame_rate.num = frame_rate_n;
86
  of->streams[0]->avg_frame_rate.den = frame_rate_d;
87
  c->pix_fmt = PIX_FMT_YUV420P;
88

  
89
  o->prev_pts = 0;
90
  o->prev_dts = 0;
91

  
92
  return of;
93
}
94

  
95
struct output_stream *out_stream_init(const char *config)
96
{
97
  out.output_format = "ffm";
98
  if (config) {
99
    out.output_file = strdup(config);
100
  } else {
101
    out.output_file = "/dev/stdout";
102
  }
103
  out.outctx = NULL;
104

  
105
  return &out;
106
}
107

  
108
void chunk_write(struct output_stream *o, int id, const uint8_t *data, int size)
109
{
110
  const int header_size = VIDEO_PAYLOAD_HEADER_SIZE; 
111
  int frames, i;
112
  const uint8_t *p;
113

  
114
  if (data[0] > 127) {
115
    fprintf(stderr, "Error! Non video chunk: %x!!!\n", data[0]);
116
    return;
117
  }
118
  if (o->outctx == NULL) {
119
    o->outctx = format_init(o, data);
120
    if (o->outctx == NULL) {
121
      fprintf(stderr, "Format init failed\n");
122

  
123
      return;
124
    }
125
    av_set_parameters(o->outctx, NULL);
126
    snprintf(o->outctx->filename, sizeof(o->outctx->filename), "%s", o->output_file);
127
    dump_format(o->outctx, 0, o->output_file, 1);
128
    url_fopen(&o->outctx->pb, o->output_file, URL_WRONLY);
129
    av_write_header(o->outctx);
130
  }
131

  
132
  frames = data[header_size - 1];
133
  p = data + header_size + FRAME_HEADER_SIZE * frames;
134
  for (i = 0; i < frames; i++) {
135
    AVPacket pkt;
136
    int64_t pts, dts;
137
    int frame_size;
138

  
139
    frame_header_parse(data + header_size + FRAME_HEADER_SIZE * i,
140
                       &frame_size, &pts, &dts);
141
    //dprintf("Frame %d PTS1: %d\n", i, pts);
142
    av_init_packet(&pkt);
143
    pkt.stream_index = 0;	// FIXME!
144
    if (pts != -1) {
145
      pts += (pts < o->prev_pts - ((1LL << 31) - 1)) ? ((o->prev_pts >> 32) + 1) << 32 : (o->prev_pts >> 32) << 32;
146
      //dprintf(" PTS2: %d\n", pts);
147
      o->prev_pts = pts;
148
      //dprintf("Frame %d has size %d --- PTS: %lld DTS: %lld\n", i, frame_size,
149
      //                                       av_rescale_q(pts, outctx->streams[0]->codec->time_base, AV_TIME_BASE_Q),
150
      //                                       av_rescale_q(dts, outctx->streams[0]->codec->time_base, AV_TIME_BASE_Q));
151
      pkt.pts = av_rescale_q(pts, o->outctx->streams[0]->codec->time_base, o->outctx->streams[0]->time_base);
152
    } else {
153
      pkt.pts = AV_NOPTS_VALUE;
154
    }
155
    dts += (dts < o->prev_dts - ((1LL << 31) - 1)) ? ((o->prev_dts >> 32) + 1) << 32 : (o->prev_dts >> 32) << 32;
156
    o->prev_dts = dts;
157
    pkt.dts = av_rescale_q(dts, o->outctx->streams[0]->codec->time_base, o->outctx->streams[0]->time_base);
158
    pkt.data = (uint8_t *)p;
159
    p += frame_size;
160
    pkt.size = frame_size;
161
    av_interleaved_write_frame(o->outctx, &pkt);
162
  }
163
}
src/Chunkiser/payload.h
1
/*
2
 *  Copyright (c) 2010 Luca Abeni
3
 *
4
 *  This is free software; see gpl-3.0.txt
5
 */
6
#define VIDEO_PAYLOAD_HEADER_SIZE 1 + 2 + 2 + 2 + 2 + 1 // 1 Frame type + 2 width + 2 height + 2 frame rate num + 2 frame rate den + 1 number of frames
7
#define FRAME_HEADER_SIZE (3 + 4 + 1)	// 3 Frame size + 4 PTS + 1 DeltaTS
8

  
9
static inline void frame_header_parse(const uint8_t *data, int *size, int64_t *pts, int64_t *dts)
10
{
11
  int i;
12

  
13
  *size = 0;
14
  for (i = 0; i < 3; i++) {
15
    *size = *size << 8;
16
    *size |= data[i];
17
  }
18
  *dts = 0;
19
  for (i = 0; i < 4; i++) {
20
    *dts = *dts << 8;
21
    *dts |= data[3 + i];
22
  }
23
  if (data[7] != 255) {
24
    *pts = *dts + data[7];
25
  } else {
26
    *pts = -1;
27
  }
28
}
29

  
30
static inline void payload_header_parse(const uint8_t *data, uint8_t *codec, int *width, int *height, int *frame_rate_n, int *frame_rate_d)
31
{
32
  *codec = data[0];
33
  *width = data[1] << 8 | data[2];
34
  *height = data[3] << 8 | data[4];
35
  *frame_rate_n = data[5] << 8 | data[6];
36
  *frame_rate_d = data[7] << 8 | data[8];
37
}
38

  
39
static inline void payload_header_write(uint8_t *data, uint8_t codec, int width, int height, int num, int den)
40
{
41
  data[0] = codec;
42
  data[1] = width >> 8;
43
  data[2] = width & 0xFF;
44
  data[3] = height >> 8;
45
  data[4] = height & 0xFF;
46
  data[5] = num >> 8;
47
  data[6] = num & 0xFF;
48
  data[7] = den >> 8;
49
  data[8] = den & 0xFF;
50
}
51

  
52
static inline void frame_header_write(uint8_t *data, int size, int32_t pts, int32_t dts)
53
{
54
  data[0] = size >> 16;
55
  data[1] = size >> 8;
56
  data[2] = size & 0xFF;
57
  data[3] = dts >> 24;
58
  data[4] = dts >> 16;
59
  data[5] = dts >> 8;
60
  data[6] = dts & 0xFF;
61
  if (pts != -1) {
62
    data[7] = (pts - dts) & 0xFF;
63
  } else {
64
    data[7] = 255;
65
  }
66
}
src/Makefile
3 3
endif
4 4
CFGDIR ?= .
5 5

  
6
SUBDIRS = ChunkIDSet ChunkTrading TopologyManager ChunkBuffer PeerSet Scheduler
6
SUBDIRS = ChunkIDSet ChunkTrading TopologyManager ChunkBuffer PeerSet Scheduler Chunkiser
7 7
COMMON_OBJS = config.o
8 8

  
9 9
.PHONY: subdirs $(SUBDIRS)
......
13 13
all: libgrapes.a
14 14

  
15 15
$(OBJ_LSTS):
16
	$(MAKE) -C $(dir $@) objs.lst
16
	$(MAKE) -C $(dir $@) objs.lst FFDIR=$(FFDIR)
17 17

  
18 18
libgrapes.a: $(OBJ_LSTS) $(COMMON_OBJS)
19 19
	$(AR) rcs libgrapes.a `cat $(OBJ_LSTS)` $(COMMON_OBJS)

Also available in: Unified diff