2017-08-10 11 views
0

私はScodecを使ってFlacメタデータをデコードしています。仕様の1つは、ヘッダーとブロックが一緒に何回も繰り返すことができるということです。ヘッダーには、現在のヘッダー/ブロックコンボが最後かどうかを示すフラグがあります。ベクトル[N]のコーデック。ここでNはベクトルの終わりを指定します。

私はHeaderとBlockをデコードできましたが、この仕様でVectorベースを作成するにはどうすればいいですか?ここで

//isLastBlock determines if this is the last Header/Block combo to decode. 
    case class Header(isLastBlock: Boolean) 
    //Some example data. 
    case class Block(someData: Int) 

    object Codec { 
    //Codec for Header 
    val headerCodec : Codec[Header] = bool.as[Header] 
    //Coded for Block 
    val blockCodec: Codec[Block] = int32.as[Block] 

    //We are guaranteed at least one Header/Block Combo, but how can we do this? 
    val headerBlock: Codec[(Header, Block, Vector[(Header, Block)])] = ??? 
    } 

scodecがこの機能を提供する場合わからない壊れたコードです。 2つのメソッドvectorOfNとsizedVectorは、デコードする前にアイテムの数を知る必要があるため動作しません。

答えて

0

flatMapと再帰を使用して解決策が見つかりました。

//create a single Codec 
    val headerBlockCode: Codec[(Header,Block)] = headerCodec ~ blockCodec 

    //Takes the last decode and continues to decode until Header.isLastBlock 
    def repeat(priorDecode: DecodeResult[(Header,Block)]) : Attempt[DecodeResult[List[(Header, Block)]]] = { 
    if (priorDecode.value._1.isLastBlock) Successful(priorDecode.map(List(_))) 
    else { 
     headerBlockCode.decode(priorDecode.remainder) match { 
     case f: Failure => f 
     case s: Successful[DecodeResult[(Header, Block)]] => { 
      repeat(s.value) match { 
      case f: Failure => f 
      case Successful(list) => { 
       Successful(list.map(decList => s.value.value :: decList)) 
      } 
      } 
     } 
     } 
    } 
    } 

    //Initial the decode 
    val bv = BitVector(data) 
    for { 
    first <- headerBlockCode.decode(bv) 
    list <- repeat(first) 
    } yield { 
    list.map(l => (list.value, l)) 
    } 
0

私は現在、まったく同じエクササイズを行っています。あなたがどのように進歩したか知りたいと思っています。

私はVectorTerminatedByIsLastIndicatorの問題を試していますが、そのアプローチは異なります。

私が作成したテストコードの一部です(Bar read MetadataBlockHeaderの場合)。 MetadataBlockHeaderのケースクラスには、isLastインジケータが含まれていないことに注意してください。これは、エンコード時に追加され、デコード中に削除されただけです。

case class Bar(value: Int) 

case class Foo(list1: List[Bar], list2: List[Bar]) 

object Foo { 

    def main(args: Array[String]) : Unit = { 

    implicit val barCodec : Codec[Bar] = { 
     ("value" | int32).hlist 
    }.as[Bar] 

    implicit val barListCodec : Codec[List[Bar]] = new Codec[List[Bar]] { 

     case class IsLast[A](isLast: Boolean, thing: A) 

     implicit val lastBarCodec : Codec[IsLast[Bar]] = { 
     ("isLast" | bool) :: ("bar" | Codec[Bar]) 
     }.as[IsLast[Bar]] 

     override def sizeBound: SizeBound = SizeBound.unknown 

     override def encode(bars: List[Bar]): Attempt[BitVector] = { 
     if (bars.size == 0) { 
      Failure(Err("Cannot encode zero length list")) 
     } else { 
      val zippedBars = bars.zipWithIndex 
      val lastBars = zippedBars.map(bi => IsLast(bi._2 + 1 == bars.size, bi._1)) 
      Codec.encodeSeq(lastBarCodec)(lastBars) 
     } 
     } 

     override def decode(b: BitVector): Attempt[DecodeResult[List[Bar]]] = { 
     val lastBars = decode(b, List.empty) 
     val bars = lastBars.map(dr => dr.value.thing) 
     Successful(DecodeResult(bars, lastBars.last.remainder)) 
     } 

     @tailrec 
     private def decode(b: BitVector, lastBars: List[DecodeResult[IsLast[Bar]]]) : List[DecodeResult[IsLast[Bar]]] = { 
     val lastBar = lastBarCodec.decode(b).require 
     val lastBarsInterim = lastBars :+ lastBar 
     if (lastBar.value.isLast) lastBarsInterim 
     else decode(lastBar.remainder, lastBarsInterim) 
     } 
    } 

    implicit val fooCodec : Codec[Foo] = { 
     (("list1" | Codec[List[Bar]]) 
     :: ("list2" | Codec[List[Bar]])) 
    }.as[Foo] 

    val bar1 = Bar(1) 
    val bar2 = Bar(2) 
    val bar3 = Bar(3) 
    val bar4 = Bar(4) 

    val aFoo = Foo(Seq(bar1, bar2).toList, Seq(bar3, bar4).toList) 
    println("aFoo:  " + aFoo) 

    val encodedFoo = fooCodec.encode(aFoo).require 
    println("encodedFoo: " + encodedFoo) 

    val decodedFoo = fooCodec.decode(encodedFoo).require.value 
    println("decodedFoo: " + decodedFoo) 

    assert(decodedFoo == aFoo) 
    } 

} 

この例のより詳細な部分は、hereです。

+0

メタデータとフレームCRCを解析できました。私がしようとしていることが実証できなかったので、そこに止まった。あなたが見たいと思うなら私のレポはここにあります。 https://github.com/OleTraveler/scodec-flac-decoder/blob/master/src/main/scala/com/ot/flac/decoder/ – OleTraveler

関連する問題