Parse caps string (as returned by `Gst.Pad.query_caps().to_string()`) into
    `pandas.DataFrame` table, with one row per configuration.

def caps_str_to_df(caps_str):
    '''
    Parse caps string (as returned by `Gst.Pad.query_caps().to_string()`) into
    `pandas.DataFrame` table, with one row per configuration.
    '''
    structures = [dict([process_dict(v.groupdict())
                   for v in re.finditer(
                       r'(?P<key>[^ ]*)=\((?P<type>.*?)\)((?P<value>[^{].*?)|{(?P<values>.*?)})(,|$)', s)])
                  for s in caps_str.split(';')]

    df = pd.DataFrame(structures)
    df.reset_index(drop=True, inplace=True)

    def compute_multi(df):
        multi_values = [[(c, k) for k, v in df[c].iteritems()
                         if isinstance(v, list)] for c in df]
        value_lists = [m for m in multi_values if m]
        if value_lists:
            return pd.DataFrame(np.concatenate(value_lists),
                             columns=['label', 'index'])
        else:
            return pd.DataFrame()

    df_multi = compute_multi(df)

    while df_multi.shape[0] > 0:
        df = resolve_multi(df, df_multi)
        df_multi = compute_multi(df)

    if 'framerate' in df:
        df['framerate_numerator'] = df['framerate'].map(lambda v: v.num)
        df['framerate_denominator'] = df['framerate'].map(lambda v: v.denom)
        df['framerate'] = df['framerate_numerator'] / df['framerate_denominator']
    if 'pixel-aspect-ratio' in df:
        df['pixel-aspect-ratio_numerator'] = df['pixel-aspect-ratio'].map(lambda v: v.num)
        df['pixel-aspect-ratio_denominator'] = df['pixel-aspect-ratio'].map(lambda v: v.denom)
        df['pixel-aspect-ratio'] = (df['pixel-aspect-ratio_numerator'] /
                                    df['pixel-aspect-ratio_numerator'])

    return df.sort(['framerate', 'width', 'height']).reset_index(drop=True)