]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/rmdec.c
cosmetics: reindent
[ffmpeg] / libavformat / rmdec.c
index 100d512adb02c19efe6471454448e0f52a75aea5..60778125bf1ada381445ad84ca7e07866a7bac41 100644 (file)
 #include "rm.h"
 #include "avstring.h"
 
-static void get_str(ByteIOContext *pb, char *buf, int buf_size)
+static inline void get_strl(ByteIOContext *pb, char *buf, int buf_size, int len)
 {
-    int len, i;
-    char *q;
+    int i;
+    char *q, r;
 
-    len = get_be16(pb);
     q = buf;
     for(i=0;i<len;i++) {
+        r = get_byte(pb);
         if (i < buf_size - 1)
-            *q++ = get_byte(pb);
+            *q++ = r;
     }
-    *q = '\0';
+    if (buf_size > 0) *q = '\0';
 }
 
-static void get_str8(ByteIOContext *pb, char *buf, int buf_size)
+static void get_str16(ByteIOContext *pb, char *buf, int buf_size)
 {
-    int len, i;
-    char *q;
+    get_strl(pb, buf, buf_size, get_be16(pb));
+}
 
-    len = get_byte(pb);
-    q = buf;
-    for(i=0;i<len;i++) {
-        if (i < buf_size - 1)
-            *q++ = get_byte(pb);
-    }
-    *q = '\0';
+static void get_str8(ByteIOContext *pb, char *buf, int buf_size)
+{
+    get_strl(pb, buf, buf_size, get_byte(pb));
 }
 
 static int rm_read_audio_stream_info(AVFormatContext *s, AVStream *st,
@@ -117,6 +113,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVStream *st,
         st->codec->codec_type = CODEC_TYPE_AUDIO;
         if (!strcmp(buf, "dnet")) {
             st->codec->codec_id = CODEC_ID_AC3;
+            st->need_parsing = AVSTREAM_PARSE_FULL;
         } else if (!strcmp(buf, "28_8")) {
             st->codec->codec_id = CODEC_ID_RA_288;
             st->codec->extradata_size= 0;
@@ -220,7 +217,7 @@ static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap)
         /* very old .ra format */
         return rm_read_header_old(s, ap);
     } else if (tag != MKTAG('.', 'R', 'M', 'F')) {
-        return AVERROR_IO;
+        return AVERROR(EIO);
     }
 
     get_be32(pb); /* header size */
@@ -261,10 +258,10 @@ static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap)
             flags = get_be16(pb); /* flags */
             break;
         case MKTAG('C', 'O', 'N', 'T'):
-            get_str(pb, s->title, sizeof(s->title));
-            get_str(pb, s->author, sizeof(s->author));
-            get_str(pb, s->copyright, sizeof(s->copyright));
-            get_str(pb, s->comment, sizeof(s->comment));
+            get_str16(pb, s->title, sizeof(s->title));
+            get_str16(pb, s->author, sizeof(s->author));
+            get_str16(pb, s->copyright, sizeof(s->copyright));
+            get_str16(pb, s->comment, sizeof(s->comment));
             break;
         case MKTAG('M', 'D', 'P', 'R'):
             st = av_new_stream(s, 0);
@@ -353,13 +350,14 @@ skip:
     if (!rm->nb_packets && (flags & 4))
         rm->nb_packets = 3600 * 25;
     get_be32(pb); /* next data header */
+    rm->curpic_num = -1;
     return 0;
 
  fail:
     for(i=0;i<s->nb_streams;i++) {
         av_free(s->streams[i]);
     }
-    return AVERROR_IO;
+    return AVERROR(EIO);
 }
 
 static int get_num(ByteIOContext *pb, int *len)
@@ -368,6 +366,7 @@ static int get_num(ByteIOContext *pb, int *len)
 
     n = get_be16(pb);
     (*len)-=2;
+    n &= 0x7FFF;
     if (n >= 0x4000) {
         return n - 0x4000;
     } else {
@@ -436,6 +435,89 @@ skip:
     return -1;
 }
 
+static int rm_assemble_video_frame(AVFormatContext *s, RMContext *rm, AVPacket *pkt, int len)
+{
+    ByteIOContext *pb = &s->pb;
+    int hdr, seq, pic_num, len2, pos;
+    int type;
+    int ssize;
+
+    hdr = get_byte(pb); len--;
+    type = hdr >> 6;
+    switch(type){
+    case 0: // slice
+    case 2: // last slice
+        seq = get_byte(pb); len--;
+        len2 = get_num(pb, &len);
+        pos = get_num(pb, &len);
+        pic_num = get_byte(pb); len--;
+        rm->remaining_len = len;
+        break;
+    case 1: //whole frame
+        seq = get_byte(pb); len--;
+        if(av_new_packet(pkt, len + 9) < 0)
+            return AVERROR(EIO);
+        pkt->data[0] = 0;
+        AV_WL32(pkt->data + 1, 1);
+        AV_WL32(pkt->data + 5, 0);
+        get_buffer(pb, pkt->data + 9, len);
+        rm->remaining_len = 0;
+        return 0;
+    case 3: //frame as a part of packet
+        len2 = get_num(pb, &len);
+        pos = get_num(pb, &len);
+        pic_num = get_byte(pb); len--;
+        rm->remaining_len = len - len2;
+        if(av_new_packet(pkt, len2 + 9) < 0)
+            return AVERROR(EIO);
+        pkt->data[0] = 0;
+        AV_WL32(pkt->data + 1, 1);
+        AV_WL32(pkt->data + 5, 0);
+        get_buffer(pb, pkt->data + 9, len2);
+        return 0;
+    }
+    //now we have to deal with single slice
+
+    if((seq & 0x7F) == 1 || rm->curpic_num != pic_num){
+        rm->slices = ((hdr & 0x3F) << 1) + 1;
+        ssize = len2 + 8*rm->slices + 1;
+        rm->videobuf = av_realloc(rm->videobuf, ssize);
+        rm->videobufsize = ssize;
+        rm->videobufpos = 8*rm->slices + 1;
+        rm->cur_slice = 0;
+        rm->curpic_num = pic_num;
+    }
+    if(type == 2){
+        len = FFMIN(len, pos);
+        pos = len2 - pos;
+    }
+
+    if(++rm->cur_slice > rm->cur_slice)
+        return 1;
+    AV_WL32(rm->videobuf - 7 + 8*rm->cur_slice, 1);
+    AV_WL32(rm->videobuf - 3 + 8*rm->cur_slice, rm->videobufpos - 8*rm->slices - 1);
+    if(rm->videobufpos + len > rm->videobufsize)
+        return 1;
+    if (get_buffer(pb, rm->videobuf + rm->videobufpos, len) != len)
+        return AVERROR(EIO);
+    rm->videobufpos += len,
+    rm->remaining_len-= len;
+
+    if(type == 2 || (rm->videobufpos) == rm->videobufsize){
+         //adjust slice headers
+         memmove(rm->videobuf + 1 + 8*rm->cur_slice, rm->videobuf + 1 + 8*rm->slices, rm->videobufsize - 1 - 8*rm->slices);
+         ssize = rm->videobufsize - 8*(rm->slices - rm->cur_slice);
+
+         rm->videobuf[0] = rm->cur_slice-1;
+         if(av_new_packet(pkt, ssize) < 0)
+             return AVERROR(ENOMEM);
+         memcpy(pkt->data, rm->videobuf, ssize);
+         return 0;
+    }
+
+    return 1;
+}
+
 static int rm_read_packet(AVFormatContext *s, AVPacket *pkt)
 {
     RMContext *rm = s->priv_data;
@@ -468,7 +550,7 @@ static int rm_read_packet(AVFormatContext *s, AVPacket *pkt)
             for (y = 0; y < rm->sub_packet_h; y++)
                 for (x = 0; x < rm->sub_packet_h/2; x++)
                     if (get_buffer(pb, rm->audiobuf+x*2*rm->audio_framesize+y*rm->coded_framesize, rm->coded_framesize) <= 0)
-                        return AVERROR_IO;
+                        return AVERROR(EIO);
             rm->audio_stream_num = 0;
             rm->audio_pkt_cnt = rm->sub_packet_h * rm->audio_framesize / st->codec->block_align - 1;
             // Release first audio packet
@@ -482,7 +564,7 @@ static int rm_read_packet(AVFormatContext *s, AVPacket *pkt)
             len= av_get_packet(pb, pkt, len);
             pkt->stream_index = 0;
             if (len <= 0) {
-                return AVERROR_IO;
+                return AVERROR(EIO);
             }
             pkt->size = len;
         }
@@ -491,34 +573,13 @@ static int rm_read_packet(AVFormatContext *s, AVPacket *pkt)
 resync:
         len=sync(s, &timestamp, &flags, &i, &pos);
         if(len<0)
-            return AVERROR_IO;
+            return AVERROR(EIO);
         st = s->streams[i];
 
         if (st->codec->codec_type == CODEC_TYPE_VIDEO) {
-            int h, pic_num, len2, pos;
-
-            h= get_byte(pb); len--;
-            if(!(h & 0x40)){
-                seq = get_byte(pb); len--;
-            }
-
-            if((h & 0xc0) == 0x40){
-                len2= pos= 0;
-            }else{
-                len2 = get_num(pb, &len);
-                pos = get_num(pb, &len);
-            }
-            /* picture number */
-            pic_num= get_byte(pb); len--;
-            rm->remaining_len= len;
             rm->current_stream= st->id;
-
-//            av_log(NULL, AV_LOG_DEBUG, "%X len:%d pos:%d len2:%d pic_num:%d\n",h, len, pos, len2, pic_num);
-            if(len2 && len2<len)
-                len=len2;
-            rm->remaining_len-= len;
-            av_get_packet(pb, pkt, len);
-
+            if(rm_assemble_video_frame(s, rm, pkt, len) == 1)
+                goto resync;//got partial frame
         } else if (st->codec->codec_type == CODEC_TYPE_AUDIO) {
             if ((st->codec->codec_id == CODEC_ID_RA_288) ||
                 (st->codec->codec_id == CODEC_ID_COOK) ||
@@ -621,6 +682,7 @@ static int rm_read_close(AVFormatContext *s)
     RMContext *rm = s->priv_data;
 
     av_free(rm->audiobuf);
+    av_free(rm->videobuf);
     return 0;
 }